penpal 7.0.3 → 7.0.4

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 (111) hide show
  1. package/dist/penpal.cjs +953 -0
  2. package/dist/penpal.cjs.map +1 -0
  3. package/dist/penpal.d.cts +234 -0
  4. package/dist/penpal.d.ts +234 -0
  5. package/dist/penpal.js +890 -1033
  6. package/dist/penpal.js.map +1 -0
  7. package/dist/penpal.min.js +1 -1
  8. package/dist/penpal.min.js.map +1 -1
  9. package/dist/penpal.mjs +943 -0
  10. package/dist/penpal.mjs.map +1 -0
  11. package/package.json +13 -21
  12. package/cjs/CallOptions.d.ts +0 -10
  13. package/cjs/CallOptions.js +0 -16
  14. package/cjs/ErrorCodeObj.d.ts +0 -9
  15. package/cjs/ErrorCodeObj.js +0 -14
  16. package/cjs/PenpalBugError.d.ts +0 -8
  17. package/cjs/PenpalBugError.js +0 -12
  18. package/cjs/PenpalError.d.ts +0 -6
  19. package/cjs/PenpalError.js +0 -11
  20. package/cjs/Reply.d.ts +0 -9
  21. package/cjs/Reply.js +0 -16
  22. package/cjs/backwardCompatibility.d.ts +0 -56
  23. package/cjs/backwardCompatibility.js +0 -134
  24. package/cjs/connect.d.ts +0 -33
  25. package/cjs/connect.js +0 -78
  26. package/cjs/connectCallHandler.d.ts +0 -8
  27. package/cjs/connectCallHandler.js +0 -90
  28. package/cjs/connectRemoteProxy.d.ts +0 -12
  29. package/cjs/connectRemoteProxy.js +0 -139
  30. package/cjs/debug.d.ts +0 -3
  31. package/cjs/debug.js +0 -8
  32. package/cjs/errorSerialization.d.ts +0 -9
  33. package/cjs/errorSerialization.js +0 -26
  34. package/cjs/generateId.d.ts +0 -8
  35. package/cjs/generateId.js +0 -11
  36. package/cjs/getPromiseWithResolvers.d.ts +0 -6
  37. package/cjs/getPromiseWithResolvers.js +0 -19
  38. package/cjs/guards.d.ts +0 -10
  39. package/cjs/guards.js +0 -40
  40. package/cjs/index.d.ts +0 -12
  41. package/cjs/index.js +0 -21
  42. package/cjs/indexForBundle.d.ts +0 -31
  43. package/cjs/indexForBundle.js +0 -22
  44. package/cjs/messengers/Messenger.d.ts +0 -14
  45. package/cjs/messengers/Messenger.js +0 -2
  46. package/cjs/messengers/PortMessenger.d.ts +0 -21
  47. package/cjs/messengers/PortMessenger.js +0 -47
  48. package/cjs/messengers/WindowMessenger.d.ts +0 -29
  49. package/cjs/messengers/WindowMessenger.js +0 -178
  50. package/cjs/messengers/WorkerMessenger.d.ts +0 -23
  51. package/cjs/messengers/WorkerMessenger.js +0 -86
  52. package/cjs/methodSerialization.d.ts +0 -22
  53. package/cjs/methodSerialization.js +0 -48
  54. package/cjs/namespace.d.ts +0 -2
  55. package/cjs/namespace.js +0 -3
  56. package/cjs/once.d.ts +0 -2
  57. package/cjs/once.js +0 -15
  58. package/cjs/shakeHands.d.ts +0 -76
  59. package/cjs/shakeHands.js +0 -190
  60. package/cjs/types.d.ts +0 -89
  61. package/cjs/types.js +0 -2
  62. package/lib/CallOptions.d.ts +0 -10
  63. package/lib/CallOptions.js +0 -14
  64. package/lib/ErrorCodeObj.d.ts +0 -9
  65. package/lib/ErrorCodeObj.js +0 -12
  66. package/lib/PenpalBugError.d.ts +0 -8
  67. package/lib/PenpalBugError.js +0 -10
  68. package/lib/PenpalError.d.ts +0 -6
  69. package/lib/PenpalError.js +0 -9
  70. package/lib/Reply.d.ts +0 -9
  71. package/lib/Reply.js +0 -14
  72. package/lib/backwardCompatibility.d.ts +0 -56
  73. package/lib/backwardCompatibility.js +0 -128
  74. package/lib/connect.d.ts +0 -33
  75. package/lib/connect.js +0 -76
  76. package/lib/connectCallHandler.d.ts +0 -8
  77. package/lib/connectCallHandler.js +0 -88
  78. package/lib/connectRemoteProxy.d.ts +0 -12
  79. package/lib/connectRemoteProxy.js +0 -137
  80. package/lib/debug.d.ts +0 -3
  81. package/lib/debug.js +0 -6
  82. package/lib/errorSerialization.d.ts +0 -9
  83. package/lib/errorSerialization.js +0 -21
  84. package/lib/generateId.d.ts +0 -8
  85. package/lib/generateId.js +0 -9
  86. package/lib/getPromiseWithResolvers.d.ts +0 -6
  87. package/lib/getPromiseWithResolvers.js +0 -17
  88. package/lib/guards.d.ts +0 -10
  89. package/lib/guards.js +0 -28
  90. package/lib/index.d.ts +0 -12
  91. package/lib/index.js +0 -9
  92. package/lib/indexForBundle.d.ts +0 -31
  93. package/lib/indexForBundle.js +0 -20
  94. package/lib/messengers/Messenger.d.ts +0 -14
  95. package/lib/messengers/Messenger.js +0 -1
  96. package/lib/messengers/PortMessenger.d.ts +0 -21
  97. package/lib/messengers/PortMessenger.js +0 -45
  98. package/lib/messengers/WindowMessenger.d.ts +0 -29
  99. package/lib/messengers/WindowMessenger.js +0 -176
  100. package/lib/messengers/WorkerMessenger.d.ts +0 -23
  101. package/lib/messengers/WorkerMessenger.js +0 -84
  102. package/lib/methodSerialization.d.ts +0 -22
  103. package/lib/methodSerialization.js +0 -42
  104. package/lib/namespace.d.ts +0 -2
  105. package/lib/namespace.js +0 -1
  106. package/lib/once.d.ts +0 -2
  107. package/lib/once.js +0 -13
  108. package/lib/shakeHands.d.ts +0 -76
  109. package/lib/shakeHands.js +0 -188
  110. package/lib/types.d.ts +0 -89
  111. package/lib/types.js +0 -1
