@adobe/uix-core 0.6.5 → 0.7.0

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.
Files changed (91) hide show
  1. package/dist/__helpers__/jest.messagechannel.d.cts +2 -0
  2. package/dist/__helpers__/jest.messagechannel.d.cts.map +1 -0
  3. package/dist/__mocks__/mock-finalization-registry.d.ts +11 -0
  4. package/dist/__mocks__/mock-finalization-registry.d.ts.map +1 -0
  5. package/dist/__mocks__/mock-weak-ref.d.ts +7 -0
  6. package/dist/__mocks__/mock-weak-ref.d.ts.map +1 -0
  7. package/dist/constants.d.ts +7 -0
  8. package/dist/constants.d.ts.map +1 -0
  9. package/dist/cross-realm-object.d.ts +44 -0
  10. package/dist/cross-realm-object.d.ts.map +1 -0
  11. package/dist/debuglog.d.ts +11 -0
  12. package/dist/debuglog.d.ts.map +1 -1
  13. package/dist/index.d.ts +4 -1
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +817 -7
  16. package/dist/index.js.map +1 -1
  17. package/dist/message-wrapper.d.ts +9 -0
  18. package/dist/message-wrapper.d.ts.map +1 -0
  19. package/dist/object-simulator.d.ts +28 -0
  20. package/dist/object-simulator.d.ts.map +1 -0
  21. package/dist/object-simulator.test.d.ts +2 -0
  22. package/dist/object-simulator.test.d.ts.map +1 -0
  23. package/dist/object-walker.d.ts +29 -0
  24. package/dist/object-walker.d.ts.map +1 -0
  25. package/dist/promises/index.d.ts +3 -0
  26. package/dist/promises/index.d.ts.map +1 -0
  27. package/dist/promises/promise-wrappers.test.d.ts +2 -0
  28. package/dist/promises/promise-wrappers.test.d.ts.map +1 -0
  29. package/dist/promises/timed.d.ts +15 -0
  30. package/dist/promises/timed.d.ts.map +1 -0
  31. package/dist/promises/wait.d.ts +7 -0
  32. package/dist/promises/wait.d.ts.map +1 -0
  33. package/dist/remote-subject.d.ts +70 -0
  34. package/dist/remote-subject.d.ts.map +1 -0
  35. package/dist/rpc/call-receiver.d.ts +4 -0
  36. package/dist/rpc/call-receiver.d.ts.map +1 -0
  37. package/dist/rpc/call-receiver.test.d.ts +2 -0
  38. package/dist/rpc/call-receiver.test.d.ts.map +1 -0
  39. package/dist/rpc/call-sender.d.ts +4 -0
  40. package/dist/rpc/call-sender.d.ts.map +1 -0
  41. package/dist/rpc/call-sender.test.d.ts +2 -0
  42. package/dist/rpc/call-sender.test.d.ts.map +1 -0
  43. package/dist/rpc/index.d.ts +3 -0
  44. package/dist/rpc/index.d.ts.map +1 -0
  45. package/dist/tickets.d.ts +34 -0
  46. package/dist/tickets.d.ts.map +1 -0
  47. package/dist/tunnel/index.d.ts +2 -0
  48. package/dist/tunnel/index.d.ts.map +1 -0
  49. package/dist/tunnel/tunnel-message.d.ts +19 -0
  50. package/dist/tunnel/tunnel-message.d.ts.map +1 -0
  51. package/dist/tunnel/tunnel.d.ts +58 -0
  52. package/dist/tunnel/tunnel.d.ts.map +1 -0
  53. package/dist/tunnel/tunnel.test.d.ts +2 -0
  54. package/dist/tunnel/tunnel.test.d.ts.map +1 -0
  55. package/dist/types.d.ts +1 -4
  56. package/dist/types.d.ts.map +1 -1
  57. package/dist/value-assertions.d.ts +10 -0
  58. package/dist/value-assertions.d.ts.map +1 -0
  59. package/package.json +1 -1
  60. package/src/__helpers__/jest.messagechannel.cjs +3 -0
  61. package/src/__mocks__/mock-finalization-registry.ts +13 -0
  62. package/src/__mocks__/mock-weak-ref.ts +10 -0
  63. package/src/constants.ts +6 -0
  64. package/src/cross-realm-object.ts +117 -0
  65. package/src/debuglog.ts +1 -1
  66. package/src/index.ts +4 -1
  67. package/src/message-wrapper.ts +35 -0
  68. package/src/object-simulator.test.ts +135 -0
  69. package/src/object-simulator.ts +136 -0
  70. package/src/object-walker.ts +92 -0
  71. package/src/promises/index.ts +2 -0
  72. package/src/promises/promise-wrappers.test.ts +63 -0
  73. package/src/promises/timed.ts +41 -0
  74. package/src/promises/wait.ts +10 -0
  75. package/src/remote-subject.ts +185 -0
  76. package/src/rpc/call-receiver.test.ts +90 -0
  77. package/src/rpc/call-receiver.ts +29 -0
  78. package/src/rpc/call-sender.test.ts +73 -0
  79. package/src/rpc/call-sender.ts +72 -0
  80. package/src/rpc/index.ts +2 -0
  81. package/src/tickets.ts +71 -0
  82. package/src/tunnel/index.ts +1 -0
  83. package/src/tunnel/tunnel-message.ts +75 -0
  84. package/src/tunnel/tunnel.test.ts +196 -0
  85. package/src/tunnel/tunnel.ts +311 -0
  86. package/src/types.ts +3 -5
  87. package/src/value-assertions.ts +48 -0
  88. package/tsconfig.json +2 -6
  89. package/dist/timeout-promise.d.ts +0 -12
  90. package/dist/timeout-promise.d.ts.map +0 -1
  91. package/src/timeout-promise.ts +0 -36
