Skip to content

Wrapping Event in a C++ class so that every where you pass an event it works. #1661

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
greggman opened this issue May 13, 2025 · 3 comments
Assignees

Comments

@greggman
Copy link

in JavaScript I can do this

class MyEvent extends Event {
  constructor(type, msg) {
    super(type);
    this.message = msg;
  }
}
const target = new EventTarget();
const e = await new Promise(resolve => {
  target.addEventListener('custom', resolve);
  target.dispatchEvent(new MyEvent('custom', 'hello'));
});
assert.ok(e.message === 'hello');

Is it possible to have MyEvent be a C++ class?

In my current attempt, when I call target.dispatchEvent I get

node:internal/event_target:220
      throw new ERR_INVALID_THIS('Event');
            ^

TypeError [ERR_INVALID_THIS]: Value of "this" must be of type Event
    at get type [as type] (node:internal/event_target:220:13)
    at EventTarget.dispatchEvent (node:internal/event_target:755:40)

I tried setting the prototype chain in C++ and this passes

assert.ok(new MyEvent('custom', 'hello') instanceof Event);

but of course it's not actually an Event, it's a non-event who's prototype chain contains Event which is what node is complaining about.

@greggman
Copy link
Author

wrt, I'm trying to verify if this is possible or not. My impression is it's not possible and that I have to do something like create class MyEvent extends Event in JavaScript and then use it from my addon.

@greggman
Copy link
Author

Just to make it clear what my goal is here. I'm trying to get dawn.node to be spec compliant.

Dawn is Chromium's implementation of the WebGPU Spec and dawn.node is trying to bring the same API to node.js

That spec has a few requirements of extending existing classes

For example GPUDevice is supposed to extend EventTarget

[Exposed=(Window, Worker), SecureContext
interface GPUDevice : EventTarget {
...
}

This means, for example, if you patch dispatchEvent on EventTarget and call dispatchEvent on a GPUDevice it must go through the patched function

EventTarget.prototype.dispatchEvent = (function(origFn) {
  return function(event) {
    console.log('type:', event.type);
    return origFn.call(this, event);
  };
})(EventTarget.prototype.dispatchEvent);

someGPUDevice.dispatchEvent(new Event('foobar'));  // should see type: foobar in console

Similarly, as mentioned above, a custom event WebGPU event, implemented by dawn.node, needs to act like an Event. In particular GPUUncapturedErrorEvent extends Event

Exposed=(Window, Worker), SecureContext]]
interface GPUUncapturedErrorEvent : Event {
   constructor(
       DOMString type,
       GPUUncapturedErrorEventInit gpuUncapturedErrorEventInitDict
   );
   [SameObject] readonly attribute GPUError error;
};

dictionary GPUUncapturedErrorEventInit : EventInit {
   required GPUError error;
};

This means for example, it's valid to dispatchEvent an GPUncaptureErrorEvent through an EventTarget

const target = new EventTarget();
target.dispatchEvent(new GPUUncapturedErrorEvent('uncapturederror', {
  error: new GPUValidationError('msg'),
});

Which is the issue above.

Several other requirements

GPUDevice.prototype instanceof EventTarget  // should be true
someGPUDevice instanceof EventTarget        // should be true
someGPUDevice instanceof GPUDevice          // should be true

I feel like I'm reading around the net and in issues in this repo that NAPI doesn't support what I'm trying to do and basically I'm trying to verify that.

@KevinEady KevinEady self-assigned this May 16, 2025
@KevinEady
Copy link
Contributor

Node-API does not currently provide a mechanism to create a C++ class that extends a JavaScript class. There's some technical limitations (as a class in V8 is a FunctionTemplate, which does not have a corresponding Node-API counterpart).

Have you tried prototype manipulation, eg. with Object.setPrototypeOf()? I am not sure if this would work, but if you have time to try it out... 👍 But it may not succeed in your requirement of someGPUDevice instanceof GPUDevice === true 🤷

Perhaps look at #229 for some other discussions regarding same.

Let us know how it turns out!

copybara-service bot pushed a commit to google/dawn that referenced this issue May 21, 2025
The Node NAPI provides no way to do this
nodejs/node-addon-api#1661

To be spec compliant GPUUncapturedErrorEvent is
required to inherit from Event so it can be used
everywhere an Event can be used. The workaround
is to manually implement GPUUncapturedErrorEvent as
a JavaScript class.

Note: This class is not used in dawn.node yet but
this CL makes the CTS test
webgpu:idl,javascript:inheritance:type="GPUUncapturedErrorEvent"
pass.

A future CL will use this class.

Bug: 419128706
Depends-On: Ib56a6403bef7f677e9f5f740193770012de30ad4
Change-Id: Ia388562d8d7f02458e36b29db1a5acb8fcac03e2
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/243294
Reviewed-by: Corentin Wallez <[email protected]>
Commit-Queue: Gregg Tavares <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Need Triage
Development

No branches or pull requests

2 participants