From bbfca7db27e712c2c858523b6a2ba2c809cc2b57 Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 04:28:47 +0000 Subject: [PATCH 1/6] feat: Support Duplex stream options as constructor options --- src/BasePostMessageStream.ts | 4 +++- src/WebWorker/WebWorkerParentPostMessageStream.ts | 7 ++++--- src/WebWorker/WebWorkerPostMessageStream.ts | 5 +++-- src/node-process/ProcessMessageStream.ts | 5 +++-- src/node-process/ProcessParentMessageStream.ts | 7 ++++--- src/node-thread/ThreadMessageStream.ts | 5 +++-- src/node-thread/ThreadParentMessageStream.ts | 7 ++++--- src/runtime/BrowserRuntimePostMessageStream.ts | 11 ++++++++--- src/window/WindowPostMessageStream.ts | 6 ++++-- 9 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/BasePostMessageStream.ts b/src/BasePostMessageStream.ts index 604cbfc..898aba6 100644 --- a/src/BasePostMessageStream.ts +++ b/src/BasePostMessageStream.ts @@ -1,4 +1,5 @@ import { Duplex } from 'readable-stream'; +import type { DuplexOptions } from 'readable-stream'; import { StreamData } from './utils'; const noop = () => undefined; @@ -24,9 +25,10 @@ export abstract class BasePostMessageStream extends Duplex { private _log: Log; - constructor() { + constructor(streamOptions: DuplexOptions = {}) { super({ objectMode: true, + ...streamOptions, }); // Initialization flags diff --git a/src/WebWorker/WebWorkerParentPostMessageStream.ts b/src/WebWorker/WebWorkerParentPostMessageStream.ts index 1b68d04..3d879d8 100644 --- a/src/WebWorker/WebWorkerParentPostMessageStream.ts +++ b/src/WebWorker/WebWorkerParentPostMessageStream.ts @@ -1,10 +1,11 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { DEDICATED_WORKER_NAME, isValidStreamMessage } from '../utils'; -interface WorkerParentStreamArgs { +interface WorkerParentStreamArgs extends DuplexOptions { worker: Worker; } @@ -24,8 +25,8 @@ export class WebWorkerParentPostMessageStream extends BasePostMessageStream { * @param args.worker - The Web Worker to exchange messages with. The worker * must instantiate a `WebWorkerPostMessageStream`. */ - constructor({ worker }: WorkerParentStreamArgs) { - super(); + constructor({ worker, ...streamOptions }: WorkerParentStreamArgs) { + super(streamOptions); this._target = DEDICATED_WORKER_NAME; this._worker = worker; diff --git a/src/WebWorker/WebWorkerPostMessageStream.ts b/src/WebWorker/WebWorkerPostMessageStream.ts index e403405..9e355c9 100644 --- a/src/WebWorker/WebWorkerPostMessageStream.ts +++ b/src/WebWorker/WebWorkerPostMessageStream.ts @@ -1,5 +1,6 @@ // We ignore coverage for the entire file due to limits on our instrumentation, // but it is in fact covered by our tests. +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, @@ -17,7 +18,7 @@ import { export class WebWorkerPostMessageStream extends BasePostMessageStream { private _name: string; - constructor() { + constructor(streamOptions: DuplexOptions = {}) { // Kudos: https://stackoverflow.com/a/18002694 if ( typeof self === 'undefined' || @@ -29,7 +30,7 @@ export class WebWorkerPostMessageStream extends BasePostMessageStream { ); } - super(); + super(streamOptions); this._name = DEDICATED_WORKER_NAME; self.addEventListener('message', this._onMessage.bind(this) as any); diff --git a/src/node-process/ProcessMessageStream.ts b/src/node-process/ProcessMessageStream.ts index 6202e51..f62035c 100644 --- a/src/node-process/ProcessMessageStream.ts +++ b/src/node-process/ProcessMessageStream.ts @@ -1,3 +1,4 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; @@ -5,8 +6,8 @@ import { isValidStreamMessage, StreamData } from '../utils'; * Child process-side Node.js `child_process` stream. */ export class ProcessMessageStream extends BasePostMessageStream { - constructor() { - super(); + constructor(streamOptions: DuplexOptions = {}) { + super(streamOptions); if (typeof globalThis.process.send !== 'function') { throw new Error( diff --git a/src/node-process/ProcessParentMessageStream.ts b/src/node-process/ProcessParentMessageStream.ts index 22eaed6..320b472 100644 --- a/src/node-process/ProcessParentMessageStream.ts +++ b/src/node-process/ProcessParentMessageStream.ts @@ -1,8 +1,9 @@ import type { ChildProcess } from 'child_process'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; -interface ProcessParentMessageStreamArgs { +interface ProcessParentMessageStreamArgs extends DuplexOptions { process: ChildProcess; } @@ -18,8 +19,8 @@ export class ProcessParentMessageStream extends BasePostMessageStream { * @param args - Options bag. * @param args.process - The process to communicate with. */ - constructor({ process }: ProcessParentMessageStreamArgs) { - super(); + constructor({ process, ...streamOptions }: ProcessParentMessageStreamArgs) { + super(streamOptions); this._process = process; this._onMessage = this._onMessage.bind(this); diff --git a/src/node-thread/ThreadMessageStream.ts b/src/node-thread/ThreadMessageStream.ts index 6fa3691..673ca4d 100644 --- a/src/node-thread/ThreadMessageStream.ts +++ b/src/node-thread/ThreadMessageStream.ts @@ -1,4 +1,5 @@ import { parentPort } from 'worker_threads'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; @@ -8,8 +9,8 @@ import { isValidStreamMessage, StreamData } from '../utils'; export class ThreadMessageStream extends BasePostMessageStream { #parentPort: Exclude; - constructor() { - super(); + constructor(streamOptions: DuplexOptions = {}) { + super(streamOptions); if (!parentPort) { throw new Error( diff --git a/src/node-thread/ThreadParentMessageStream.ts b/src/node-thread/ThreadParentMessageStream.ts index 6ab1138..38dcb95 100644 --- a/src/node-thread/ThreadParentMessageStream.ts +++ b/src/node-thread/ThreadParentMessageStream.ts @@ -1,8 +1,9 @@ import { Worker } from 'worker_threads'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream } from '../BasePostMessageStream'; import { isValidStreamMessage, StreamData } from '../utils'; -interface ThreadParentMessageStreamArgs { +interface ThreadParentMessageStreamArgs extends DuplexOptions { thread: Worker; } @@ -18,8 +19,8 @@ export class ThreadParentMessageStream extends BasePostMessageStream { * @param args - Options bag. * @param args.thread - The thread to communicate with. */ - constructor({ thread }: ThreadParentMessageStreamArgs) { - super(); + constructor({ thread, ...streamOptions }: ThreadParentMessageStreamArgs) { + super(streamOptions); this._thread = thread; this._onMessage = this._onMessage.bind(this); diff --git a/src/runtime/BrowserRuntimePostMessageStream.ts b/src/runtime/BrowserRuntimePostMessageStream.ts index 335d3ab..ed1766a 100644 --- a/src/runtime/BrowserRuntimePostMessageStream.ts +++ b/src/runtime/BrowserRuntimePostMessageStream.ts @@ -1,10 +1,11 @@ +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { isValidStreamMessage } from '../utils'; -export interface BrowserRuntimePostMessageStreamArgs { +export interface BrowserRuntimePostMessageStreamArgs extends DuplexOptions { name: string; target: string; } @@ -26,8 +27,12 @@ export class BrowserRuntimePostMessageStream extends BasePostMessageStream { * multiple streams sharing the same runtime. * @param args.target - The name of the stream to exchange messages with. */ - constructor({ name, target }: BrowserRuntimePostMessageStreamArgs) { - super(); + constructor({ + name, + target, + ...streamOptions + }: BrowserRuntimePostMessageStreamArgs) { + super(streamOptions); this.#name = name; this.#target = target; diff --git a/src/window/WindowPostMessageStream.ts b/src/window/WindowPostMessageStream.ts index 76df938..81a64f3 100644 --- a/src/window/WindowPostMessageStream.ts +++ b/src/window/WindowPostMessageStream.ts @@ -1,11 +1,12 @@ import { assert } from '@metamask/utils'; +import type { DuplexOptions } from 'readable-stream'; import { BasePostMessageStream, PostMessageEvent, } from '../BasePostMessageStream'; import { isValidStreamMessage } from '../utils'; -interface WindowPostMessageStreamArgs { +interface WindowPostMessageStreamArgs extends DuplexOptions { name: string; target: string; targetOrigin?: string; @@ -56,8 +57,9 @@ export class WindowPostMessageStream extends BasePostMessageStream { target, targetOrigin = location.origin, targetWindow = window, + ...streamOptions }: WindowPostMessageStreamArgs) { - super(); + super(streamOptions); if ( typeof window === 'undefined' || From 0866c9c00d08df4c8997d8f906c0a7656336901d Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 04:37:10 +0000 Subject: [PATCH 2/6] chore: add test-case for overriding stream options --- src/window/WindowPostMessageStream.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/window/WindowPostMessageStream.test.ts b/src/window/WindowPostMessageStream.test.ts index 536ddea..5ca46b5 100644 --- a/src/window/WindowPostMessageStream.test.ts +++ b/src/window/WindowPostMessageStream.test.ts @@ -1,6 +1,16 @@ import { WindowPostMessageStream } from './WindowPostMessageStream'; describe('WindowPostMessageStream', () => { + it('can override base stream options', () => { + const pms = new WindowPostMessageStream({ + name: 'foo', + target: 'bar', + encoding: 'ucs2', + objectMode: false, + }); + expect((pms as any).encoding).toBe('ucs2'); + }); + it('throws if window.postMessage is not a function', () => { const originalPostMessage = window.postMessage; (window as any).postMessage = undefined; From 9aee774d451047d57dfe5ddc32e268294378da58 Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 04:54:16 +0000 Subject: [PATCH 3/6] chore: remove unused default option from BasePostMessageStream --- src/BasePostMessageStream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BasePostMessageStream.ts b/src/BasePostMessageStream.ts index 898aba6..4e77d9d 100644 --- a/src/BasePostMessageStream.ts +++ b/src/BasePostMessageStream.ts @@ -25,7 +25,7 @@ export abstract class BasePostMessageStream extends Duplex { private _log: Log; - constructor(streamOptions: DuplexOptions = {}) { + constructor(streamOptions: DuplexOptions) { super({ objectMode: true, ...streamOptions, From e40630afdea31c4072a7e8ab6a6b23453181b11d Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 04:55:29 +0000 Subject: [PATCH 4/6] fix: make options optional in BasePostMessageStream --- src/BasePostMessageStream.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BasePostMessageStream.ts b/src/BasePostMessageStream.ts index 4e77d9d..b94618e 100644 --- a/src/BasePostMessageStream.ts +++ b/src/BasePostMessageStream.ts @@ -25,7 +25,7 @@ export abstract class BasePostMessageStream extends Duplex { private _log: Log; - constructor(streamOptions: DuplexOptions) { + constructor(streamOptions?: DuplexOptions) { super({ objectMode: true, ...streamOptions, From 908f0676bf20292bdb4804c1f20050c5ef32c435 Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 05:01:36 +0000 Subject: [PATCH 5/6] fix test --- src/window/WindowPostMessageStream.test.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/window/WindowPostMessageStream.test.ts b/src/window/WindowPostMessageStream.test.ts index 5ca46b5..c6c1420 100644 --- a/src/window/WindowPostMessageStream.test.ts +++ b/src/window/WindowPostMessageStream.test.ts @@ -8,7 +8,16 @@ describe('WindowPostMessageStream', () => { encoding: 'ucs2', objectMode: false, }); - expect((pms as any).encoding).toBe('ucs2'); + expect(pms._readableState.encoding).toBe('ucs2'); + expect(pms._readableState.objectMode).toBe(false); + expect(pms._writableState.objectMode).toBe(false); + }); + + it('can be instantiated without options', () => { + const pms = new WindowPostMessageStream(undefined as any); + expect(pms._readableState.encoding).toBe('utf8'); + expect(pms._readableState.objectMode).toBe(true); + expect(pms._writableState.objectMode).toBe(true); }); it('throws if window.postMessage is not a function', () => { From 3f68eb8d4124bc531dc6ed58d55ff58f9c41f1bb Mon Sep 17 00:00:00 2001 From: legobt <6wbvkn0j@anonaddy.me> Date: Wed, 15 May 2024 05:07:36 +0000 Subject: [PATCH 6/6] fix test --- src/window/WindowPostMessageStream.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/window/WindowPostMessageStream.test.ts b/src/window/WindowPostMessageStream.test.ts index c6c1420..9233b71 100644 --- a/src/window/WindowPostMessageStream.test.ts +++ b/src/window/WindowPostMessageStream.test.ts @@ -13,9 +13,8 @@ describe('WindowPostMessageStream', () => { expect(pms._writableState.objectMode).toBe(false); }); - it('can be instantiated without options', () => { - const pms = new WindowPostMessageStream(undefined as any); - expect(pms._readableState.encoding).toBe('utf8'); + it('can be instantiated with default options', () => { + const pms = new WindowPostMessageStream({ name: 'foo', target: 'bar' }); expect(pms._readableState.objectMode).toBe(true); expect(pms._writableState.objectMode).toBe(true); });