@@ -1,47 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const PenpalError_js_1 = require("../PenpalError.js");
4
- /**
5
- * Handles the details of communicating on a MessagePort.
6
- */
7
- class PortMessenger {
8
- #port;
9
- #validateReceivedMessage;
10
- #messageCallbacks = new Set();
11
- constructor({ port }) {
12
- if (!port) {
13
- throw new PenpalError_js_1.default('INVALID_ARGUMENT', 'port must be defined');
14
- }
15
- this.#port = port;
16
- }
17
- initialize = ({ validateReceivedMessage }) => {
18
- this.#validateReceivedMessage = validateReceivedMessage;
19
- this.#port.addEventListener('message', this.#handleMessage);
20
- this.#port.start();
21
- };
22
- sendMessage = (message, transferables) => {
23
- this.#port?.postMessage(message, {
24
- transfer: transferables,
25
- });
26
- };
27
- addMessageHandler = (callback) => {
28
- this.#messageCallbacks.add(callback);
29
- };
30
- removeMessageHandler = (callback) => {
31
- this.#messageCallbacks.delete(callback);
32
- };
33
- destroy = () => {
34
- this.#port.removeEventListener('message', this.#handleMessage);
35
- this.#port.close();
36
- this.#messageCallbacks.clear();
37
- };
38
- #handleMessage = ({ data }) => {
39
- if (!this.#validateReceivedMessage?.(data)) {
40
- return;
41
- }
42
- for (const callback of this.#messageCallbacks) {
43
- callback(data);
44
- }
45
- };
46
- }
47
- exports.default = PortMessenger;
@@ -1,29 +0,0 @@
1
- import { Message } from '../types.js';
2
- import Messenger, { InitializeMessengerOptions, MessageHandler } from './Messenger.js';
3
- type Options = {
4
- /**
5
- * The window with which the current window will communicate.
6
- */
7
- remoteWindow: Window;
8
- /**
9
- * An array of strings or regular expressions defining to which origins
10
- * communication will be allowed. If not provided, communication will be
11
- * restricted to the origin of the current page. You may specify an allowed
12
- * origin of `*` to not restrict communication, but beware the risks of
13
- * doing so.
14
- */
15
- allowedOrigins?: (string | RegExp)[];
16
- };
17
- /**
18
- * Handles the details of communicating with a child window.
19
- */
20
- declare class WindowMessenger implements Messenger {
21
- #private;
22
- constructor({ remoteWindow, allowedOrigins }: Options);
23
- initialize: ({ log, validateReceivedMessage, }: InitializeMessengerOptions) => void;
24
- sendMessage: (message: Message, transferables?: Transferable[]) => void;
25
- addMessageHandler: (callback: MessageHandler) => void;
26
- removeMessageHandler: (callback: MessageHandler) => void;
27
- destroy: () => void;
28
- }
29
- export default WindowMessenger;
@@ -1,178 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const backwardCompatibility_js_1 = require("../backwardCompatibility.js");
4
- const guards_js_1 = require("../guards.js");
5
- const PenpalError_js_1 = require("../PenpalError.js");
6
- const PenpalBugError_js_1 = require("../PenpalBugError.js");
7
- /**
8
- * Handles the details of communicating with a child window.
9
- */
10
- class WindowMessenger {
11
- #remoteWindow;
12
- #allowedOrigins;
13
- #log;
14
- #validateReceivedMessage;
15
- #concreteRemoteOrigin;
16
- #messageCallbacks = new Set();
17
- #port;
18
- // TODO: Used for backward-compatibility. Remove in next major version.
19
- #isChildUsingDeprecatedProtocol = false;
20
- constructor({ remoteWindow, allowedOrigins }) {
21
- if (!remoteWindow) {
22
- throw new PenpalError_js_1.default('INVALID_ARGUMENT', 'remoteWindow must be defined');
23
- }
24
- this.#remoteWindow = remoteWindow;
25
- this.#allowedOrigins = allowedOrigins?.length
26
- ? allowedOrigins
27
- : [window.origin];
28
- }
29
- initialize = ({ log, validateReceivedMessage, }) => {
30
- this.#log = log;
31
- this.#validateReceivedMessage = validateReceivedMessage;
32
- window.addEventListener('message', this.#handleMessageFromRemoteWindow);
33
- };
34
- sendMessage = (message, transferables) => {
35
- if ((0, guards_js_1.isSynMessage)(message)) {
36
- const originForSending = this.#getOriginForSendingMessage(message);
37
- this.#remoteWindow.postMessage(message, {
38
- targetOrigin: originForSending,
39
- transfer: transferables,
40
- });
41
- return;
42
- }
43
- if ((0, guards_js_1.isAck1Message)(message) ||
44
- // If the child is using a previous version of Penpal, we need to
45
- // downgrade the message and send it through the window rather than
46
- // the port because older versions of Penpal don't use MessagePorts.
47
- this.#isChildUsingDeprecatedProtocol) {
48
- const payload = this.#isChildUsingDeprecatedProtocol
49
- ? (0, backwardCompatibility_js_1.downgradeMessage)(message)
50
- : message;
51
- const originForSending = this.#getOriginForSendingMessage(message);
52
- this.#remoteWindow.postMessage(payload, {
53
- targetOrigin: originForSending,
54
- transfer: transferables,
55
- });
56
- return;
57
- }
58
- if ((0, guards_js_1.isAck2Message)(message)) {
59
- const { port1, port2 } = new MessageChannel();
60
- this.#port = port1;
61
- port1.addEventListener('message', this.#handleMessageFromPort);
62
- port1.start();
63
- const transferablesToSend = [port2, ...(transferables || [])];
64
- const originForSending = this.#getOriginForSendingMessage(message);
65
- this.#remoteWindow.postMessage(message, {
66
- targetOrigin: originForSending,
67
- transfer: transferablesToSend,
68
- });
69
- return;
70
- }
71
- if (this.#port) {
72
- this.#port.postMessage(message, {
73
- transfer: transferables,
74
- });
75
- return;
76
- }
77
- throw new PenpalBugError_js_1.default('Port is undefined');
78
- };
79
- addMessageHandler = (callback) => {
80
- this.#messageCallbacks.add(callback);
81
- };
82
- removeMessageHandler = (callback) => {
83
- this.#messageCallbacks.delete(callback);
84
- };
85
- destroy = () => {
86
- window.removeEventListener('message', this.#handleMessageFromRemoteWindow);
87
- this.#destroyPort();
88
- this.#messageCallbacks.clear();
89
- };
90
- #isAllowedOrigin = (origin) => {
91
- return this.#allowedOrigins.some((allowedOrigin) => allowedOrigin instanceof RegExp
92
- ? allowedOrigin.test(origin)
93
- : allowedOrigin === origin || allowedOrigin === '*');
94
- };
95
- #getOriginForSendingMessage = (message) => {
96
- // It's safe to send the SYN message to any origin because it doesn't contain
97
- // anything sensitive. When Penpal receives a SYN message, the origin on
98
- // the message (which we call the concrete origin) is validated against the
99
- // configured allowed origins. All subsequent messages will be sent to the
100
- // concrete origin.
101
- // If you decide to change this, consider https://github.com/Aaronius/penpal/issues/103
102
- if ((0, guards_js_1.isSynMessage)(message)) {
103
- return '*';
104
- }
105
- if (!this.#concreteRemoteOrigin) {
106
- throw new PenpalBugError_js_1.default('Concrete remote origin not set');
107
- }
108
- // If the concrete remote origin (the origin we received from the remote
109
- // on a prior message) is 'null', it means the remote is within
110
- // an "opaque origin". The only way to post a message to an
111
- // opaque origin is by using '*'. This does carry some security risk,
112
- // so we only do this if the consumer has specifically defined '*' as
113
- // an allowed origin. Opaque origins occur, for example, when
114
- // loading an HTML document directly from the filesystem (not a
115
- // web server) or through a data URI.
116
- return this.#concreteRemoteOrigin === 'null' &&
117
- this.#allowedOrigins.includes('*')
118
- ? '*'
119
- : this.#concreteRemoteOrigin;
120
- };
121
- #destroyPort = () => {
122
- this.#port?.removeEventListener('message', this.#handleMessageFromPort);
123
- this.#port?.close();
124
- this.#port = undefined;
125
- };
126
- #handleMessageFromRemoteWindow = ({ source, origin, ports, data, }) => {
127
- if (source !== this.#remoteWindow) {
128
- return;
129
- }
130
- // TODO: Used for backward-compatibility. Remove in next major version.
131
- if ((0, backwardCompatibility_js_1.isDeprecatedMessage)(data)) {
132
- this.#log?.('Please upgrade the child window to the latest version of Penpal.');
133
- this.#isChildUsingDeprecatedProtocol = true;
134
- data = (0, backwardCompatibility_js_1.upgradeMessage)(data);
135
- }
136
- if (!this.#validateReceivedMessage?.(data)) {
137
- return;
138
- }
139
- if (!this.#isAllowedOrigin(origin)) {
140
- this.#log?.(`Received a message from origin \`${origin}\` which did not match ` +
141
- `allowed origins \`[${this.#allowedOrigins.join(', ')}]\``);
142
- return;
143
- }
144
- if ((0, guards_js_1.isSynMessage)(data)) {
145
- // If we receive a SYN message and already have a port, it means
146
- // the child is re-connecting, in which case we'll receive a new port.
147
- // For this reason, we always make sure we destroy the existing port.
148
- this.#destroyPort();
149
- this.#concreteRemoteOrigin = origin;
150
- }
151
- if ((0, guards_js_1.isAck2Message)(data) &&
152
- // Previous versions of Penpal don't use MessagePorts and do all
153
- // communication through the window.
154
- !this.#isChildUsingDeprecatedProtocol) {
155
- this.#port = ports[0];
156
- if (!this.#port) {
157
- throw new PenpalBugError_js_1.default('No port received on ACK2');
158
- }
159
- this.#port.addEventListener('message', this.#handleMessageFromPort);
160
- this.#port.start();
161
- }
162
- for (const callback of this.#messageCallbacks) {
163
- callback(data);
164
- }
165
- };
166
- #handleMessageFromPort = ({ data }) => {
167
- // Unlike in _handleMessageFromWindow, we don't need to check if
168
- // the message is from a deprecated version of Penpal because older versions
169
- // of Penpal don't use MessagePorts.
170
- if (!this.#validateReceivedMessage?.(data)) {
171
- return;
172
- }
173
- for (const callback of this.#messageCallbacks) {
174
- callback(data);
175
- }
176
- };
177
- }
178
- exports.default = WindowMessenger;
@@ -1,23 +0,0 @@
1
- import { Message } from '../types.js';
2
- import Messenger, { InitializeMessengerOptions, MessageHandler } from './Messenger.js';
3
- type Options = {
4
- /**
5
- * The web worker receiving/sending communication from/to the parent window.
6
- * If this messenger is being used within the worker, `worker` should
7
- * typically be set to `self`.
8
- */
9
- worker: Worker | DedicatedWorkerGlobalScope;
10
- };
11
- /**
12
- * Handles the details of communicating with a child web worker.
13
- */
14
- declare class WorkerMessenger implements Messenger {
15
- #private;
16
- constructor({ worker }: Options);
17
- initialize: ({ validateReceivedMessage }: InitializeMessengerOptions) => void;
18
- sendMessage: (message: Message, transferables?: Transferable[]) => void;
19
- addMessageHandler: (callback: MessageHandler) => void;
20
- removeMessageHandler: (callback: MessageHandler) => void;
21
- destroy: () => void;
22
- }
23
- export default WorkerMessenger;
@@ -1,86 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const guards_js_1 = require("../guards.js");
4
- const PenpalError_js_1 = require("../PenpalError.js");
5
- const PenpalBugError_js_1 = require("../PenpalBugError.js");
6
- /**
7
- * Handles the details of communicating with a child web worker.
8
- */
9
- class WorkerMessenger {
10
- #worker;
11
- #validateReceivedMessage;
12
- #messageCallbacks = new Set();
13
- #port;
14
- constructor({ worker }) {
15
- if (!worker) {
16
- throw new PenpalError_js_1.default('INVALID_ARGUMENT', 'worker must be defined');
17
- }
18
- this.#worker = worker;
19
- }
20
- initialize = ({ validateReceivedMessage }) => {
21
- this.#validateReceivedMessage = validateReceivedMessage;
22
- this.#worker.addEventListener('message', this.#handleMessage);
23
- };
24
- sendMessage = (message, transferables) => {
25
- if ((0, guards_js_1.isSynMessage)(message) || (0, guards_js_1.isAck1Message)(message)) {
26
- this.#worker.postMessage(message, { transfer: transferables });
27
- return;
28
- }
29
- if ((0, guards_js_1.isAck2Message)(message)) {
30
- const { port1, port2 } = new MessageChannel();
31
- this.#port = port1;
32
- port1.addEventListener('message', this.#handleMessage);
33
- port1.start();
34
- this.#worker.postMessage(message, {
35
- transfer: [port2, ...(transferables || [])],
36
- });
37
- return;
38
- }
39
- if (this.#port) {
40
- this.#port.postMessage(message, {
41
- transfer: transferables,
42
- });
43
- return;
44
- }
45
- throw new PenpalBugError_js_1.default('Port is undefined');
46
- };
47
- addMessageHandler = (callback) => {
48
- this.#messageCallbacks.add(callback);
49
- };
50
- removeMessageHandler = (callback) => {
51
- this.#messageCallbacks.delete(callback);
52
- };
53
- destroy = () => {
54
- this.#worker.removeEventListener('message', this.#handleMessage);
55
- this.#destroyPort();
56
- this.#messageCallbacks.clear();
57
- };
58
- #destroyPort = () => {
59
- this.#port?.removeEventListener('message', this.#handleMessage);
60
- this.#port?.close();
61
- this.#port = undefined;
62
- };
63
- #handleMessage = ({ ports, data }) => {
64
- if (!this.#validateReceivedMessage?.(data)) {
65
- return;
66
- }
67
- if ((0, guards_js_1.isSynMessage)(data)) {
68
- // If we receive a SYN message and already have a port, it means
69
- // the child is re-connecting, in which case we'll receive a new port.
70
- // For this reason, we always make sure we destroy the existing port.
71
- this.#destroyPort();
72
- }
73
- if ((0, guards_js_1.isAck2Message)(data)) {
74
- this.#port = ports[0];
75
- if (!this.#port) {
76
- throw new PenpalBugError_js_1.default('No port received on ACK2');
77
- }
78
- this.#port.addEventListener('message', this.#handleMessage);
79
- this.#port.start();
80
- }
81
- for (const callback of this.#messageCallbacks) {
82
- callback(data);
83
- }
84
- };
85
- }
86
- exports.default = WorkerMessenger;
@@ -1,22 +0,0 @@
1
- import { MethodPath, Methods } from './types.js';
2
- /**
3
- * Given an object of (nested) keys to functions, extract paths to each function.
4
- *
5
- * @example
6
- * Given this Method object:
7
- * {
8
- * one: {
9
- * two: () => {}
10
- * }
11
- * three: () => {}
12
- * }
13
- *
14
- * the extracted MethodPath[] would be:
15
- * [
16
- * ['one', 'two'],
17
- * ['three']
18
- * ]
19
- */
20
- export declare const extractMethodPathsFromMethods: (methods: Methods, currentPath?: MethodPath) => MethodPath[];
21
- export declare const getMethodAtMethodPath: (methodPath: MethodPath, methods: Methods) => Function | undefined;
22
- export declare const formatMethodPath: (methodPath: MethodPath) => string;
@@ -1,48 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.formatMethodPath = exports.getMethodAtMethodPath = exports.extractMethodPathsFromMethods = void 0;
4
- const guards_js_1 = require("./guards.js");
5
- // TODO: Used for backward-compatibility. Remove in next major version.
6
- /**
7
- * Given an object of (nested) keys to functions, extract paths to each function.
8
- *
9
- * @example
10
- * Given this Method object:
11
- * {
12
- * one: {
13
- * two: () => {}
14
- * }
15
- * three: () => {}
16
- * }
17
- *
18
- * the extracted MethodPath[] would be:
19
- * [
20
- * ['one', 'two'],
21
- * ['three']
22
- * ]
23
- */
24
- const extractMethodPathsFromMethods = (methods, currentPath = []) => {
25
- const methodPaths = [];
26
- for (const key of Object.keys(methods)) {
27
- const value = methods[key];
28
- if ((0, guards_js_1.isFunction)(value)) {
29
- methodPaths.push([...currentPath, key]);
30
- }
31
- else if ((0, guards_js_1.isObject)(value)) {
32
- methodPaths.push(...(0, exports.extractMethodPathsFromMethods)(value, [...currentPath, key]));
33
- }
34
- }
35
- return methodPaths;
36
- };
37
- exports.extractMethodPathsFromMethods = extractMethodPathsFromMethods;
38
- const getMethodAtMethodPath = (methodPath, methods) => {
39
- const result = methodPath.reduce((acc, pathSegment) => {
40
- return (0, guards_js_1.isObject)(acc) ? acc[pathSegment] : undefined;
41
- }, methods);
42
- return (0, guards_js_1.isFunction)(result) ? result : undefined;
43
- };
44
- exports.getMethodAtMethodPath = getMethodAtMethodPath;
45
- const formatMethodPath = (methodPath) => {
46
- return methodPath.join('.');
47
- };
48
- exports.formatMethodPath = formatMethodPath;
@@ -1,2 +0,0 @@
1
- declare const _default: "penpal";
2
- export default _default;
package/cjs/namespace.js DELETED
@@ -1,3 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.default = 'penpal';
package/cjs/once.d.ts DELETED
@@ -1,2 +0,0 @@
1
- declare const once: <T extends (...args: any[]) => any>(fn: T) => ((...args: Parameters<T>) => ReturnType<T>);
2
- export default once;
package/cjs/once.js DELETED
@@ -1,15 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
4
- const once = (fn) => {
5
- let isCalled = false;
6
- let result;
7
- return (...args) => {
8
- if (!isCalled) {
9
- isCalled = true;
10
- result = fn(...args);
11
- }
12
- return result;
13
- };
14
- };
15
- exports.default = once;
@@ -1,76 +0,0 @@
1
- import Messenger from './messengers/Messenger.js';
2
- import { Methods, RemoteProxy, Log } from './types.js';
3
- type Options = {
4
- messenger: Messenger;
5
- methods: Methods;
6
- timeout: number | undefined;
7
- channel: string | undefined;
8
- log: Log | undefined;
9
- };
10
- type HandshakeResult<TMethods extends Methods> = {
11
- remoteProxy: RemoteProxy<TMethods>;
12
- destroy: () => void;
13
- };
14
- /**
15
- * Attempts to establish communication with the remote via a handshake protocol.
16
- * The handshake protocol fulfills a few requirements:
17
- *
18
- * 1. One participant in the handshake may not be available when the other
19
- * participant starts the handshake. For example, a document inside an iframe
20
- * may not be loaded when the parent window starts a handshake.
21
- * 2. While #1 could be solved by having the consumer of Penpal specify which
22
- * participant should initiate the handshake, we'd rather avoid this
23
- * unnecessary cognitive load.
24
- * 3. While #1 could be solved by having the consumer of Penpal specify which
25
- * participant is the "parent" or "child" and then having Penpal assume
26
- * the child should initiate the handshake, we'd rather avoid parent-child
27
- * terminology since Penpal can support communication between two
28
- * participants where neither would be considered a parent nor child. It may
29
- * also be too presumptive that the child should always initiate the
30
- * handshake.
31
- * 4. For robustness, each participant must know that the other participant is
32
- * receiving its messages for the handshake to be considered complete.
33
- * 5. The handshake should support a participant attempting to
34
- * re-establish the connection. This can occur, for example, if an end user
35
- * were to right-click within an iframe and click reload.
36
- * 6. The handshake should allow a Messenger to easily attach something to
37
- * a handshake message from one participant to the other unidirectionally
38
- * (rather than from both participants to each other).
39
- * This is important when a participant needs to be in charge of, for
40
- * example, creating a MessageChannel and sending one MessagePort from the
41
- * MessagePort pair to the other participant. If both participants attempted
42
- * to do this it could lead to confusion.
43
- * 7. The handshake ideally shouldn't require sending handshake messages on an
44
- * interval (retrying until the other participant is ready to receive them).
45
- * Intervals can increase compute resources if the interval is too short
46
- * or increase latency if the interval is too long. While we could make this
47
- * configurable, it's additional mental load for the consumer. Additionally,
48
- * setInterval and setTimeout are not available within some contexts
49
- * (like AudioWorklet), where a consumer may like to use Penpal.
50
- *
51
- * To accomplish these requirements, the handshake protocol is as follows:
52
- * 1. Each participant generates a random participant ID.
53
- * 2. As soon as possible, each participant sends a SYN message containing its
54
- * participant ID to the other participant.
55
- * 3. When the SYN messages were sent, one of the participants may not have
56
- * been ready to receive the SYN message from the other. At least one
57
- * of the participants was ready, however, and should have received a SYN
58
- * message from the other participant. Each participant that did receive
59
- * a SYN message knows for sure that the other participant is now ready
60
- * to receive a SYN message, so it will send another SYN message in case
61
- * the other participant did not receive the first SYN message. This
62
- * ultimately results in each participant sending two SYN messages.
63
- * 4. Each participant now should have received at least one SYN message from
64
- * the other participant. Each participant compares their own ID with the
65
- * other participant's ID. Whichever participant has the higher ID
66
- * (using a simple string comparison) is considered the handshake leader
67
- * and will send an ACK1 message to the other participant.
68
- * 5. At this point, the handshake leader does not know whether the other
69
- * participant is actually receiving messages. The participant receiving
70
- * the ACK1 message will respond with an ACK2, informing the handshake
71
- * leader that it is indeed receiving messages.
72
- * 6. At this point, both participants know the other is receiving messages
73
- * and the handshake is complete.
74
- */
75
- declare const shakeHands: <TMethods extends Methods>({ messenger, methods, timeout, channel, log, }: Options) => Promise<HandshakeResult<TMethods>>;
76
- export default shakeHands;