@prismicio/simulator 0.1.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 (127) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/SimulatorAPI.cjs +50 -0
  4. package/dist/SimulatorAPI.cjs.map +1 -0
  5. package/dist/SimulatorAPI.d.ts +12 -0
  6. package/dist/SimulatorAPI.js +50 -0
  7. package/dist/SimulatorAPI.js.map +1 -0
  8. package/dist/SimulatorClient.cjs +54 -0
  9. package/dist/SimulatorClient.cjs.map +1 -0
  10. package/dist/SimulatorClient.d.ts +10 -0
  11. package/dist/SimulatorClient.js +54 -0
  12. package/dist/SimulatorClient.js.map +1 -0
  13. package/dist/channel/ChannelEmitter.cjs +146 -0
  14. package/dist/channel/ChannelEmitter.cjs.map +1 -0
  15. package/dist/channel/ChannelEmitter.d.ts +38 -0
  16. package/dist/channel/ChannelEmitter.js +146 -0
  17. package/dist/channel/ChannelEmitter.js.map +1 -0
  18. package/dist/channel/ChannelNetwork.cjs +112 -0
  19. package/dist/channel/ChannelNetwork.cjs.map +1 -0
  20. package/dist/channel/ChannelNetwork.d.ts +24 -0
  21. package/dist/channel/ChannelNetwork.js +112 -0
  22. package/dist/channel/ChannelNetwork.js.map +1 -0
  23. package/dist/channel/ChannelReceiver.cjs +95 -0
  24. package/dist/channel/ChannelReceiver.cjs.map +1 -0
  25. package/dist/channel/ChannelReceiver.d.ts +20 -0
  26. package/dist/channel/ChannelReceiver.js +95 -0
  27. package/dist/channel/ChannelReceiver.js.map +1 -0
  28. package/dist/channel/errors.cjs +54 -0
  29. package/dist/channel/errors.cjs.map +1 -0
  30. package/dist/channel/errors.d.ts +25 -0
  31. package/dist/channel/errors.js +54 -0
  32. package/dist/channel/errors.js.map +1 -0
  33. package/dist/channel/index.d.ts +10 -0
  34. package/dist/channel/messages.cjs +66 -0
  35. package/dist/channel/messages.cjs.map +1 -0
  36. package/dist/channel/messages.d.ts +10 -0
  37. package/dist/channel/messages.js +66 -0
  38. package/dist/channel/messages.js.map +1 -0
  39. package/dist/channel/types.cjs +11 -0
  40. package/dist/channel/types.cjs.map +1 -0
  41. package/dist/channel/types.d.ts +61 -0
  42. package/dist/channel/types.js +13 -0
  43. package/dist/channel/types.js.map +1 -0
  44. package/dist/index.cjs +33 -0
  45. package/dist/index.cjs.map +1 -0
  46. package/dist/index.d.ts +7 -0
  47. package/dist/index.js +27 -0
  48. package/dist/index.js.map +1 -0
  49. package/dist/kit/SimulatorManager.cjs +140 -0
  50. package/dist/kit/SimulatorManager.cjs.map +1 -0
  51. package/dist/kit/SimulatorManager.d.ts +15 -0
  52. package/dist/kit/SimulatorManager.js +140 -0
  53. package/dist/kit/SimulatorManager.js.map +1 -0
  54. package/dist/kit/State.cjs +82 -0
  55. package/dist/kit/State.cjs.map +1 -0
  56. package/dist/kit/State.d.ts +25 -0
  57. package/dist/kit/State.js +82 -0
  58. package/dist/kit/State.js.map +1 -0
  59. package/dist/kit/domHelpers.cjs +53 -0
  60. package/dist/kit/domHelpers.cjs.map +1 -0
  61. package/dist/kit/domHelpers.d.ts +9 -0
  62. package/dist/kit/domHelpers.js +53 -0
  63. package/dist/kit/domHelpers.js.map +1 -0
  64. package/dist/kit/eventHandlers.cjs +15 -0
  65. package/dist/kit/eventHandlers.cjs.map +1 -0
  66. package/dist/kit/eventHandlers.d.ts +4 -0
  67. package/dist/kit/eventHandlers.js +15 -0
  68. package/dist/kit/eventHandlers.js.map +1 -0
  69. package/dist/kit/getDefault.cjs +16 -0
  70. package/dist/kit/getDefault.cjs.map +1 -0
  71. package/dist/kit/getDefault.d.ts +8 -0
  72. package/dist/kit/getDefault.js +16 -0
  73. package/dist/kit/getDefault.js.map +1 -0
  74. package/dist/kit/index.cjs +26 -0
  75. package/dist/kit/index.cjs.map +1 -0
  76. package/dist/kit/index.d.ts +8 -0
  77. package/dist/kit/index.js +23 -0
  78. package/dist/kit/index.js.map +1 -0
  79. package/dist/kit/messages.cjs +29 -0
  80. package/dist/kit/messages.cjs.map +1 -0
  81. package/dist/kit/messages.d.ts +1 -0
  82. package/dist/kit/messages.js +29 -0
  83. package/dist/kit/messages.js.map +1 -0
  84. package/dist/kit/types.cjs +9 -0
  85. package/dist/kit/types.cjs.map +1 -0
  86. package/dist/kit/types.d.ts +23 -0
  87. package/dist/kit/types.js +10 -0
  88. package/dist/kit/types.js.map +1 -0
  89. package/dist/lib/EventEmitter.cjs +27 -0
  90. package/dist/lib/EventEmitter.cjs.map +1 -0
  91. package/dist/lib/EventEmitter.d.ts +10 -0
  92. package/dist/lib/EventEmitter.js +27 -0
  93. package/dist/lib/EventEmitter.js.map +1 -0
  94. package/dist/lib/__PRODUCTION__.d.ts +7 -0
  95. package/dist/lib/throttle.cjs +24 -0
  96. package/dist/lib/throttle.cjs.map +1 -0
  97. package/dist/lib/throttle.d.ts +1 -0
  98. package/dist/lib/throttle.js +24 -0
  99. package/dist/lib/throttle.js.map +1 -0
  100. package/dist/types.cjs +14 -0
  101. package/dist/types.cjs.map +1 -0
  102. package/dist/types.d.ts +34 -0
  103. package/dist/types.js +16 -0
  104. package/dist/types.js.map +1 -0
  105. package/package.json +99 -0
  106. package/src/SimulatorAPI.ts +90 -0
  107. package/src/SimulatorClient.ts +96 -0
  108. package/src/channel/ChannelEmitter.ts +278 -0
  109. package/src/channel/ChannelNetwork.ts +216 -0
  110. package/src/channel/ChannelReceiver.ts +184 -0
  111. package/src/channel/errors.ts +53 -0
  112. package/src/channel/index.ts +75 -0
  113. package/src/channel/messages.ts +115 -0
  114. package/src/channel/types.ts +138 -0
  115. package/src/index.ts +42 -0
  116. package/src/kit/SimulatorManager.ts +199 -0
  117. package/src/kit/State.ts +113 -0
  118. package/src/kit/domHelpers.ts +75 -0
  119. package/src/kit/eventHandlers.ts +16 -0
  120. package/src/kit/getDefault.ts +18 -0
  121. package/src/kit/index.ts +33 -0
  122. package/src/kit/messages.ts +25 -0
  123. package/src/kit/types.ts +30 -0
  124. package/src/lib/EventEmitter.ts +41 -0
  125. package/src/lib/__PRODUCTION__.ts +12 -0
  126. package/src/lib/throttle.ts +26 -0
  127. package/src/types.ts +57 -0
