diff --git a/.eslintrc.js b/.eslintrc.js
index 8464945125b678..99f7196ffc8158 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -287,6 +287,11 @@ module.exports = {
BigInt: 'readable',
BigInt64Array: 'readable',
BigUint64Array: 'readable',
+ Event: 'readable',
+ EventTarget: 'readable',
+ MessageChannel: 'readable',
+ MessageEvent: 'readable',
+ MessagePort: 'readable',
TextEncoder: 'readable',
TextDecoder: 'readable',
queueMicrotask: 'readable',
diff --git a/doc/api/events.md b/doc/api/events.md
index 7ace75fa65ddbe..527354d408ca6a 100644
--- a/doc/api/events.md
+++ b/doc/api/events.md
@@ -1067,9 +1067,15 @@ const ac = new AbortController();
process.nextTick(() => ac.abort());
```
+
## `EventTarget` and `Event` API
> Stability: 1 - Experimental
@@ -1080,7 +1086,7 @@ Neither the `EventTarget` nor `Event` classes are available for end
user code to create.
```js
-const target = getEventTargetSomehow();
+const target = new EventTarget();
target.addEventListener('foo', (event) => {
console.log('foo event happened!');
@@ -1166,7 +1172,7 @@ const handler4 = {
}
};
-const target = getEventTargetSomehow();
+const target = new EventTarget();
target.addEventListener('foo', handler1);
target.addEventListener('foo', handler2);
@@ -1187,6 +1193,10 @@ The `EventTarget` does not implement any special default handling for
### Class: `Event`
The `Event` object is an adaptation of the [`Event` Web API][]. Instances
@@ -1339,6 +1349,11 @@ The event type identifier.
### Class: `EventTarget`
#### `eventTarget.addEventListener(type, listener[, options])`
@@ -1372,7 +1387,7 @@ a `listener`. Any individual `listener` may be added once with
```js
function handler(event) {}
-const target = getEventTargetSomehow();
+const target = new EventTarget();
target.addEventListener('foo', handler, { capture: true }); // first
target.addEventListener('foo', handler, { capture: false }); // second
diff --git a/doc/api/globals.md b/doc/api/globals.md
index 8b279a21715e6b..4191c1e017afc7 100644
--- a/doc/api/globals.md
+++ b/doc/api/globals.md
@@ -169,6 +169,30 @@ added: v0.1.100
Used to print to stdout and stderr. See the [`console`][] section.
+## `Event`
+
+
+
+
+> Stability: 1 - Experimental
+
+A browser-compatible implementation of the `Event` class. See
+[`EventTarget` and `Event` API][] for more details.
+
+## `EventTarget`
+
+
+
+
+> Stability: 1 - Experimental
+
+A browser-compatible implementation of the `EventTarget` class. See
+[`EventTarget` and `Event` API][] for more details.
+
## `exports`
This variable may appear to be global but is not. See [`exports`][].
@@ -187,6 +211,33 @@ within the browser `var something` will define a new global variable. In
Node.js this is different. The top-level scope is not the global scope;
`var something` inside a Node.js module will be local to that module.
+## `MessageChannel`
+
+
+
+
+The `MessageChannel` class. See [`MessageChannel`][] for more details.
+
+## `MessageEvent`
+
+
+
+
+The `MessageEvent` class. See [`MessageEvent`][] for more details.
+
+## `MessagePort`
+
+
+
+
+The `MessagePort` class. See [`MessagePort`][] for more details.
+
## `module`
This variable may appear to be global but is not. See [`module`][].
@@ -322,6 +373,10 @@ The object that acts as the namespace for all W3C
[Mozilla Developer Network][webassembly-mdn] for usage and compatibility.
[`AbortController`]: https://developer.mozilla.org/en-US/docs/Web/API/AbortController
+[`EventTarget` and `Event` API]: events.md#event-target-and-event-api
+[`MessageChannel`]: worker_threads.md#worker_threads_class_messagechannel
+[`MessageEvent`]: https://developer.mozilla.org/en-US/docs/Web/API/MessageEvent/MessageEvent
+[`MessagePort`]: worker_threads.md#worker_threads_class_messageport
[`TextDecoder`]: util.md#util_class_util_textdecoder
[`TextEncoder`]: util.md#util_class_util_textencoder
[`URLSearchParams`]: url.md#url_class_urlsearchparams
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 551367583e55a8..bb4689d0d342e8 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -140,6 +140,21 @@ if (!config.noBrowserGlobals) {
exposeInterface(global, 'AbortController', AbortController);
exposeInterface(global, 'AbortSignal', AbortSignal);
+ const {
+ EventTarget,
+ Event,
+ } = require('internal/event_target');
+ exposeInterface(global, 'EventTarget', EventTarget);
+ exposeInterface(global, 'Event', Event);
+ const {
+ MessageChannel,
+ MessagePort,
+ MessageEvent,
+ } = require('internal/worker/io');
+ exposeInterface(global, 'MessageChannel', MessageChannel);
+ exposeInterface(global, 'MessagePort', MessagePort);
+ exposeInterface(global, 'MessageEvent', MessageEvent);
+
// https://html.spec.whatwg.org/multipage/webappapis.html#windoworworkerglobalscope
const timers = require('timers');
defineOperation(global, 'clearInterval', timers.clearInterval);
diff --git a/lib/internal/worker/io.js b/lib/internal/worker/io.js
index 5b5118a1d70b21..e3ca6fe0cc10b5 100644
--- a/lib/internal/worker/io.js
+++ b/lib/internal/worker/io.js
@@ -4,6 +4,7 @@ const {
ObjectAssign,
ObjectCreate,
ObjectDefineProperty,
+ ObjectDefineProperties,
ObjectGetOwnPropertyDescriptors,
ObjectGetPrototypeOf,
ObjectSetPrototypeOf,
@@ -21,7 +22,8 @@ const {
drainMessagePort,
moveMessagePortToContext,
receiveMessageOnPort: receiveMessageOnPort_,
- stopMessagePort
+ stopMessagePort,
+ checkMessagePort
} = internalBinding('messaging');
const {
getEnvMessagePort
@@ -38,12 +40,20 @@ const {
kRemoveListener,
} = require('internal/event_target');
const { inspect } = require('internal/util/inspect');
+const {
+ ERR_INVALID_ARG_TYPE
+} = require('internal/errors').codes;
+const kData = Symbol('kData');
const kIncrementsPortRef = Symbol('kIncrementsPortRef');
+const kLastEventId = Symbol('kLastEventId');
const kName = Symbol('kName');
+const kOrigin = Symbol('kOrigin');
const kPort = Symbol('kPort');
+const kPorts = Symbol('kPorts');
const kWaitingStreams = Symbol('kWaitingStreams');
const kWritableCallbacks = Symbol('kWritableCallbacks');
+const kSource = Symbol('kSource');
const kStartedReading = Symbol('kStartedReading');
const kStdioWantsMoreDataCallback = Symbol('kStdioWantsMoreDataCallback');
@@ -72,19 +82,57 @@ ObjectSetPrototypeOf(MessagePort.prototype, NodeEventTarget.prototype);
MessagePort.prototype.ref = MessagePortPrototype.ref;
MessagePort.prototype.unref = MessagePortPrototype.unref;
+function validateMessagePort(port, name) {
+ if (!checkMessagePort(port))
+ throw new ERR_INVALID_ARG_TYPE(name, 'MessagePort', port);
+}
+
class MessageEvent extends Event {
- constructor(data, target, type) {
+ constructor(type, {
+ data = null,
+ origin = '',
+ lastEventId = '',
+ source = null,
+ ports = [],
+ } = {}) {
super(type);
- this.data = data;
+ this[kData] = data;
+ this[kOrigin] = `${origin}`;
+ this[kLastEventId] = `${lastEventId}`;
+ this[kSource] = source;
+ this[kPorts] = [...ports];
+
+ if (this[kSource] !== null)
+ validateMessagePort(this[kSource], 'init.source');
+ for (let i = 0; i < this[kPorts].length; i++)
+ validateMessagePort(this[kPorts][i], `init.ports[${i}]`);
}
}
+ObjectDefineProperties(MessageEvent.prototype, {
+ data: {
+ get() { return this[kData]; }, enumerable: true, configurable: true
+ },
+ origin: {
+ get() { return this[kOrigin]; }, enumerable: true, configurable: true
+ },
+ lastEventId: {
+ get() { return this[kLastEventId]; }, enumerable: true, configurable: true
+ },
+ source: {
+ get() { return this[kSource]; }, enumerable: true, configurable: true
+ },
+ ports: {
+ get() { return this[kPorts]; }, enumerable: true, configurable: true
+ },
+});
+
ObjectDefineProperty(
MessagePort.prototype,
kCreateEvent,
{
value: function(data, type) {
- return new MessageEvent(data, this, type);
+ return new MessageEvent(type, { data });
},
configurable: false,
writable: false,
@@ -283,6 +331,7 @@ module.exports = {
moveMessagePortToContext,
MessagePort,
MessageChannel,
+ MessageEvent,
receiveMessageOnPort,
setupPortReferencing,
ReadableWorkerStdio,
diff --git a/src/node_external_reference.h b/src/node_external_reference.h
index f332103c3f5a27..0544979dd9a6f1 100644
--- a/src/node_external_reference.h
+++ b/src/node_external_reference.h
@@ -64,7 +64,8 @@ class ExternalReferenceRegistry {
V(string_decoder) \
V(trace_events) \
V(timers) \
- V(types)
+ V(types) \
+ V(worker)
#if NODE_HAVE_I18N_SUPPORT
#define EXTERNAL_REFERENCE_BINDING_LIST_I18N(V) V(icu)
diff --git a/src/node_messaging.cc b/src/node_messaging.cc
index a072176523e1e9..db3c24c3f853e6 100644
--- a/src/node_messaging.cc
+++ b/src/node_messaging.cc
@@ -1004,6 +1004,12 @@ void MessagePort::Stop(const FunctionCallbackInfo& args) {
port->Stop();
}
+void MessagePort::CheckType(const FunctionCallbackInfo& args) {
+ Environment* env = Environment::GetCurrent(args);
+ args.GetReturnValue().Set(
+ GetMessagePortConstructorTemplate(env)->HasInstance(args[0]));
+}
+
void MessagePort::Drain(const FunctionCallbackInfo& args) {
MessagePort* port;
ASSIGN_OR_RETURN_UNWRAP(&port, args[0].As