osra 0.6.6 → 0.6.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -7
- package/build/index.js +553 -551
- package/build/index.js.map +1 -1
- package/build/revivables/identity.d.ts +12 -10
- package/build/revivables/index.d.ts +13 -0
- package/build/utils/transport.d.ts +3 -4
- package/build/utils/type-guards.d.ts +2 -7
- package/build/utils/webext-types.d.ts +65 -0
- package/package.json +7 -5
|
@@ -9,24 +9,26 @@ export type Messages = {
|
|
|
9
9
|
};
|
|
10
10
|
export declare const Messages: Messages;
|
|
11
11
|
declare const IDENTITY_MARKER: unique symbol;
|
|
12
|
-
|
|
12
|
+
/** Phantom shape. A tracked value carries no marker of its own, the mark lives in a WeakMap, so
|
|
13
|
+
* this is what `isType` declares instead: matching it at the type level would widen `Capable` to
|
|
14
|
+
* every object, and nothing a user writes structurally matches this. */
|
|
15
|
+
type IdentityMarked = {
|
|
13
16
|
readonly [IDENTITY_MARKER]: true;
|
|
14
|
-
readonly value: T;
|
|
15
17
|
};
|
|
16
18
|
export type BoxedIdentity<T extends Capable = Capable> = BoxBaseType<typeof type> & {
|
|
17
19
|
id: string;
|
|
18
20
|
inner?: Capable;
|
|
19
21
|
[UnderlyingType]: T;
|
|
20
22
|
};
|
|
21
|
-
/**
|
|
22
|
-
*
|
|
23
|
-
*
|
|
23
|
+
/** Mark a value so osra preserves its reference identity across the boundary. The peer's revived
|
|
24
|
+
* value stands for this one, and handing it back - to you, or onward to a further context and back
|
|
25
|
+
* again - resolves to this very reference. The mark sticks to the value, so only the side that
|
|
26
|
+
* owns it has to opt in. Idempotent, and primitives pass through unchanged. */
|
|
24
27
|
export declare const identity: <T>(value: T) => T;
|
|
25
|
-
export declare const isType: (value: unknown) => value is
|
|
26
|
-
export declare const box: <T extends Capable, TContext extends RevivableContext>(
|
|
27
|
-
/** Identity-box a referenceable value with a caller-supplied inner box,
|
|
28
|
-
*
|
|
29
|
-
* description=undefined) where recursing back through their own box
|
|
28
|
+
export declare const isType: (value: unknown) => value is IdentityMarked;
|
|
29
|
+
export declare const box: <T extends Capable, TContext extends RevivableContext>(value: T, context: TContext) => BoxedIdentity<T>;
|
|
30
|
+
/** Identity-box a referenceable value with a caller-supplied inner box, bypassing the walker. Used
|
|
31
|
+
* by revivables (symbol with description=undefined) where recursing back through their own box
|
|
30
32
|
* would loop into this module again. */
|
|
31
33
|
export declare const boxByReference: <T extends WeakKey, TContext extends RevivableContext>(value: T, innerBox: Capable, context: TContext) => BoxedIdentity;
|
|
32
34
|
export declare const revive: <T extends BoxedIdentity, TContext extends RevivableContext>(value: T, context: TContext) => T[UnderlyingType];
|
|
@@ -70,5 +70,18 @@ export declare const defaultRevivableModules: readonly [typeof transfer, typeof
|
|
|
70
70
|
}];
|
|
71
71
|
export type DefaultRevivableModules = typeof defaultRevivableModules;
|
|
72
72
|
export type DefaultRevivableModule = DefaultRevivableModules[number];
|
|
73
|
+
/** Hold a side effect until the whole box walk this value belongs to has finished, and undo it if the
|
|
74
|
+
* walk throws. A module that records state the PEER will be told about ("it knows this id now") must
|
|
75
|
+
* not keep that record when a later sibling breaks the message it was recorded for: nothing ships,
|
|
76
|
+
* and every later send would then reference something the peer never received. Outside a walk the
|
|
77
|
+
* effect is already settled, so `commit` runs immediately. */
|
|
78
|
+
export declare const onBoxWalkSettled: (commit: () => void, rollback: () => void) => void;
|
|
73
79
|
export declare const recursiveBox: <T extends Capable, TModules extends readonly RevivableModule[]>(value: T, context: RevivableContext<TModules>) => DeepReplaceWithBox<T, TModules[number]>;
|
|
80
|
+
/** Box a value your own module claimed in place: every other module gets its turn and children are
|
|
81
|
+
* walked as usual, but `claimedBy` is skipped, and the cycle guard the caller's `recursiveBox`
|
|
82
|
+
* frame already holds for this value is not re-entered.
|
|
83
|
+
* A module needs this when its `isType` matches a bare value rather than a wrapper around one, the
|
|
84
|
+
* way `identity()` marks a reference in place: `recursiveBox` on that same value would come
|
|
85
|
+
* straight back to the module, and the guard would report it as a cycle. */
|
|
86
|
+
export declare const boxClaimedValue: <T extends Capable, TModules extends readonly RevivableModule[]>(value: T, context: RevivableContext<TModules>, claimedBy: string) => DeepReplaceWithBox<T, TModules[number]>;
|
|
74
87
|
export declare const recursiveRevive: <T extends Capable, TModules extends readonly RevivableModule[]>(value: T, context: RevivableContext<TModules>) => DeepReplaceWithRevive<T, TModules[number]>;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import type { Browser } from 'webextension-polyfill';
|
|
2
1
|
import type { Message } from '../types.js';
|
|
3
|
-
import type { WebExtOnConnect, WebExtOnMessage, WebExtPort, WebExtRuntime, WebExtSender } from './
|
|
2
|
+
import type { WebExtGlobal, WebExtOnConnect, WebExtOnMessage, WebExtPort, WebExtRuntime, WebExtSender } from './webext-types.js';
|
|
4
3
|
/** What the local side knows about the realm on the other end of a connection.
|
|
5
4
|
*
|
|
6
5
|
* `origin` and `source` are only OBSERVABLE on window transports. A MessagePort message carries
|
|
@@ -61,8 +60,8 @@ export type PlatformTransport = EmitPlatformTransport | ReceivePlatformTransport
|
|
|
61
60
|
export type EmitTransport = EmitPlatformTransport | CustomEmitTransport;
|
|
62
61
|
export type ReceiveTransport = ReceivePlatformTransport | CustomReceiveTransport;
|
|
63
62
|
export type Transport = PlatformTransport | CustomTransport;
|
|
64
|
-
export declare const getWebExtensionGlobal: () =>
|
|
65
|
-
export declare const getWebExtensionRuntime: () =>
|
|
63
|
+
export declare const getWebExtensionGlobal: () => WebExtGlobal | undefined;
|
|
64
|
+
export declare const getWebExtensionRuntime: () => WebExtRuntime | undefined;
|
|
66
65
|
export declare const checkOsraMessageKey: (message: any, key: string) => message is Message;
|
|
67
66
|
export declare const registerOsraMessageListener: ({ listener, transport, remoteName, key, origin, unregisterSignal }: {
|
|
68
67
|
listener: (message: Message, messageContext: MessageContext) => void;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Runtime } from 'webextension-polyfill';
|
|
2
1
|
import type { Message } from '../types.js';
|
|
3
2
|
import type { CustomEmitTransport, CustomReceiveTransport, CustomTransport, EmitJsonPlatformTransport, EmitTransport, JsonPlatformTransport, ReceiveJsonPlatformTransport, ReceiveTransport, Transport } from './transport.js';
|
|
3
|
+
import type { WebExtOnConnect, WebExtOnMessage, WebExtPort, WebExtRuntime } from './webext-types.js';
|
|
4
4
|
declare const typedArrayConstructorsByName: {
|
|
5
5
|
readonly Int8Array: Int8ArrayConstructor;
|
|
6
6
|
readonly Uint8Array: Uint8ArrayConstructor;
|
|
@@ -41,14 +41,10 @@ export declare const isSharedArrayBuffer: (value: unknown) => boolean;
|
|
|
41
41
|
* the unrelated clonable fallback module. Use isSharedArrayBuffer. */
|
|
42
42
|
export declare const isClonable: typeof isSharedArrayBuffer;
|
|
43
43
|
export declare const isTransferable: (value: unknown) => value is Transferable;
|
|
44
|
-
export type WebExtRuntime
|
|
44
|
+
export type { WebExtRuntime, WebExtPort, WebExtSender, WebExtOnConnect, WebExtOnMessage, WebExtEvent, WebExtGlobal } from './webext-types.js';
|
|
45
45
|
export declare const isWebExtensionRuntime: (value: unknown) => value is WebExtRuntime;
|
|
46
|
-
export type WebExtPort = ReturnType<WebExtRuntime['connect']> | Runtime.Port;
|
|
47
46
|
export declare const isWebExtensionPort: (value: unknown, connectPort?: boolean) => value is WebExtPort;
|
|
48
|
-
export type WebExtSender = NonNullable<WebExtPort['sender']>;
|
|
49
|
-
export type WebExtOnConnect = WebExtRuntime['onConnect'];
|
|
50
47
|
export declare const isWebExtensionOnConnect: (value: unknown) => value is WebExtOnConnect;
|
|
51
|
-
export type WebExtOnMessage = WebExtRuntime['onMessage'];
|
|
52
48
|
export declare const isWebExtensionOnMessage: (value: unknown) => value is WebExtOnMessage;
|
|
53
49
|
export declare const isWindow: (value: unknown) => value is Window;
|
|
54
50
|
export declare const isEmitJsonOnlyTransport: (value: unknown) => value is EmitJsonPlatformTransport;
|
|
@@ -63,4 +59,3 @@ export declare const isCustomEmitTransport: (value: unknown) => value is CustomE
|
|
|
63
59
|
export declare const isCustomReceiveTransport: (value: unknown) => value is CustomReceiveTransport;
|
|
64
60
|
export declare const isCustomTransport: (value: unknown) => value is CustomTransport;
|
|
65
61
|
export declare const isTransport: (value: unknown) => value is Transport;
|
|
66
|
-
export {};
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/** Structural stand-ins for the handful of WebExtension shapes osra touches.
|
|
2
|
+
*
|
|
3
|
+
* Vendored rather than imported from `webextension-polyfill`, because a bare `import type` inside a
|
|
4
|
+
* SHIPPED .d.ts makes osra's own declarations depend on a package the consumer may not have, and
|
|
5
|
+
* osra ships no dependencies. 0.6.6 and 0.6.7 did exactly that: `build/utils/transport.d.ts` and
|
|
6
|
+
* `build/utils/type-guards.d.ts` both imported `webextension-polyfill`, so a consumer without
|
|
7
|
+
* `@types/webextension-polyfill` got TS2307 under `skipLibCheck: false` and, far worse, a silent
|
|
8
|
+
* collapse with it on - `WebExtRuntime` became `any`, which made `Transport` `any`, which made
|
|
9
|
+
* `IsJsonOnlyTransport` true for every transport and degraded the whole `Capable` check.
|
|
10
|
+
* `npm run check-declaration-imports` is the guard that keeps it from coming back.
|
|
11
|
+
*
|
|
12
|
+
* Deliberately loose: only the members osra actually calls, typed permissively enough that both
|
|
13
|
+
* `webextension-polyfill`'s `Runtime.Static` and `@types/chrome`'s `typeof chrome.runtime` stay
|
|
14
|
+
* assignable, since either can be handed to `expose()` as a transport. No index signatures here,
|
|
15
|
+
* for the same reason: an interface has no implicit index signature, so adding one to these would
|
|
16
|
+
* make every real sender and port stop being assignable. `tests/extension` compiles against
|
|
17
|
+
* @types/chrome and the docs examples compile against webextension-polyfill, which is what keeps
|
|
18
|
+
* both ends honest. */
|
|
19
|
+
/** The three members osra uses on an extension event (`runtime.onMessage`, `port.onDisconnect`, ...). */
|
|
20
|
+
export type WebExtEvent<TListener extends (...args: any[]) => any = (...args: any[]) => any> = {
|
|
21
|
+
addListener(listener: TListener, ...rest: any[]): void;
|
|
22
|
+
removeListener(listener: TListener): void;
|
|
23
|
+
hasListener(listener: TListener): boolean;
|
|
24
|
+
};
|
|
25
|
+
/** Who a message came from, as the browser reported it. osra never builds one, it only hands the
|
|
26
|
+
* browser's own object through to your code, so the fields are all optional and the engine may
|
|
27
|
+
* carry more than these. */
|
|
28
|
+
export type WebExtSender = {
|
|
29
|
+
id?: string;
|
|
30
|
+
url?: string;
|
|
31
|
+
origin?: string;
|
|
32
|
+
frameId?: number;
|
|
33
|
+
documentId?: string;
|
|
34
|
+
tlsChannelId?: string;
|
|
35
|
+
tab?: {
|
|
36
|
+
id?: number;
|
|
37
|
+
url?: string;
|
|
38
|
+
title?: string;
|
|
39
|
+
windowId?: number;
|
|
40
|
+
index?: number;
|
|
41
|
+
active?: boolean;
|
|
42
|
+
};
|
|
43
|
+
};
|
|
44
|
+
export type WebExtPort = {
|
|
45
|
+
name: string;
|
|
46
|
+
sender?: WebExtSender;
|
|
47
|
+
disconnect(): void;
|
|
48
|
+
postMessage(message: any): void;
|
|
49
|
+
onMessage: WebExtEvent;
|
|
50
|
+
onDisconnect: WebExtEvent;
|
|
51
|
+
};
|
|
52
|
+
export type WebExtRuntime = {
|
|
53
|
+
id?: string;
|
|
54
|
+
connect(...args: any[]): WebExtPort;
|
|
55
|
+
sendMessage(...args: any[]): any;
|
|
56
|
+
onMessage: WebExtEvent;
|
|
57
|
+
onConnect: WebExtEvent;
|
|
58
|
+
onConnectExternal?: WebExtEvent;
|
|
59
|
+
};
|
|
60
|
+
export type WebExtOnConnect = WebExtRuntime['onConnect'];
|
|
61
|
+
export type WebExtOnMessage = WebExtRuntime['onMessage'];
|
|
62
|
+
/** The `browser` / `chrome` global, as much of it as osra looks at. */
|
|
63
|
+
export type WebExtGlobal = {
|
|
64
|
+
runtime?: WebExtRuntime;
|
|
65
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "osra",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.8",
|
|
4
4
|
"description": "Easy communication between workers",
|
|
5
5
|
"homepage": "https://github.com/Banou26/osra#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "vp build && node ./node_modules/typescript7/bin/tsc --declaration --emitDeclarationOnly",
|
|
38
38
|
"build-watch": "vp build --watch",
|
|
39
|
-
"clean": "
|
|
39
|
+
"clean": "node -e \"require('node:fs').rmSync('build', { recursive: true, force: true })\"",
|
|
40
40
|
"prepublishOnly": "npm run clean && npm run build",
|
|
41
41
|
"build-test": "vp build --config vite.test.config.ts",
|
|
42
42
|
"build-test-watch": "vp build --config vite.test.config.ts --watch",
|
|
@@ -46,20 +46,22 @@
|
|
|
46
46
|
"test": "npm run build && npm run build-test && npx playwright test",
|
|
47
47
|
"test-watch": "set PWTEST_WATCH=1 & npx playwright test",
|
|
48
48
|
"test-watch-headful": "nodemon --watch build-test --exec \"npx playwright test --headed\"",
|
|
49
|
-
"test-with-coverage": "npm run build-test && npx playwright test && npm run print-coverage && npm run clean-coverage",
|
|
49
|
+
"test-with-coverage": "VITE_COVERAGE=true npm run build-test && VITE_COVERAGE=true npx playwright test && npm run print-coverage && npm run clean-coverage",
|
|
50
50
|
"print-coverage": "npx nyc report",
|
|
51
|
-
"clean-coverage": "
|
|
51
|
+
"clean-coverage": "node -e \"for (const dir of ['.nyc_output', 'coverage']) require('node:fs').rmSync(dir, { recursive: true, force: true })\"",
|
|
52
52
|
"type-check": "node ./node_modules/typescript7/bin/tsc --noEmit && node ./node_modules/typescript7/bin/tsc --noEmit -p tsconfig.tests.json",
|
|
53
53
|
"start-server": "http-server -p 3000",
|
|
54
54
|
"build-extension-test": "node build-extension-test.mjs",
|
|
55
55
|
"test-extension": "npm run build-extension-test && npx playwright test -c playwright.extension.config.ts",
|
|
56
56
|
"check-consumer-types": "npm run build && node ./node_modules/typescript7/bin/tsc --noEmit -p tsconfig.consumer.json",
|
|
57
|
+
"check-declaration-imports": "node scripts/check-declaration-imports.mjs",
|
|
57
58
|
"docs-dev": "npm run dev -w docs",
|
|
58
59
|
"docs-build": "npm run build -w docs",
|
|
59
60
|
"docs-preview": "npm run preview -w docs",
|
|
60
61
|
"docs-gen-reference": "npm run gen:reference -w docs",
|
|
61
62
|
"docs-check-links": "npm run check-links -w docs",
|
|
62
|
-
"docs-check-twoslash": "npm run check-twoslash -w docs"
|
|
63
|
+
"docs-check-twoslash": "npm run check-twoslash -w docs",
|
|
64
|
+
"docs-check-html": "npm run check-html -w docs"
|
|
63
65
|
},
|
|
64
66
|
"devDependencies": {
|
|
65
67
|
"@istanbuljs/nyc-config-typescript": "^1.0.2",
|