@@ -0,0 +1,58 @@
1
+ import EventEmitter from "eventemitter3";
2
+ /** @alpha */
3
+ export interface TunnelConfig {
4
+ /**
5
+ * To ensure secure communication, target origin must be specified, so the
6
+ * tunnel can't connect to an unauthorized domain. Can be '*' to disable
7
+ * origin checks, but this is discouraged!
8
+ */
9
+ targetOrigin: string;
10
+ /**
11
+ * A Promise for a tunnel will reject if not connected within timeout (ms).
12
+ * @defaultValue 4000
13
+ */
14
+ timeout: number;
15
+ }
16
+ /**
17
+ * An EventEmitter across two documents. It emits events on the remote document
18
+ * and takes subscribers from the local document.
19
+ * @alpha
20
+ */
21
+ export declare class Tunnel extends EventEmitter {
22
+ private _messagePort;
23
+ config: TunnelConfig;
24
+ constructor(config: TunnelConfig);
25
+ /**
26
+ * Create a Tunnel that connects to the page running in the provided iframe.
27
+ *
28
+ * @remarks
29
+ * Returns a Tunnel that listens for connection requests from the page in the
30
+ * provided iframe, which it will send periodically until timeout if that page
31
+ * has called {@link Tunnel.toParent}. If it receives one, the Tunnel will accept the
32
+ * connection and send an exclusive MessagePort to the xrobject on the other
33
+ * end. The tunnel may reconnect if the iframe reloads, in which case it will
34
+ * emit another "connected" event.
35
+ *
36
+ * @alpha
37
+ */
38
+ static toIframe(target: HTMLIFrameElement, options: Partial<TunnelConfig>): Tunnel;
39
+ /**
40
+ * Create a Tunnel that connects to the page running in the parent window.
41
+ *
42
+ * @remarks
43
+ * Returns a Tunnel that starts sending connection requests to the parent
44
+ * window, sending them periodically until the window responds with an accept
45
+ * message or the timeout passes. The parent window will accept the request if
46
+ * it calls {@link Tunnel.toIframe}.
47
+ *
48
+ * @alpha
49
+ */
50
+ static toParent(source: WindowProxy, opts: Partial<TunnelConfig>): Tunnel;
51
+ connect(remote: MessagePort): void;
52
+ destroy(): void;
53
+ emit(type: string | symbol, payload?: unknown): boolean;
54
+ emitLocal: (type: string | symbol, payload?: unknown) => any;
55
+ private static _normalizeConfig;
56
+ private _emitFromMessage;
57
+ }
58
+ //# sourceMappingURL=tunnel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.d.ts","sourceRoot":"","sources":["../../src/tunnel/tunnel.ts"],"names":[],"mappings":"AAAA,OAAO,YAAY,MAAM,eAAe,CAAC;AAiCzC,aAAa;AACb,MAAM,WAAW,YAAY;IAG3B;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,OAAO,EAAE,MAAM,CAAC;CAGjB;AAuBD;;;;GAIG;AACH,qBAAa,MAAO,SAAQ,YAAY;IAGtC,OAAO,CAAC,YAAY,CAAc;IAElC,MAAM,EAAE,YAAY,CAAC;gBAMT,MAAM,EAAE,YAAY;IAShC;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,QAAQ,CACb,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,CAAC,YAAY,CAAC,GAC7B,MAAM;IAyDT;;;;;;;;;;OAUG;IACH,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG,MAAM;IAwDzE,OAAO,CAAC,MAAM,EAAE,WAAW;IAW3B,OAAO,IAAI,IAAI;IAUf,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,GAAG,OAAO;IAQvD,SAAS,SAAU,MAAM,GAAG,MAAM,YAAY,OAAO,SAEnD;IAMF,OAAO,CAAC,MAAM,CAAC,gBAAgB;IA8B/B,OAAO,CAAC,gBAAgB,CAEtB;CAGH"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tunnel.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.test.d.ts","sourceRoot":"","sources":["../../src/tunnel/tunnel.test.ts"],"names":[],"mappings":""}
package/dist/types.d.ts CHANGED
@@ -133,10 +133,7 @@ export interface HostConnection<T = unknown> {
133
133
  export interface GuestConnection {
134
134
  id: string;
135
135
  url: URL;
136
- attachUI(frame: HTMLIFrameElement, privateMethods?: RemoteHostApis): {
137
- promise: Promise<unknown>;
138
- destroy: Function;
139
- };
136
+ attachUI(frame: HTMLIFrameElement, privateMethods?: RemoteHostApis): Promise<unknown>;
140
137
  load(): Promise<unknown>;
141
138
  error?: Error;
142
139
  hasCapabilities(capabilities: unknown): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /** @internal */
2
+ export declare type Primitive = string | number | boolean;
3
+ export declare function isPlainObject<T>(value: unknown): value is T & object;
4
+ export declare function isPrimitive(value: unknown): value is Primitive;
5
+ export declare function isIterable<T>(value: unknown): value is T[];
6
+ export declare function isFunction(value: unknown): value is CallableFunction;
7
+ export declare function hasProp(value: unknown, prop: string): boolean;
8
+ export declare function isTunnelSource(value: unknown): value is Window | ServiceWorker;
9
+ export declare function isIframe(value: unknown): value is HTMLIFrameElement;
10
+ //# sourceMappingURL=value-assertions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"value-assertions.d.ts","sourceRoot":"","sources":["../src/value-assertions.ts"],"names":[],"mappings":"AAAA,gBAAgB;AAChB,oBAAY,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAElD,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,CAAC,GAAG,MAAM,CAMpE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAM9D;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,CAAC,EAAE,CAE1D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAEpE;AAED,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAEnD;AAED,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,MAAM,GAAG,aAAa,CAMjC;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,iBAAiB,CAMnE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adobe/uix-core",
3
- "version": "0.6.5",
3
+ "version": "0.7.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -0,0 +1,3 @@
1
+ const { MessageChannel, MessagePort } = require("node:worker_threads");
2
+ window.MessageChannel = MessageChannel;
3
+ window.MessagePort = MessagePort;
@@ -0,0 +1,13 @@
1
+ type CleanupHandler = (heldValue: any) => void;
2
+ const register = jest.fn();
3
+ const unregister = jest.fn();
4
+ export class FakeFinalizationRegistry {
5
+ static mock: FakeFinalizationRegistry;
6
+ register = register;
7
+ unregister = unregister;
8
+ cleanupHandler: jest.MockedFunction<CleanupHandler>;
9
+ constructor(handler: CleanupHandler) {
10
+ this.cleanupHandler = jest.fn(handler);
11
+ FakeFinalizationRegistry.mock = this;
12
+ }
13
+ }
@@ -0,0 +1,10 @@
1
+ export class FakeWeakRef<T> {
2
+ ref: T;
3
+ constructor(ref: T) {
4
+ this.ref = ref;
5
+ }
6
+ deref(): T {
7
+ return this.ref;
8
+ }
9
+ readonly [Symbol.toStringTag]: "WeakRef";
10
+ }
@@ -0,0 +1,6 @@
1
+ /** @internal */
2
+ export const NS_ROOT = "_$pg";
3
+ export const VERSION = "0.0.1";
4
+ export const SYM_CLEANUP = Symbol(`${NS_ROOT}_cleanup`);
5
+ export const SYM_INTERNAL = Symbol(`${NS_ROOT}_internal`);
6
+ export const INIT_CALLBACK = `${NS_ROOT}_init_cb`;
@@ -0,0 +1,117 @@
1
+ import type { WrappedMessage } from "./message-wrapper";
2
+ import { wrap } from "./message-wrapper";
3
+ import { ObjectSimulator } from "./object-simulator";
4
+ import type { Asynced } from "./object-walker";
5
+ import { timeoutPromise } from "./promises/timed";
6
+ import { receiveCalls } from "./rpc";
7
+ import type { InitTicket } from "./tickets";
8
+ import { INIT_TICKET } from "./tickets";
9
+ import type { TunnelConfig } from "./tunnel";
10
+ import { Tunnel } from "./tunnel";
11
+
12
+ const INIT_MESSAGE: WrappedMessage<InitTicket> = wrap(INIT_TICKET);
13
+
14
+ /**
15
+ * Representation of an object on the other side of an iframe/window divide
16
+ * between JS runtimes.
17
+ *
18
+ * @remarks
19
+ * At first, xrobject simply returned the proxy to the remote object and did
20
+ * not expose any of the underlying event handling. However, there was no way
21
+ * for a consumer to handle the case where the remote iframe reloaded, which
22
+ * would invalidate all of the simulated objects.
23
+ *
24
+ * This new manager object exposes the {@link Tunnel} object so that consumers
25
+ * can subscribe to the "api" event.
26
+ * @alpha
27
+ */
28
+ export interface CrossRealmObject<ExpectedApi> {
29
+ /**
30
+ * The event emitter that transmits RPC events between remotes. Can be used to
31
+ * listen to "api" events, which re-emit the initial remote API after an
32
+ * unexpected reload. Can also be used to manually destroy the xrobject.
33
+ * @internal
34
+ */
35
+ tunnel: Tunnel;
36
+ /**
37
+ * Accessor for the simulated object. Putting the object behind an accessor is
38
+ * a way (we hope) to subtly discourage hanging on to a reference to the
39
+ * object, which will invalidate without the holder of the reference knowing.
40
+ * @internal
41
+ */
42
+ getRemoteApi(): Asynced<ExpectedApi>;
43
+ }
44
+
45
+ async function setupApiExchange<T>(
46
+ tunnel: Tunnel,
47
+ apiToSend: unknown
48
+ ): Promise<CrossRealmObject<T>> {
49
+ let done = false;
50
+ let remoteApi!: Asynced<T>;
51
+ const xrObject: CrossRealmObject<T> = {
52
+ tunnel,
53
+ getRemoteApi(): Asynced<T> {
54
+ return remoteApi;
55
+ },
56
+ };
57
+ return timeoutPromise(
58
+ "Initial API exchange",
59
+ new Promise((resolve, reject) => {
60
+ const simulator = ObjectSimulator.create(tunnel, FinalizationRegistry);
61
+
62
+ const sendApi = simulator.makeSender(INIT_MESSAGE);
63
+ const apiCallback = (api: Asynced<T>) => {
64
+ remoteApi = api;
65
+ if (!done) {
66
+ done = true;
67
+ resolve(xrObject);
68
+ }
69
+ };
70
+ tunnel.on("api", apiCallback);
71
+
72
+ const unsubscribe = receiveCalls(
73
+ (api: Asynced<T>) => tunnel.emitLocal("api", api),
74
+ INIT_TICKET,
75
+ new WeakRef(simulator.subject)
76
+ );
77
+ const destroy = (e: Error) => {
78
+ unsubscribe();
79
+ if (!done) {
80
+ done = true;
81
+ reject(e);
82
+ }
83
+ };
84
+ tunnel.on("destroyed", destroy);
85
+ tunnel.on("connected", () =>
86
+ (sendApi as Function)(apiToSend).catch(destroy)
87
+ );
88
+ }),
89
+ tunnel.config.timeout,
90
+ () => tunnel.destroy()
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Create a CrossRealmObject in an iframe, simulating objects from the parent window.
96
+ * @alpha
97
+ */
98
+ export async function connectParentWindow<Expected>(
99
+ tunnelOptions: Partial<TunnelConfig>,
100
+ apiToSend: unknown
101
+ ): Promise<CrossRealmObject<Expected>> {
102
+ const tunnel = Tunnel.toParent(window.parent, tunnelOptions);
103
+ return setupApiExchange<Expected>(tunnel, apiToSend);
104
+ }
105
+
106
+ /**
107
+ * Create a CrossRealmObject simulating objects from the provided iframe runtime.
108
+ * @alpha
109
+ */
110
+ export async function connectIframe<Expected>(
111
+ frame: HTMLIFrameElement,
112
+ tunnelOptions: Partial<TunnelConfig>,
113
+ apiToSend: unknown
114
+ ): Promise<CrossRealmObject<Expected>> {
115
+ const tunnel = Tunnel.toIframe(frame, tunnelOptions);
116
+ return setupApiExchange<Expected>(tunnel, apiToSend);
117
+ }
package/src/debuglog.ts CHANGED
@@ -1,4 +1,4 @@
1
- /*
1
+ /**
2
2
  Copyright 2022 Adobe. All rights reserved.
3
3
  This file is licensed to you under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License. You may obtain a copy
package/src/index.ts CHANGED
@@ -19,5 +19,8 @@ export * from "./debug-emitter";
19
19
  export * from "./debuglog";
20
20
  export * from "./emitter";
21
21
  export * from "./namespace-proxy";
22
- export * from "./timeout-promise";
23
22
  export * from "./types";
23
+ export * from "./cross-realm-object";
24
+ export * from "./promises";
25
+ export * from "./tunnel";
26
+ export type { Asynced } from "./object-walker";
@@ -0,0 +1,35 @@
1
+ import { NS_ROOT } from "./constants";
2
+ import { isPlainObject } from "./value-assertions";
3
+
4
+ /** @internal */
5
+ export type WrappedMessage<Message extends object> = { [NS_ROOT]: Message };
6
+
7
+ export function wrap<Message extends object = object>(
8
+ message: Message
9
+ ): WrappedMessage<Message> {
10
+ return { [NS_ROOT]: message };
11
+ }
12
+
13
+ export function unwrap<Message extends object>(
14
+ wrappedMessage: WrappedMessage<Message>
15
+ ): Message {
16
+ return wrappedMessage[NS_ROOT];
17
+ }
18
+
19
+ export function isWrapped<Message extends object = object>(
20
+ item: unknown
21
+ ): item is WrappedMessage<Message> {
22
+ if (!isPlainObject(item)) {
23
+ return false;
24
+ }
25
+ const keys = Object.keys(item);
26
+ const hasRoot = keys.includes(NS_ROOT);
27
+ if (hasRoot && keys.length != 1) {
28
+ console.error(
29
+ `malformed tunnel message, should have one prop "${NS_ROOT}" at root`,
30
+ item
31
+ );
32
+ return false;
33
+ }
34
+ return hasRoot;
35
+ }
@@ -0,0 +1,135 @@
1
+ import { NS_ROOT } from "./constants";
2
+ import { EventEmitter } from "eventemitter3";
3
+ import { ObjectSimulator } from "./object-simulator";
4
+ import { FakeFinalizationRegistry } from "./__mocks__/mock-finalization-registry";
5
+ import { wait } from "./promises/wait";
6
+ import { DefMessage } from "./object-walker";
7
+
8
+ describe("function simulator exchanges functions and tickets", () => {
9
+ let objectSimulator: ObjectSimulator;
10
+ beforeEach(() => {
11
+ jest.spyOn(console, "error").mockImplementation(() => {});
12
+ const emitter = new EventEmitter();
13
+ objectSimulator = ObjectSimulator.create(emitter, FakeFinalizationRegistry);
14
+ });
15
+ it("turns an object with functions into an object with tickets", async () => {
16
+ const invokeIt = (blorp: CallableFunction) => blorp();
17
+ const gnorf = {
18
+ slorf: {
19
+ blorf: (x: number) => x + 1,
20
+ },
21
+ };
22
+ const toBeTicketed = {
23
+ list: [
24
+ {
25
+ what: 8,
26
+ doa: invokeIt,
27
+ },
28
+ ],
29
+ gnorf,
30
+ harbl: 3,
31
+ };
32
+ const ticketed = objectSimulator.simulate(toBeTicketed);
33
+ expect(ticketed).toMatchInlineSnapshot(`
34
+ {
35
+ "gnorf": {
36
+ "slorf": {
37
+ "blorf": {
38
+ "_\$pg": {
39
+ "fnId": "blorf_2",
40
+ },
41
+ },
42
+ },
43
+ },
44
+ "harbl": 3,
45
+ "list": [
46
+ {
47
+ "doa": {
48
+ "_\$pg": {
49
+ "fnId": "invokeIt_1",
50
+ },
51
+ },
52
+ "what": 8,
53
+ },
54
+ ],
55
+ }
56
+ `);
57
+ const unticketed = objectSimulator.materialize(ticketed);
58
+ expect(unticketed).toMatchInlineSnapshot(`
59
+ {
60
+ "gnorf": {
61
+ "slorf": {
62
+ "blorf": [Function],
63
+ },
64
+ },
65
+ "harbl": 3,
66
+ "list": [
67
+ {
68
+ "doa": [Function],
69
+ "what": 8,
70
+ },
71
+ ],
72
+ }
73
+ `);
74
+ const remoteInvokeIt = unticketed.list[0].doa;
75
+ await expect(remoteInvokeIt(() => "oh noes")).resolves.toBe("oh noes");
76
+ await expect(unticketed.gnorf.slorf.blorf(9)).resolves.toBe(10);
77
+ });
78
+ it("dies when an object has an unrecognizable value", () => {
79
+ expect(() =>
80
+ objectSimulator.simulate({
81
+ lol: Symbol("lol"),
82
+ })
83
+ ).toThrowError("Bad value");
84
+ });
85
+ it("passes through tickets when unexpected", () => {
86
+ const hasTicket = {
87
+ [NS_ROOT]: {
88
+ some: "ticket",
89
+ },
90
+ };
91
+ const doTicket = () => objectSimulator.simulate({ hasTicket });
92
+ expect(doTicket).not.toThrowError();
93
+ expect(doTicket()).toMatchObject({ hasTicket });
94
+ });
95
+ it("strips unserializable props, but throws on unserializable values", () => {
96
+ expect(() =>
97
+ objectSimulator.simulate({
98
+ lol: Symbol("lol"),
99
+ })
100
+ ).toThrowError("Bad value");
101
+ expect(() =>
102
+ objectSimulator.simulate({
103
+ [Symbol("lol")]: "lol",
104
+ })
105
+ ).not.toThrowError();
106
+ });
107
+ it("can handle root functions", async () => {
108
+ let called = false;
109
+ const ticketedLoneFn = objectSimulator.simulate(() => {
110
+ called = true;
111
+ });
112
+ expect(ticketedLoneFn).toMatchInlineSnapshot(`
113
+ {
114
+ "_$pg": {
115
+ "fnId": "<anonymous>_1",
116
+ },
117
+ }
118
+ `);
119
+ const loneFn = objectSimulator.materialize(ticketedLoneFn);
120
+ await expect(loneFn()).resolves.not.toThrowError();
121
+ expect(called).toBe(true);
122
+ });
123
+ it("notifies remote when FinalizationRegistry calls cleanup handler", async () => {
124
+ const willBeGCed = objectSimulator.simulate(() => {}) as DefMessage;
125
+ objectSimulator.materialize(willBeGCed);
126
+ const { subject } = objectSimulator;
127
+ const fakeTicket = willBeGCed[NS_ROOT];
128
+ const gcHandler = jest.fn();
129
+ subject.onOutOfScope(fakeTicket, gcHandler);
130
+ const lastCleanupHandler = FakeFinalizationRegistry.mock.cleanupHandler;
131
+ lastCleanupHandler(fakeTicket.fnId);
132
+ await wait(100);
133
+ expect(gcHandler).toHaveBeenCalled();
134
+ });
135
+ });
@@ -0,0 +1,136 @@
1
+ import { isWrapped, unwrap, wrap } from "./message-wrapper";
2
+ import EventEmitter from "eventemitter3";
3
+ import type { DefMessage, Materialized, Simulated } from "./object-walker";
4
+ import { NOT_TRANSFORMED, transformRecursive } from "./object-walker";
5
+ import { makeCallSender, receiveCalls } from "./rpc";
6
+ import type { Simulator } from "./remote-subject";
7
+ import { RemoteSubject } from "./remote-subject";
8
+ import type { DefTicket } from "./tickets";
9
+ import { hasProp } from "./value-assertions";
10
+
11
+ function isDefMessage(value: unknown): value is DefMessage {
12
+ return isWrapped(value) && hasProp(unwrap(value), "fnId");
13
+ }
14
+
15
+ const bindAll = <T>(inst: T, methods: (keyof T)[]) => {
16
+ for (const methodName of methods) {
17
+ const method = inst[methodName];
18
+ if (typeof method === "function") {
19
+ inst[methodName] = method.bind(inst);
20
+ }
21
+ }
22
+ };
23
+
24
+ interface CleanupNotifier {
25
+ // #region Public Methods
26
+
27
+ register(obj: any, heldValue: string, ref?: any): void;
28
+ unregister(ref: any): void;
29
+
30
+ // #endregion Public Methods
31
+ }
32
+
33
+ interface CleanupNotifierConstructor {
34
+ new (callback: (heldValue: unknown) => void): CleanupNotifier;
35
+ }
36
+
37
+ export class ObjectSimulator implements Simulator {
38
+ // #region Properties
39
+
40
+ private cleanupNotifier: CleanupNotifier;
41
+ private fnCounter = 0;
42
+ private receiverTicketCache: WeakMap<CallableFunction, DefTicket> =
43
+ new WeakMap();
44
+ private senderCache: WeakMap<DefTicket, CallableFunction> = new WeakMap();
45
+
46
+ subject: RemoteSubject;
47
+
48
+ // #endregion Properties
49
+
50
+ // #region Constructors
51
+
52
+ constructor(subject: RemoteSubject, cleanupNotifier: CleanupNotifier) {
53
+ this.cleanupNotifier = cleanupNotifier;
54
+ this.subject = subject;
55
+
56
+ bindAll(this, ["makeSender", "makeReceiver", "simulate", "materialize"]);
57
+ }
58
+
59
+ // #endregion Constructors
60
+
61
+ // #region Public Static Methods
62
+
63
+ static create(
64
+ emitter: EventEmitter,
65
+ Cleanup: CleanupNotifierConstructor
66
+ ): ObjectSimulator {
67
+ let simulator: Simulator;
68
+ // proxy simulator, so as not to have cyclic dependency
69
+ const simulatorInterface: Simulator = {
70
+ simulate: (x) => simulator.simulate(x),
71
+ materialize: (x) => simulator.materialize(x),
72
+ };
73
+
74
+ const subject = new RemoteSubject(emitter, simulatorInterface);
75
+
76
+ const cleanupNotifier = new Cleanup((fnId: string) => {
77
+ return subject.notifyCleanup({ fnId });
78
+ });
79
+
80
+ simulator = new ObjectSimulator(subject, cleanupNotifier);
81
+
82
+ return simulator as ObjectSimulator;
83
+ }
84
+
85
+ // #endregion Public Static Methods
86
+
87
+ // #region Public Methods
88
+
89
+ makeReceiver(fn: CallableFunction) {
90
+ if (typeof fn !== "function") {
91
+ return NOT_TRANSFORMED;
92
+ }
93
+ let fnTicket = this.receiverTicketCache.get(fn);
94
+ if (!fnTicket) {
95
+ fnTicket = {
96
+ fnId: `${fn.name || "<anonymous>"}_${++this.fnCounter}`,
97
+ };
98
+ const cleanup = receiveCalls(fn, fnTicket, new WeakRef(this.subject));
99
+ this.subject.onOutOfScope(fnTicket, cleanup);
100
+ this.receiverTicketCache.set(fn, fnTicket);
101
+ }
102
+ return wrap(fnTicket);
103
+ }
104
+
105
+ makeSender(message: unknown) {
106
+ if (!isDefMessage(message)) {
107
+ return NOT_TRANSFORMED;
108
+ }
109
+ const ticket = unwrap(message);
110
+ /* istanbul ignore else: preopt */
111
+ if (!this.senderCache.has(ticket)) {
112
+ const sender = makeCallSender(ticket, new WeakRef(this.subject));
113
+ this.cleanupNotifier.register(sender, ticket.fnId, sender);
114
+ this.senderCache.set(ticket, sender);
115
+ return sender;
116
+ } else {
117
+ return this.senderCache.get(ticket) as CallableFunction;
118
+ }
119
+ }
120
+
121
+ materialize<T>(simulated: T) {
122
+ return transformRecursive<CallableFunction>(
123
+ this.makeSender,
124
+ simulated
125
+ ) as Materialized<T>;
126
+ }
127
+
128
+ simulate<T>(localObject: T) {
129
+ return transformRecursive<DefMessage>(
130
+ this.makeReceiver,
131
+ localObject
132
+ ) as Simulated<T>;
133
+ }
134
+
135
+ // #endregion Public Methods
136
+ }