@@ -0,0 +1,146 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => {
5
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+ return value;
7
+ };
8
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
+ const types = require("./types.cjs");
10
+ const errors = require("./errors.cjs");
11
+ const ChannelNetwork = require("./ChannelNetwork.cjs");
12
+ const messages = require("./messages.cjs");
13
+ const channelEmitterDefaultOptions = {
14
+ connectTimeout: 2e4,
15
+ requestIDPrefix: "emitter-"
16
+ };
17
+ class ChannelEmitter extends ChannelNetwork.ChannelNetwork {
18
+ constructor(target, requestHandlers, options) {
19
+ super(requestHandlers, { ...channelEmitterDefaultOptions, ...options });
20
+ __publicField(this, "_target");
21
+ __publicField(this, "_channel", null);
22
+ __publicField(this, "_receiverReady", "");
23
+ __publicField(this, "_receiverReadyCallback", null);
24
+ __publicField(this, "_connected", false);
25
+ this._target = target;
26
+ window.addEventListener("message", (event) => {
27
+ this._onPublicMessage(event);
28
+ });
29
+ }
30
+ get channel() {
31
+ if (!this._channel) {
32
+ throw new errors.ChannelNotSetError();
33
+ }
34
+ return this._channel;
35
+ }
36
+ set channel(channel) {
37
+ this._channel = channel;
38
+ if (this._channel) {
39
+ this.port = this._channel.port1;
40
+ } else {
41
+ this.port = null;
42
+ }
43
+ }
44
+ get connected() {
45
+ return this._connected;
46
+ }
47
+ /**
48
+ * Initiates connection to receiver
49
+ *
50
+ * @param receiverOptions - Options to configure the receiver with
51
+ * @param newOrigin - Indicates to the emitter that we're connecting to a new
52
+ * origin
53
+ *
54
+ * @returns Success connect message
55
+ */
56
+ connect(receiverOptions = {}, newOrigin = false) {
57
+ this.disconnect();
58
+ if (newOrigin) {
59
+ this._receiverReady = "";
60
+ }
61
+ return new Promise((resolve, reject) => {
62
+ this._target.addEventListener("load", () => {
63
+ if (!this._target.contentWindow) {
64
+ return reject(new Error("Target window is not available"));
65
+ }
66
+ const receiverReadyTimeout = setTimeout(() => {
67
+ reject(new errors.ConnectionTimeoutError());
68
+ }, this.options.connectTimeout);
69
+ const receiverReadyCallback = async () => {
70
+ clearTimeout(receiverReadyTimeout);
71
+ this.channel = new MessageChannel();
72
+ const request = this.createRequestMessage(types.InternalEmitterRequestType.Connect, receiverOptions);
73
+ const response = await this.postRequest(request, (request2) => {
74
+ this._target.contentWindow.postMessage(request2, "*", [
75
+ this.channel.port2
76
+ ]);
77
+ });
78
+ this.postResponse(messages.createSuccessResponseMessage(this._receiverReady, void 0), (response2) => {
79
+ this._target.contentWindow.postMessage(response2, "*");
80
+ });
81
+ this._connected = true;
82
+ resolve(response);
83
+ };
84
+ if (this._receiverReady) {
85
+ receiverReadyCallback();
86
+ } else {
87
+ this._receiverReadyCallback = receiverReadyCallback;
88
+ }
89
+ }, { once: true });
90
+ });
91
+ }
92
+ /**
93
+ * Destroys current connection to receiver if any
94
+ */
95
+ disconnect() {
96
+ this._connected = false;
97
+ this.channel = null;
98
+ }
99
+ /**
100
+ * Handles public messages
101
+ */
102
+ async _onPublicMessage(event) {
103
+ if (event.source !== this._target.contentWindow) {
104
+ return;
105
+ }
106
+ try {
107
+ const message = messages.validateMessage(event.data);
108
+ if (messages.isRequestMessage(message)) {
109
+ if (this.options.debug) {
110
+ console.debug(event.data);
111
+ }
112
+ switch (message.type) {
113
+ case types.InternalReceiverRequestType.Ready:
114
+ this._receiverReady = message.requestID;
115
+ if (this._receiverReadyCallback) {
116
+ const receiverReadyCallbackPromise = this._receiverReadyCallback();
117
+ this._receiverReadyCallback = null;
118
+ await receiverReadyCallbackPromise;
119
+ }
120
+ break;
121
+ default:
122
+ this.postResponse(messages.createErrorResponseMessage(message.requestID, void 0), (response) => {
123
+ event.source.postMessage(response, event.origin);
124
+ });
125
+ break;
126
+ }
127
+ } else {
128
+ }
129
+ } catch (error) {
130
+ if (error instanceof TypeError)
131
+ ;
132
+ else {
133
+ throw error;
134
+ }
135
+ }
136
+ }
137
+ postFormattedRequest(type, data, options = {}) {
138
+ if (!this._connected) {
139
+ throw new errors.NotReadyError("Emitter is not connected, use `ChannelEmitter.connect()` first");
140
+ }
141
+ return this.postRequest(this.createRequestMessage(type, data), void 0, options);
142
+ }
143
+ }
144
+ exports.ChannelEmitter = ChannelEmitter;
145
+ exports.channelEmitterDefaultOptions = channelEmitterDefaultOptions;
146
+ //# sourceMappingURL=ChannelEmitter.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChannelEmitter.cjs","sources":["../../../src/channel/ChannelEmitter.ts"],"sourcesContent":["import {\n\tExtractSuccessResponseMessage,\n\tInternalEmitterRequestType,\n\tInternalEmitterTransactions,\n\tInternalReceiverRequestType,\n\tSuccessResponseMessage,\n\tTransactionsHandlers,\n\tUnknownRequestMessage,\n\tUnknownResponseMessage,\n\tUnknownTransaction,\n} from \"./types\";\n\nimport {\n\tChannelNotSetError,\n\tConnectionTimeoutError,\n\tNotReadyError,\n} from \"./errors\";\n\nimport {\n\tChannelNetwork,\n\tChannelNetworkOptions,\n\tPostRequestOptions,\n} from \"./ChannelNetwork\";\nimport { AllChannelReceiverOptions } from \"./ChannelReceiver\";\nimport {\n\tcreateErrorResponseMessage,\n\tcreateSuccessResponseMessage,\n\tisRequestMessage,\n\tvalidateMessage,\n} from \"./messages\";\n\nexport type ChannelEmitterOptions = {\n\tconnectTimeout: number;\n};\n\nexport const channelEmitterDefaultOptions: ChannelEmitterOptions &\n\tPartial<ChannelNetworkOptions> = {\n\tconnectTimeout: 20000,\n\trequestIDPrefix: \"emitter-\",\n};\n\nexport type AllChannelEmitterOptions = ChannelEmitterOptions &\n\tChannelNetworkOptions;\n\nexport abstract class ChannelEmitter<\n\tTReceiverTransactions extends Record<string, UnknownTransaction> = Record<\n\t\tstring,\n\t\tnever\n\t>,\n\tTOptions extends Record<string, unknown> = Record<string, unknown>,\n\tTReceiverOptions extends Record<string, unknown> = Record<string, unknown>,\n> extends ChannelNetwork<\n\tTReceiverTransactions,\n\tChannelEmitterOptions & TOptions\n> {\n\tprivate _target: HTMLIFrameElement;\n\tprivate _channel: MessageChannel | null = null;\n\tprotected get channel(): MessageChannel {\n\t\tif (!this._channel) {\n\t\t\tthrow new ChannelNotSetError();\n\t\t}\n\n\t\treturn this._channel;\n\t}\n\tprotected set channel(channel: MessageChannel | null) {\n\t\tthis._channel = channel;\n\n\t\t// Update port automatically\n\t\tif (this._channel) {\n\t\t\tthis.port = this._channel.port1;\n\t\t} else {\n\t\t\tthis.port = null;\n\t\t}\n\t}\n\tprivate _receiverReady = \"\";\n\tprivate _receiverReadyCallback: (() => Promise<void>) | null = null;\n\tprivate _connected = false;\n\tpublic get connected(): boolean {\n\t\treturn this._connected;\n\t}\n\n\tconstructor(\n\t\ttarget: HTMLIFrameElement,\n\t\trequestHandlers: TransactionsHandlers<TReceiverTransactions>,\n\t\toptions: Partial<AllChannelEmitterOptions> & TOptions,\n\t) {\n\t\tsuper(requestHandlers, { ...channelEmitterDefaultOptions, ...options });\n\n\t\tthis._target = target;\n\n\t\twindow.addEventListener(\"message\", (event) => {\n\t\t\tthis._onPublicMessage(event);\n\t\t});\n\t}\n\n\t/**\n\t * Initiates connection to receiver\n\t *\n\t * @param receiverOptions - Options to configure the receiver with\n\t * @param newOrigin - Indicates to the emitter that we're connecting to a new\n\t * origin\n\t *\n\t * @returns Success connect message\n\t */\n\tconnect(\n\t\treceiverOptions: InternalEmitterTransactions<\n\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t>[\"connect\"][\"request\"][\"data\"] = {},\n\t\tnewOrigin = false,\n\t): Promise<SuccessResponseMessage> {\n\t\t// Disconnect first\n\t\tthis.disconnect();\n\t\t// If changing origin we'll need to wait for receiver to be ready again\n\t\tif (newOrigin) {\n\t\t\tthis._receiverReady = \"\";\n\t\t}\n\n\t\t// Handshake promise\n\t\treturn new Promise<SuccessResponseMessage>((resolve, reject) => {\n\t\t\t// Wait for target to be loaded\n\t\t\tthis._target.addEventListener(\n\t\t\t\t\"load\",\n\t\t\t\t() => {\n\t\t\t\t\t// Throw if target doesn't allow access to content window\n\t\t\t\t\tif (!this._target.contentWindow) {\n\t\t\t\t\t\treturn reject(new Error(\"Target window is not available\"));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst receiverReadyTimeout = setTimeout(() => {\n\t\t\t\t\t\treject(new ConnectionTimeoutError());\n\t\t\t\t\t}, this.options.connectTimeout);\n\n\t\t\t\t\t// Connect to target once ready\n\t\t\t\t\tconst receiverReadyCallback = async (): Promise<void> => {\n\t\t\t\t\t\t// Clear receiver ready timeout\n\t\t\t\t\t\tclearTimeout(receiverReadyTimeout);\n\n\t\t\t\t\t\t// Create new message channel (set up port automatically)\n\t\t\t\t\t\t// This is done here to prevent transferable objects neutering\n\t\t\t\t\t\t// when calling `connect()` multiple times\n\t\t\t\t\t\tthis.channel = new MessageChannel();\n\n\t\t\t\t\t\t// Conclude handshake by sending message channel port to target\n\t\t\t\t\t\tconst request = this.createRequestMessage(\n\t\t\t\t\t\t\tInternalEmitterRequestType.Connect,\n\t\t\t\t\t\t\treceiverOptions,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst response = await this.postRequest<\n\t\t\t\t\t\t\tInternalEmitterTransactions<\n\t\t\t\t\t\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t\t\t\t\t\t>[\"connect\"][\"request\"],\n\t\t\t\t\t\t\tInternalEmitterTransactions<\n\t\t\t\t\t\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t\t\t\t\t\t>[\"connect\"][\"response\"]\n\t\t\t\t\t\t>(request, (request) => {\n\t\t\t\t\t\t\t// Target content window is checked in previous statement\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\tthis._target.contentWindow!.postMessage(request, \"*\", [\n\t\t\t\t\t\t\t\tthis.channel.port2,\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Finish by aknowledging ready\n\t\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\t\tcreateSuccessResponseMessage(this._receiverReady, undefined),\n\t\t\t\t\t\t\t(response) => {\n\t\t\t\t\t\t\t\t// Target content window is checked in previous statement\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\tthis._target.contentWindow!.postMessage(response, \"*\");\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// If post request succeed, we're connected\n\t\t\t\t\t\tthis._connected = true;\n\n\t\t\t\t\t\tresolve(response);\n\t\t\t\t\t};\n\n\t\t\t\t\tif (this._receiverReady) {\n\t\t\t\t\t\t// If receiver is already ready, send port immediately\n\t\t\t\t\t\treceiverReadyCallback();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Else wait for receiver to be ready\n\t\t\t\t\t\tthis._receiverReadyCallback = receiverReadyCallback;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Destroys current connection to receiver if any\n\t */\n\tdisconnect(): void {\n\t\tthis._connected = false;\n\t\tthis.channel = null;\n\t}\n\n\t/**\n\t * Handles public messages\n\t */\n\tprivate async _onPublicMessage(event: MessageEvent<unknown>): Promise<void> {\n\t\t// Return is event is not from target\n\t\tif (event.source !== this._target.contentWindow) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst message = validateMessage(event.data);\n\n\t\t\tif (isRequestMessage(message)) {\n\t\t\t\tif (this.options.debug) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.debug(event.data);\n\t\t\t\t}\n\n\t\t\t\tswitch (message.type) {\n\t\t\t\t\tcase InternalReceiverRequestType.Ready:\n\t\t\t\t\t\tthis._receiverReady = message.requestID;\n\n\t\t\t\t\t\t// If emitter is waiting for receiver to be ready\n\t\t\t\t\t\tif (this._receiverReadyCallback) {\n\t\t\t\t\t\t\t// We don't await the promise directly as we need to clear the callback first\n\t\t\t\t\t\t\tconst receiverReadyCallbackPromise =\n\t\t\t\t\t\t\t\tthis._receiverReadyCallback();\n\n\t\t\t\t\t\t\tthis._receiverReadyCallback = null;\n\n\t\t\t\t\t\t\tawait receiverReadyCallbackPromise;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\t\tcreateErrorResponseMessage(message.requestID, undefined),\n\t\t\t\t\t\t\t(response) => {\n\t\t\t\t\t\t\t\t(event.source as WindowProxy).postMessage(\n\t\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\t\tevent.origin,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response messages are expected on public channel\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof TypeError) {\n\t\t\t\t// Ignore unknown messages\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected postFormattedRequest<\n\t\tTRequest extends UnknownRequestMessage,\n\t\tTResponse extends UnknownResponseMessage,\n\t>(\n\t\ttype: TRequest[\"type\"],\n\t\tdata?: TRequest[\"data\"],\n\t\toptions: PostRequestOptions = {},\n\t): Promise<ExtractSuccessResponseMessage<TResponse>> {\n\t\tif (!this._connected) {\n\t\t\tthrow new NotReadyError(\n\t\t\t\t\"Emitter is not connected, use `ChannelEmitter.connect()` first\",\n\t\t\t);\n\t\t}\n\n\t\treturn this.postRequest(\n\t\t\tthis.createRequestMessage(type, data),\n\t\t\tundefined,\n\t\t\toptions,\n\t\t);\n\t}\n}\n"],"names":["ChannelNetwork","ChannelNotSetError","ConnectionTimeoutError","InternalEmitterRequestType","request","createSuccessResponseMessage","response","validateMessage","isRequestMessage","InternalReceiverRequestType","createErrorResponseMessage","NotReadyError"],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import { ExtractSuccessResponseMessage, InternalEmitterTransactions, SuccessResponseMessage, TransactionsHandlers, UnknownRequestMessage, UnknownResponseMessage, UnknownTransaction } from "./types";
2
+ import { ChannelNetwork, ChannelNetworkOptions, PostRequestOptions } from "./ChannelNetwork";
3
+ import { AllChannelReceiverOptions } from "./ChannelReceiver";
4
+ export type ChannelEmitterOptions = {
5
+ connectTimeout: number;
6
+ };
7
+ export declare const channelEmitterDefaultOptions: ChannelEmitterOptions & Partial<ChannelNetworkOptions>;
8
+ export type AllChannelEmitterOptions = ChannelEmitterOptions & ChannelNetworkOptions;
9
+ export declare abstract class ChannelEmitter<TReceiverTransactions extends Record<string, UnknownTransaction> = Record<string, never>, TOptions extends Record<string, unknown> = Record<string, unknown>, TReceiverOptions extends Record<string, unknown> = Record<string, unknown>> extends ChannelNetwork<TReceiverTransactions, ChannelEmitterOptions & TOptions> {
10
+ private _target;
11
+ private _channel;
12
+ protected get channel(): MessageChannel;
13
+ protected set channel(channel: MessageChannel | null);
14
+ private _receiverReady;
15
+ private _receiverReadyCallback;
16
+ private _connected;
17
+ get connected(): boolean;
18
+ constructor(target: HTMLIFrameElement, requestHandlers: TransactionsHandlers<TReceiverTransactions>, options: Partial<AllChannelEmitterOptions> & TOptions);
19
+ /**
20
+ * Initiates connection to receiver
21
+ *
22
+ * @param receiverOptions - Options to configure the receiver with
23
+ * @param newOrigin - Indicates to the emitter that we're connecting to a new
24
+ * origin
25
+ *
26
+ * @returns Success connect message
27
+ */
28
+ connect(receiverOptions?: InternalEmitterTransactions<AllChannelReceiverOptions & TReceiverOptions>["connect"]["request"]["data"], newOrigin?: boolean): Promise<SuccessResponseMessage>;
29
+ /**
30
+ * Destroys current connection to receiver if any
31
+ */
32
+ disconnect(): void;
33
+ /**
34
+ * Handles public messages
35
+ */
36
+ private _onPublicMessage;
37
+ protected postFormattedRequest<TRequest extends UnknownRequestMessage, TResponse extends UnknownResponseMessage>(type: TRequest["type"], data?: TRequest["data"], options?: PostRequestOptions): Promise<ExtractSuccessResponseMessage<TResponse>>;
38
+ }
@@ -0,0 +1,146 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { InternalReceiverRequestType, InternalEmitterRequestType } from "./types.js";
8
+ import { ChannelNotSetError, ConnectionTimeoutError, NotReadyError } from "./errors.js";
9
+ import { ChannelNetwork } from "./ChannelNetwork.js";
10
+ import { validateMessage, isRequestMessage, createErrorResponseMessage, createSuccessResponseMessage } from "./messages.js";
11
+ const channelEmitterDefaultOptions = {
12
+ connectTimeout: 2e4,
13
+ requestIDPrefix: "emitter-"
14
+ };
15
+ class ChannelEmitter extends ChannelNetwork {
16
+ constructor(target, requestHandlers, options) {
17
+ super(requestHandlers, { ...channelEmitterDefaultOptions, ...options });
18
+ __publicField(this, "_target");
19
+ __publicField(this, "_channel", null);
20
+ __publicField(this, "_receiverReady", "");
21
+ __publicField(this, "_receiverReadyCallback", null);
22
+ __publicField(this, "_connected", false);
23
+ this._target = target;
24
+ window.addEventListener("message", (event) => {
25
+ this._onPublicMessage(event);
26
+ });
27
+ }
28
+ get channel() {
29
+ if (!this._channel) {
30
+ throw new ChannelNotSetError();
31
+ }
32
+ return this._channel;
33
+ }
34
+ set channel(channel) {
35
+ this._channel = channel;
36
+ if (this._channel) {
37
+ this.port = this._channel.port1;
38
+ } else {
39
+ this.port = null;
40
+ }
41
+ }
42
+ get connected() {
43
+ return this._connected;
44
+ }
45
+ /**
46
+ * Initiates connection to receiver
47
+ *
48
+ * @param receiverOptions - Options to configure the receiver with
49
+ * @param newOrigin - Indicates to the emitter that we're connecting to a new
50
+ * origin
51
+ *
52
+ * @returns Success connect message
53
+ */
54
+ connect(receiverOptions = {}, newOrigin = false) {
55
+ this.disconnect();
56
+ if (newOrigin) {
57
+ this._receiverReady = "";
58
+ }
59
+ return new Promise((resolve, reject) => {
60
+ this._target.addEventListener("load", () => {
61
+ if (!this._target.contentWindow) {
62
+ return reject(new Error("Target window is not available"));
63
+ }
64
+ const receiverReadyTimeout = setTimeout(() => {
65
+ reject(new ConnectionTimeoutError());
66
+ }, this.options.connectTimeout);
67
+ const receiverReadyCallback = async () => {
68
+ clearTimeout(receiverReadyTimeout);
69
+ this.channel = new MessageChannel();
70
+ const request = this.createRequestMessage(InternalEmitterRequestType.Connect, receiverOptions);
71
+ const response = await this.postRequest(request, (request2) => {
72
+ this._target.contentWindow.postMessage(request2, "*", [
73
+ this.channel.port2
74
+ ]);
75
+ });
76
+ this.postResponse(createSuccessResponseMessage(this._receiverReady, void 0), (response2) => {
77
+ this._target.contentWindow.postMessage(response2, "*");
78
+ });
79
+ this._connected = true;
80
+ resolve(response);
81
+ };
82
+ if (this._receiverReady) {
83
+ receiverReadyCallback();
84
+ } else {
85
+ this._receiverReadyCallback = receiverReadyCallback;
86
+ }
87
+ }, { once: true });
88
+ });
89
+ }
90
+ /**
91
+ * Destroys current connection to receiver if any
92
+ */
93
+ disconnect() {
94
+ this._connected = false;
95
+ this.channel = null;
96
+ }
97
+ /**
98
+ * Handles public messages
99
+ */
100
+ async _onPublicMessage(event) {
101
+ if (event.source !== this._target.contentWindow) {
102
+ return;
103
+ }
104
+ try {
105
+ const message = validateMessage(event.data);
106
+ if (isRequestMessage(message)) {
107
+ if (this.options.debug) {
108
+ console.debug(event.data);
109
+ }
110
+ switch (message.type) {
111
+ case InternalReceiverRequestType.Ready:
112
+ this._receiverReady = message.requestID;
113
+ if (this._receiverReadyCallback) {
114
+ const receiverReadyCallbackPromise = this._receiverReadyCallback();
115
+ this._receiverReadyCallback = null;
116
+ await receiverReadyCallbackPromise;
117
+ }
118
+ break;
119
+ default:
120
+ this.postResponse(createErrorResponseMessage(message.requestID, void 0), (response) => {
121
+ event.source.postMessage(response, event.origin);
122
+ });
123
+ break;
124
+ }
125
+ } else {
126
+ }
127
+ } catch (error) {
128
+ if (error instanceof TypeError)
129
+ ;
130
+ else {
131
+ throw error;
132
+ }
133
+ }
134
+ }
135
+ postFormattedRequest(type, data, options = {}) {
136
+ if (!this._connected) {
137
+ throw new NotReadyError("Emitter is not connected, use `ChannelEmitter.connect()` first");
138
+ }
139
+ return this.postRequest(this.createRequestMessage(type, data), void 0, options);
140
+ }
141
+ }
142
+ export {
143
+ ChannelEmitter,
144
+ channelEmitterDefaultOptions
145
+ };
146
+ //# sourceMappingURL=ChannelEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChannelEmitter.js","sources":["../../../src/channel/ChannelEmitter.ts"],"sourcesContent":["import {\n\tExtractSuccessResponseMessage,\n\tInternalEmitterRequestType,\n\tInternalEmitterTransactions,\n\tInternalReceiverRequestType,\n\tSuccessResponseMessage,\n\tTransactionsHandlers,\n\tUnknownRequestMessage,\n\tUnknownResponseMessage,\n\tUnknownTransaction,\n} from \"./types\";\n\nimport {\n\tChannelNotSetError,\n\tConnectionTimeoutError,\n\tNotReadyError,\n} from \"./errors\";\n\nimport {\n\tChannelNetwork,\n\tChannelNetworkOptions,\n\tPostRequestOptions,\n} from \"./ChannelNetwork\";\nimport { AllChannelReceiverOptions } from \"./ChannelReceiver\";\nimport {\n\tcreateErrorResponseMessage,\n\tcreateSuccessResponseMessage,\n\tisRequestMessage,\n\tvalidateMessage,\n} from \"./messages\";\n\nexport type ChannelEmitterOptions = {\n\tconnectTimeout: number;\n};\n\nexport const channelEmitterDefaultOptions: ChannelEmitterOptions &\n\tPartial<ChannelNetworkOptions> = {\n\tconnectTimeout: 20000,\n\trequestIDPrefix: \"emitter-\",\n};\n\nexport type AllChannelEmitterOptions = ChannelEmitterOptions &\n\tChannelNetworkOptions;\n\nexport abstract class ChannelEmitter<\n\tTReceiverTransactions extends Record<string, UnknownTransaction> = Record<\n\t\tstring,\n\t\tnever\n\t>,\n\tTOptions extends Record<string, unknown> = Record<string, unknown>,\n\tTReceiverOptions extends Record<string, unknown> = Record<string, unknown>,\n> extends ChannelNetwork<\n\tTReceiverTransactions,\n\tChannelEmitterOptions & TOptions\n> {\n\tprivate _target: HTMLIFrameElement;\n\tprivate _channel: MessageChannel | null = null;\n\tprotected get channel(): MessageChannel {\n\t\tif (!this._channel) {\n\t\t\tthrow new ChannelNotSetError();\n\t\t}\n\n\t\treturn this._channel;\n\t}\n\tprotected set channel(channel: MessageChannel | null) {\n\t\tthis._channel = channel;\n\n\t\t// Update port automatically\n\t\tif (this._channel) {\n\t\t\tthis.port = this._channel.port1;\n\t\t} else {\n\t\t\tthis.port = null;\n\t\t}\n\t}\n\tprivate _receiverReady = \"\";\n\tprivate _receiverReadyCallback: (() => Promise<void>) | null = null;\n\tprivate _connected = false;\n\tpublic get connected(): boolean {\n\t\treturn this._connected;\n\t}\n\n\tconstructor(\n\t\ttarget: HTMLIFrameElement,\n\t\trequestHandlers: TransactionsHandlers<TReceiverTransactions>,\n\t\toptions: Partial<AllChannelEmitterOptions> & TOptions,\n\t) {\n\t\tsuper(requestHandlers, { ...channelEmitterDefaultOptions, ...options });\n\n\t\tthis._target = target;\n\n\t\twindow.addEventListener(\"message\", (event) => {\n\t\t\tthis._onPublicMessage(event);\n\t\t});\n\t}\n\n\t/**\n\t * Initiates connection to receiver\n\t *\n\t * @param receiverOptions - Options to configure the receiver with\n\t * @param newOrigin - Indicates to the emitter that we're connecting to a new\n\t * origin\n\t *\n\t * @returns Success connect message\n\t */\n\tconnect(\n\t\treceiverOptions: InternalEmitterTransactions<\n\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t>[\"connect\"][\"request\"][\"data\"] = {},\n\t\tnewOrigin = false,\n\t): Promise<SuccessResponseMessage> {\n\t\t// Disconnect first\n\t\tthis.disconnect();\n\t\t// If changing origin we'll need to wait for receiver to be ready again\n\t\tif (newOrigin) {\n\t\t\tthis._receiverReady = \"\";\n\t\t}\n\n\t\t// Handshake promise\n\t\treturn new Promise<SuccessResponseMessage>((resolve, reject) => {\n\t\t\t// Wait for target to be loaded\n\t\t\tthis._target.addEventListener(\n\t\t\t\t\"load\",\n\t\t\t\t() => {\n\t\t\t\t\t// Throw if target doesn't allow access to content window\n\t\t\t\t\tif (!this._target.contentWindow) {\n\t\t\t\t\t\treturn reject(new Error(\"Target window is not available\"));\n\t\t\t\t\t}\n\n\t\t\t\t\tconst receiverReadyTimeout = setTimeout(() => {\n\t\t\t\t\t\treject(new ConnectionTimeoutError());\n\t\t\t\t\t}, this.options.connectTimeout);\n\n\t\t\t\t\t// Connect to target once ready\n\t\t\t\t\tconst receiverReadyCallback = async (): Promise<void> => {\n\t\t\t\t\t\t// Clear receiver ready timeout\n\t\t\t\t\t\tclearTimeout(receiverReadyTimeout);\n\n\t\t\t\t\t\t// Create new message channel (set up port automatically)\n\t\t\t\t\t\t// This is done here to prevent transferable objects neutering\n\t\t\t\t\t\t// when calling `connect()` multiple times\n\t\t\t\t\t\tthis.channel = new MessageChannel();\n\n\t\t\t\t\t\t// Conclude handshake by sending message channel port to target\n\t\t\t\t\t\tconst request = this.createRequestMessage(\n\t\t\t\t\t\t\tInternalEmitterRequestType.Connect,\n\t\t\t\t\t\t\treceiverOptions,\n\t\t\t\t\t\t);\n\t\t\t\t\t\tconst response = await this.postRequest<\n\t\t\t\t\t\t\tInternalEmitterTransactions<\n\t\t\t\t\t\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t\t\t\t\t\t>[\"connect\"][\"request\"],\n\t\t\t\t\t\t\tInternalEmitterTransactions<\n\t\t\t\t\t\t\t\tAllChannelReceiverOptions & TReceiverOptions\n\t\t\t\t\t\t\t>[\"connect\"][\"response\"]\n\t\t\t\t\t\t>(request, (request) => {\n\t\t\t\t\t\t\t// Target content window is checked in previous statement\n\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\tthis._target.contentWindow!.postMessage(request, \"*\", [\n\t\t\t\t\t\t\t\tthis.channel.port2,\n\t\t\t\t\t\t\t]);\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\t// Finish by aknowledging ready\n\t\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\t\tcreateSuccessResponseMessage(this._receiverReady, undefined),\n\t\t\t\t\t\t\t(response) => {\n\t\t\t\t\t\t\t\t// Target content window is checked in previous statement\n\t\t\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\t\t\t\tthis._target.contentWindow!.postMessage(response, \"*\");\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\n\t\t\t\t\t\t// If post request succeed, we're connected\n\t\t\t\t\t\tthis._connected = true;\n\n\t\t\t\t\t\tresolve(response);\n\t\t\t\t\t};\n\n\t\t\t\t\tif (this._receiverReady) {\n\t\t\t\t\t\t// If receiver is already ready, send port immediately\n\t\t\t\t\t\treceiverReadyCallback();\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Else wait for receiver to be ready\n\t\t\t\t\t\tthis._receiverReadyCallback = receiverReadyCallback;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\t{ once: true },\n\t\t\t);\n\t\t});\n\t}\n\n\t/**\n\t * Destroys current connection to receiver if any\n\t */\n\tdisconnect(): void {\n\t\tthis._connected = false;\n\t\tthis.channel = null;\n\t}\n\n\t/**\n\t * Handles public messages\n\t */\n\tprivate async _onPublicMessage(event: MessageEvent<unknown>): Promise<void> {\n\t\t// Return is event is not from target\n\t\tif (event.source !== this._target.contentWindow) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst message = validateMessage(event.data);\n\n\t\t\tif (isRequestMessage(message)) {\n\t\t\t\tif (this.options.debug) {\n\t\t\t\t\t// eslint-disable-next-line no-console\n\t\t\t\t\tconsole.debug(event.data);\n\t\t\t\t}\n\n\t\t\t\tswitch (message.type) {\n\t\t\t\t\tcase InternalReceiverRequestType.Ready:\n\t\t\t\t\t\tthis._receiverReady = message.requestID;\n\n\t\t\t\t\t\t// If emitter is waiting for receiver to be ready\n\t\t\t\t\t\tif (this._receiverReadyCallback) {\n\t\t\t\t\t\t\t// We don't await the promise directly as we need to clear the callback first\n\t\t\t\t\t\t\tconst receiverReadyCallbackPromise =\n\t\t\t\t\t\t\t\tthis._receiverReadyCallback();\n\n\t\t\t\t\t\t\tthis._receiverReadyCallback = null;\n\n\t\t\t\t\t\t\tawait receiverReadyCallbackPromise;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\t\tcreateErrorResponseMessage(message.requestID, undefined),\n\t\t\t\t\t\t\t(response) => {\n\t\t\t\t\t\t\t\t(event.source as WindowProxy).postMessage(\n\t\t\t\t\t\t\t\t\tresponse,\n\t\t\t\t\t\t\t\t\tevent.origin,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// No response messages are expected on public channel\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof TypeError) {\n\t\t\t\t// Ignore unknown messages\n\t\t\t} else {\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected postFormattedRequest<\n\t\tTRequest extends UnknownRequestMessage,\n\t\tTResponse extends UnknownResponseMessage,\n\t>(\n\t\ttype: TRequest[\"type\"],\n\t\tdata?: TRequest[\"data\"],\n\t\toptions: PostRequestOptions = {},\n\t): Promise<ExtractSuccessResponseMessage<TResponse>> {\n\t\tif (!this._connected) {\n\t\t\tthrow new NotReadyError(\n\t\t\t\t\"Emitter is not connected, use `ChannelEmitter.connect()` first\",\n\t\t\t);\n\t\t}\n\n\t\treturn this.postRequest(\n\t\t\tthis.createRequestMessage(type, data),\n\t\t\tundefined,\n\t\t\toptions,\n\t\t);\n\t}\n}\n"],"names":["request","response"],"mappings":"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"}
@@ -0,0 +1,112 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
+ var __publicField = (obj, key, value) => {
5
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
6
+ return value;
7
+ };
8
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
9
+ const errors = require("./errors.cjs");
10
+ const messages = require("./messages.cjs");
11
+ const channelNetworkDefaultOptions = {
12
+ debug: false,
13
+ maximumRequestConcurrency: 20,
14
+ defaultTimeout: 5e3,
15
+ requestIDPrefix: "channel-"
16
+ };
17
+ class ChannelNetwork {
18
+ constructor(requestHandlers, options) {
19
+ __publicField(this, "requestHandlers");
20
+ __publicField(this, "options");
21
+ __publicField(this, "_port", null);
22
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
23
+ __publicField(this, "_pendingRequests", /* @__PURE__ */ new Map());
24
+ this.requestHandlers = requestHandlers;
25
+ this.options = { ...channelNetworkDefaultOptions, ...options };
26
+ }
27
+ get port() {
28
+ if (!this._port) {
29
+ throw new errors.PortNotSetError();
30
+ }
31
+ return this._port;
32
+ }
33
+ set port(port) {
34
+ if (this._port) {
35
+ this._port.onmessage = null;
36
+ }
37
+ this._port = port;
38
+ if (this._port) {
39
+ this._port.onmessage = this.onMessage.bind(this);
40
+ }
41
+ }
42
+ createRequestMessage(type, data) {
43
+ return messages.createRequestMessage(type, data, this.options.requestIDPrefix);
44
+ }
45
+ async onMessage(event) {
46
+ if (this.options.debug) {
47
+ console.debug(event.data);
48
+ }
49
+ try {
50
+ const message = messages.validateMessage(event.data);
51
+ if (messages.isRequestMessage(message)) {
52
+ if (!this.requestHandlers[message.type]) {
53
+ this.postResponse(messages.createErrorResponseMessage(message.requestID, void 0, 501));
54
+ } else {
55
+ try {
56
+ const response = await this.requestHandlers[message.type](message, {
57
+ success: messages.createSuccessResponseMessage.bind(this, message.requestID),
58
+ error: messages.createErrorResponseMessage.bind(this, message.requestID)
59
+ });
60
+ this.postResponse(response);
61
+ } catch (error) {
62
+ this.postResponse(messages.createErrorResponseMessage(message.requestID, error, 500));
63
+ }
64
+ }
65
+ } else {
66
+ if (!this._pendingRequests.has(message.requestID)) {
67
+ console.error(`Unknown request ID received in response: ${JSON.stringify(message)}`);
68
+ } else {
69
+ this._pendingRequests.get(message.requestID)(message);
70
+ this._pendingRequests.delete(message.requestID);
71
+ }
72
+ }
73
+ } catch (error) {
74
+ if (error instanceof TypeError) {
75
+ console.warn(error.message);
76
+ } else {
77
+ throw error;
78
+ }
79
+ }
80
+ }
81
+ postRequest(request, postMessage = (request2) => this.port.postMessage(request2), options = {}) {
82
+ if (this.options.debug) {
83
+ console.debug(request);
84
+ }
85
+ if (this._pendingRequests.size >= this.options.maximumRequestConcurrency) {
86
+ throw new errors.TooManyConcurrentRequestsError(request);
87
+ }
88
+ return new Promise((resolve, reject) => {
89
+ const requestTimeout = setTimeout(() => {
90
+ if (this._pendingRequests.has(request.requestID)) {
91
+ this._pendingRequests.delete(request.requestID);
92
+ }
93
+ reject(new errors.RequestTimeoutError(request));
94
+ }, options.timeout || this.options.defaultTimeout);
95
+ this._pendingRequests.set(request.requestID, (response) => {
96
+ clearTimeout(requestTimeout);
97
+ messages.isSuccessResponseMessage(response) ? resolve(response) : reject(new errors.ResponseError(response));
98
+ });
99
+ postMessage(request);
100
+ });
101
+ }
102
+ postResponse(response, postMessage = (response2) => this.port.postMessage(response2)) {
103
+ if (this.options.debug) {
104
+ console.debug(response);
105
+ }
106
+ postMessage(response);
107
+ return response;
108
+ }
109
+ }
110
+ exports.ChannelNetwork = ChannelNetwork;
111
+ exports.channelNetworkDefaultOptions = channelNetworkDefaultOptions;
112
+ //# sourceMappingURL=ChannelNetwork.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChannelNetwork.cjs","sources":["../../../src/channel/ChannelNetwork.ts"],"sourcesContent":["import {\n\tExtractErrorResponseMessage,\n\tExtractSuccessResponseMessage,\n\tRequestMessage,\n\tTransactionsHandlers,\n\tUnknownRequestMessage,\n\tUnknownResponseMessage,\n\tUnknownTransaction,\n} from \"./types\";\n\nimport {\n\tPortNotSetError,\n\tRequestTimeoutError,\n\tResponseError,\n\tTooManyConcurrentRequestsError,\n} from \"./errors\";\n\nimport {\n\tcreateErrorResponseMessage,\n\tcreateRequestMessage,\n\tcreateSuccessResponseMessage,\n\tisRequestMessage,\n\tisSuccessResponseMessage,\n\tvalidateMessage,\n} from \"./messages\";\n\nexport type PostRequestOptions = {\n\ttimeout?: number;\n};\n\nexport type ChannelNetworkOptions = {\n\tdebug: boolean;\n\tmaximumRequestConcurrency: number;\n\tdefaultTimeout: number;\n\trequestIDPrefix: string;\n};\n\nexport const channelNetworkDefaultOptions: ChannelNetworkOptions = {\n\tdebug: false,\n\tmaximumRequestConcurrency: 20,\n\tdefaultTimeout: 5000,\n\trequestIDPrefix: \"channel-\",\n};\n\nexport abstract class ChannelNetwork<\n\tTPartnerTransactions extends Record<string, UnknownTransaction> = Record<\n\t\tstring,\n\t\tnever\n\t>,\n\tTOptions extends Record<string, unknown> = Record<string, unknown>,\n> {\n\tpublic requestHandlers: TransactionsHandlers<TPartnerTransactions>;\n\tpublic options: ChannelNetworkOptions & TOptions;\n\n\tprivate _port: MessagePort | null = null;\n\tprotected get port(): MessagePort {\n\t\tif (!this._port) {\n\t\t\tthrow new PortNotSetError();\n\t\t}\n\n\t\treturn this._port;\n\t}\n\tprotected set port(port: MessagePort | null) {\n\t\t// Destroy old port\n\t\tif (this._port) {\n\t\t\tthis._port.onmessage = null;\n\t\t}\n\n\t\tthis._port = port;\n\t\tif (this._port) {\n\t\t\tthis._port.onmessage = this.onMessage.bind(this);\n\t\t}\n\t}\n\n\t// eslint-disable-next-line @typescript-eslint/no-explicit-any\n\tprivate _pendingRequests: Map<string, (response: any) => void> = new Map();\n\n\tconstructor(\n\t\trequestHandlers: TransactionsHandlers<TPartnerTransactions>,\n\t\toptions: Partial<ChannelNetworkOptions> & TOptions,\n\t) {\n\t\tthis.requestHandlers = requestHandlers;\n\t\tthis.options = { ...channelNetworkDefaultOptions, ...options };\n\t}\n\n\tpublic createRequestMessage<TType extends string = string, TData = undefined>(\n\t\ttype: TType,\n\t\tdata: TData,\n\t): RequestMessage<TType, TData> {\n\t\treturn createRequestMessage(type, data, this.options.requestIDPrefix);\n\t}\n\n\tprotected async onMessage(event: MessageEvent<unknown>): Promise<void> {\n\t\tif (this.options.debug) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(event.data);\n\t\t}\n\n\t\ttry {\n\t\t\tconst message = validateMessage(event.data);\n\n\t\t\tif (isRequestMessage(message)) {\n\t\t\t\tif (!this.requestHandlers[message.type]) {\n\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\tcreateErrorResponseMessage(message.requestID, undefined, 501),\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\ttry {\n\t\t\t\t\t\t// TODO: Figure out why type cannot be inferred on its own anymore\n\t\t\t\t\t\tconst response = await this.requestHandlers[message.type](message, {\n\t\t\t\t\t\t\tsuccess: createSuccessResponseMessage.bind(\n\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\tmessage.requestID,\n\t\t\t\t\t\t\t) as Parameters<\n\t\t\t\t\t\t\t\t(typeof this.requestHandlers)[string]\n\t\t\t\t\t\t\t>[1][\"success\"],\n\t\t\t\t\t\t\terror: createErrorResponseMessage.bind(\n\t\t\t\t\t\t\t\tthis,\n\t\t\t\t\t\t\t\tmessage.requestID,\n\t\t\t\t\t\t\t) as Parameters<\n\t\t\t\t\t\t\t\t(typeof this.requestHandlers)[string]\n\t\t\t\t\t\t\t>[1][\"error\"],\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tthis.postResponse(response);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tthis.postResponse(\n\t\t\t\t\t\t\tcreateErrorResponseMessage(message.requestID, error, 500),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (!this._pendingRequests.has(message.requestID)) {\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t`Unknown request ID received in response: ${JSON.stringify(\n\t\t\t\t\t\t\tmessage,\n\t\t\t\t\t\t)}`,\n\t\t\t\t\t);\n\t\t\t\t} else {\n\t\t\t\t\t// Pending requests are checked in previous statement\n\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n\t\t\t\t\tthis._pendingRequests.get(message.requestID)!(message);\n\t\t\t\t\tthis._pendingRequests.delete(message.requestID);\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tif (error instanceof TypeError) {\n\t\t\t\tconsole.warn(error.message);\n\t\t\t} else {\n\t\t\t\t// Should not be possible, but who knows :shrug:\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t}\n\n\tprotected postRequest<\n\t\tTRequest extends UnknownRequestMessage,\n\t\tTResponse extends UnknownResponseMessage,\n\t>(\n\t\trequest: TRequest,\n\t\tpostMessage = (request: TRequest): void => this.port.postMessage(request),\n\t\toptions: PostRequestOptions = {},\n\t): Promise<ExtractSuccessResponseMessage<TResponse>> {\n\t\tif (this.options.debug) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(request);\n\t\t}\n\n\t\tif (this._pendingRequests.size >= this.options.maximumRequestConcurrency) {\n\t\t\tthrow new TooManyConcurrentRequestsError(request);\n\t\t}\n\n\t\treturn new Promise<ExtractSuccessResponseMessage<TResponse>>(\n\t\t\t(resolve, reject) => {\n\t\t\t\tconst requestTimeout = setTimeout(() => {\n\t\t\t\t\tif (this._pendingRequests.has(request.requestID)) {\n\t\t\t\t\t\tthis._pendingRequests.delete(request.requestID);\n\t\t\t\t\t}\n\t\t\t\t\treject(new RequestTimeoutError(request));\n\t\t\t\t}, options.timeout || this.options.defaultTimeout);\n\n\t\t\t\tthis._pendingRequests.set(\n\t\t\t\t\trequest.requestID,\n\t\t\t\t\t(response: TResponse): void => {\n\t\t\t\t\t\tclearTimeout(requestTimeout);\n\n\t\t\t\t\t\tisSuccessResponseMessage(response)\n\t\t\t\t\t\t\t? resolve(response as ExtractSuccessResponseMessage<TResponse>)\n\t\t\t\t\t\t\t: reject(\n\t\t\t\t\t\t\t\t\tnew ResponseError(\n\t\t\t\t\t\t\t\t\t\tresponse as ExtractErrorResponseMessage<TResponse>,\n\t\t\t\t\t\t\t\t\t),\n\t\t\t\t\t\t\t );\n\t\t\t\t\t},\n\t\t\t\t);\n\n\t\t\t\tpostMessage(request);\n\t\t\t},\n\t\t);\n\t}\n\n\tprotected postResponse<TResponse extends UnknownResponseMessage>(\n\t\tresponse: TResponse,\n\t\tpostMessage = (response: TResponse): void =>\n\t\t\tthis.port.postMessage(response),\n\t): TResponse {\n\t\tif (this.options.debug) {\n\t\t\t// eslint-disable-next-line no-console\n\t\t\tconsole.debug(response);\n\t\t}\n\n\t\tpostMessage(response);\n\n\t\treturn response;\n\t}\n}\n"],"names":["PortNotSetError","createRequestMessage","validateMessage","isRequestMessage","createErrorResponseMessage","createSuccessResponseMessage","request","TooManyConcurrentRequestsError","RequestTimeoutError","isSuccessResponseMessage","ResponseError","response"],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import { ExtractSuccessResponseMessage, RequestMessage, TransactionsHandlers, UnknownRequestMessage, UnknownResponseMessage, UnknownTransaction } from "./types";
2
+ export type PostRequestOptions = {
3
+ timeout?: number;
4
+ };
5
+ export type ChannelNetworkOptions = {
6
+ debug: boolean;
7
+ maximumRequestConcurrency: number;
8
+ defaultTimeout: number;
9
+ requestIDPrefix: string;
10
+ };
11
+ export declare const channelNetworkDefaultOptions: ChannelNetworkOptions;
12
+ export declare abstract class ChannelNetwork<TPartnerTransactions extends Record<string, UnknownTransaction> = Record<string, never>, TOptions extends Record<string, unknown> = Record<string, unknown>> {
13
+ requestHandlers: TransactionsHandlers<TPartnerTransactions>;
14
+ options: ChannelNetworkOptions & TOptions;
15
+ private _port;
16
+ protected get port(): MessagePort;
17
+ protected set port(port: MessagePort | null);
18
+ private _pendingRequests;
19
+ constructor(requestHandlers: TransactionsHandlers<TPartnerTransactions>, options: Partial<ChannelNetworkOptions> & TOptions);
20
+ createRequestMessage<TType extends string = string, TData = undefined>(type: TType, data: TData): RequestMessage<TType, TData>;
21
+ protected onMessage(event: MessageEvent<unknown>): Promise<void>;
22
+ protected postRequest<TRequest extends UnknownRequestMessage, TResponse extends UnknownResponseMessage>(request: TRequest, postMessage?: (request: TRequest) => void, options?: PostRequestOptions): Promise<ExtractSuccessResponseMessage<TResponse>>;
23
+ protected postResponse<TResponse extends UnknownResponseMessage>(response: TResponse, postMessage?: (response: TResponse) => void): TResponse;
24
+ }
@@ -0,0 +1,112 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ import { PortNotSetError, TooManyConcurrentRequestsError, RequestTimeoutError, ResponseError } from "./errors.js";
8
+ import { createRequestMessage, validateMessage, isRequestMessage, createErrorResponseMessage, createSuccessResponseMessage, isSuccessResponseMessage } from "./messages.js";
9
+ const channelNetworkDefaultOptions = {
10
+ debug: false,
11
+ maximumRequestConcurrency: 20,
12
+ defaultTimeout: 5e3,
13
+ requestIDPrefix: "channel-"
14
+ };
15
+ class ChannelNetwork {
16
+ constructor(requestHandlers, options) {
17
+ __publicField(this, "requestHandlers");
18
+ __publicField(this, "options");
19
+ __publicField(this, "_port", null);
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ __publicField(this, "_pendingRequests", /* @__PURE__ */ new Map());
22
+ this.requestHandlers = requestHandlers;
23
+ this.options = { ...channelNetworkDefaultOptions, ...options };
24
+ }
25
+ get port() {
26
+ if (!this._port) {
27
+ throw new PortNotSetError();
28
+ }
29
+ return this._port;
30
+ }
31
+ set port(port) {
32
+ if (this._port) {
33
+ this._port.onmessage = null;
34
+ }
35
+ this._port = port;
36
+ if (this._port) {
37
+ this._port.onmessage = this.onMessage.bind(this);
38
+ }
39
+ }
40
+ createRequestMessage(type, data) {
41
+ return createRequestMessage(type, data, this.options.requestIDPrefix);
42
+ }
43
+ async onMessage(event) {
44
+ if (this.options.debug) {
45
+ console.debug(event.data);
46
+ }
47
+ try {
48
+ const message = validateMessage(event.data);
49
+ if (isRequestMessage(message)) {
50
+ if (!this.requestHandlers[message.type]) {
51
+ this.postResponse(createErrorResponseMessage(message.requestID, void 0, 501));
52
+ } else {
53
+ try {
54
+ const response = await this.requestHandlers[message.type](message, {
55
+ success: createSuccessResponseMessage.bind(this, message.requestID),
56
+ error: createErrorResponseMessage.bind(this, message.requestID)
57
+ });
58
+ this.postResponse(response);
59
+ } catch (error) {
60
+ this.postResponse(createErrorResponseMessage(message.requestID, error, 500));
61
+ }
62
+ }
63
+ } else {
64
+ if (!this._pendingRequests.has(message.requestID)) {
65
+ console.error(`Unknown request ID received in response: ${JSON.stringify(message)}`);
66
+ } else {
67
+ this._pendingRequests.get(message.requestID)(message);
68
+ this._pendingRequests.delete(message.requestID);
69
+ }
70
+ }
71
+ } catch (error) {
72
+ if (error instanceof TypeError) {
73
+ console.warn(error.message);
74
+ } else {
75
+ throw error;
76
+ }
77
+ }
78
+ }
79
+ postRequest(request, postMessage = (request2) => this.port.postMessage(request2), options = {}) {
80
+ if (this.options.debug) {
81
+ console.debug(request);
82
+ }
83
+ if (this._pendingRequests.size >= this.options.maximumRequestConcurrency) {
84
+ throw new TooManyConcurrentRequestsError(request);
85
+ }
86
+ return new Promise((resolve, reject) => {
87
+ const requestTimeout = setTimeout(() => {
88
+ if (this._pendingRequests.has(request.requestID)) {
89
+ this._pendingRequests.delete(request.requestID);
90
+ }
91
+ reject(new RequestTimeoutError(request));
92
+ }, options.timeout || this.options.defaultTimeout);
93
+ this._pendingRequests.set(request.requestID, (response) => {
94
+ clearTimeout(requestTimeout);
95
+ isSuccessResponseMessage(response) ? resolve(response) : reject(new ResponseError(response));
96
+ });
97
+ postMessage(request);
98
+ });
99
+ }
100
+ postResponse(response, postMessage = (response2) => this.port.postMessage(response2)) {
101
+ if (this.options.debug) {
102
+ console.debug(response);
103
+ }
104
+ postMessage(response);
105
+ return response;
106
+ }
107
+ }
108
+ export {
109
+ ChannelNetwork,
110
+ channelNetworkDefaultOptions
111
+ };
112
+ //# sourceMappingURL=ChannelNetwork.js.map