penpal 7.0.0-beta.2 → 7.0.0-beta.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 (57) hide show
  1. package/README.md +28 -20
  2. package/cjs/CallOptions.d.ts +1 -2
  3. package/cjs/CallOptions.js +2 -1
  4. package/cjs/ErrorCodeObj.d.ts +9 -0
  5. package/cjs/ErrorCodeObj.js +14 -0
  6. package/cjs/PenpalError.d.ts +1 -1
  7. package/cjs/Reply.d.ts +1 -2
  8. package/cjs/Reply.js +2 -1
  9. package/cjs/backwardCompatibility.js +5 -6
  10. package/cjs/connect.js +3 -4
  11. package/cjs/connectCallHandler.js +4 -5
  12. package/cjs/connectRemoteProxy.js +26 -17
  13. package/cjs/guards.js +6 -7
  14. package/cjs/index.d.ts +1 -1
  15. package/cjs/index.js +3 -3
  16. package/cjs/indexForBundle.d.ts +8 -2
  17. package/cjs/indexForBundle.js +2 -2
  18. package/cjs/messengers/PortMessenger.d.ts +1 -4
  19. package/cjs/messengers/PortMessenger.js +22 -23
  20. package/cjs/messengers/WindowMessenger.d.ts +1 -13
  21. package/cjs/messengers/WindowMessenger.js +103 -104
  22. package/cjs/messengers/WorkerMessenger.d.ts +1 -6
  23. package/cjs/messengers/WorkerMessenger.js +46 -47
  24. package/cjs/shakeHands.js +7 -8
  25. package/cjs/types.d.ts +8 -7
  26. package/dist/penpal.js +238 -237
  27. package/dist/penpal.min.js +1 -1
  28. package/dist/penpal.min.js.map +1 -1
  29. package/lib/CallOptions.d.ts +1 -2
  30. package/lib/CallOptions.js +2 -1
  31. package/lib/ErrorCodeObj.d.ts +9 -0
  32. package/lib/ErrorCodeObj.js +12 -0
  33. package/lib/PenpalError.d.ts +1 -1
  34. package/lib/Reply.d.ts +1 -2
  35. package/lib/Reply.js +2 -1
  36. package/lib/backwardCompatibility.js +5 -6
  37. package/lib/connect.js +3 -4
  38. package/lib/connectCallHandler.js +4 -5
  39. package/lib/connectRemoteProxy.js +27 -18
  40. package/lib/guards.js +6 -7
  41. package/lib/index.d.ts +1 -1
  42. package/lib/index.js +1 -1
  43. package/lib/indexForBundle.d.ts +8 -2
  44. package/lib/indexForBundle.js +1 -1
  45. package/lib/messengers/PortMessenger.d.ts +1 -4
  46. package/lib/messengers/PortMessenger.js +22 -23
  47. package/lib/messengers/WindowMessenger.d.ts +1 -13
  48. package/lib/messengers/WindowMessenger.js +103 -104
  49. package/lib/messengers/WorkerMessenger.d.ts +1 -6
  50. package/lib/messengers/WorkerMessenger.js +46 -47
  51. package/lib/shakeHands.js +7 -8
  52. package/lib/types.d.ts +8 -7
  53. package/package.json +3 -2
  54. package/cjs/enums.d.ts +0 -19
  55. package/cjs/enums.js +0 -25
  56. package/lib/enums.d.ts +0 -19
  57. package/lib/enums.js +0 -22
package/README.md CHANGED
@@ -27,13 +27,13 @@
27
27
 
28
28
  Install Penpal from npm as follows:
29
29
 
30
- `npm install penpal`
30
+ `npm install penpal@next`
31
31
 
32
32
  ### Using a CDN
33
33
 
34
34
  Alternatively, load a build of Penpal that is already hosted on a CDN:
35
35
 
36
- `<script src="https://unpkg.com/penpal@^7/dist/penpal.min.js"></script>`
36
+ `<script src="https://unpkg.com/penpal@next/dist/penpal.min.js"></script>`
37
37
 
38
38
  Penpal will then be installed on `window.Penpal`. Usage is similar to if you were using it from npm, which is documented below, but instead of importing each module, you would access it on the `Penpal` global variable instead.
39
39
 
@@ -267,7 +267,7 @@ console.log(additionResult); // 8
267
267
  ### Window
268
268
 
269
269
  ```javascript
270
- import { WorkerMessenger, connect } from 'penpal';
270
+ import { PortMessenger, connect } from 'penpal';
271
271
 
272
272
  const worker = new SharedWorker('shared-worker.js');
273
273
 
@@ -345,6 +345,16 @@ import { PortMessenger, connect } from 'penpal';
345
345
  const initPenpal = async () => {
346
346
  const { port1, port2 } = new MessageChannel();
347
347
 
348
+ navigator.serviceWorker.controller?.postMessage(
349
+ {
350
+ type: 'INIT_PENPAL',
351
+ port: port2,
352
+ },
353
+ {
354
+ transfer: [port2],
355
+ }
356
+ );
357
+
348
358
  const messenger = new PortMessenger({
349
359
  port: port1,
350
360
  });
@@ -365,16 +375,6 @@ const initPenpal = async () => {
365
375
  console.log(multiplicationResult); // 12
366
376
  const divisionResult = await remote.divide(12, 4);
367
377
  console.log(divisionResult); // 3
368
-
369
- navigator.serviceWorker.controller?.postMessage(
370
- {
371
- type: 'INIT_PENPAL',
372
- port: port2,
373
- },
374
- {
375
- transfer: [port2],
376
- }
377
- );
378
378
  };
379
379
 
380
380
  if (navigator.serviceWorker.controller) {
@@ -566,13 +566,13 @@ const connection = connect({
566
566
 
567
567
  ## Parallel Connections
568
568
 
569
- In fairly rare cases, you may wish to make parallel connections between two participants. To illustrate, let's use a scenario where you wish to make two parallel connections between Window A and Window B. In other words, you will be calling `connect()` twice within Window A and twice within Window B.
569
+ In fairly rare cases, you may wish to make parallel connections between two participants. To illustrate, let's use a scenario where you wish to make two parallel connections between a parent window and an iframe window. In other words, you will be calling `connect()` twice within the parent window and twice within the iframe window.
570
570
 
571
- In an attempt to establish these two connections, Penpal in Window A will be calling `postMessage()` on a single window object. By default, when Penpal within Window B receives these messages, it has no way to disambiguate messages related to the first call to `connect()` from messages related to the second call to `connect()`. As a result, the connections may fail to be properly established.
571
+ In an attempt to establish these two connections, Penpal in the parent window will be calling `postMessage()` on the iframe's window object (`iframe.contentWindow`). By default, when Penpal within the iframe window receives these messages, it has no way to disambiguate messages related to the parent window's first call to `connect()` from messages related to the parent window's second call to `connect()`. As a result, the connections may fail to be properly established.
572
572
 
573
573
  To prevent this issue, Penpal provides the concept of channels. A channel is a string identifier of your choosing that you may provide when calling `connect()` within both participants. When a channel is provided, it is used to disambiguate communication between parallel connections. This is better explained in code:
574
574
 
575
- ### Window A
575
+ ### Parent Window
576
576
 
577
577
  ```javascript
578
578
  import { WindowMessenger, connect } from 'penpal';
@@ -613,14 +613,14 @@ const connectionB = connect({
613
613
  });
614
614
  ```
615
615
 
616
- ### Window B
616
+ ### Iframe Window
617
617
 
618
618
  ```javascript
619
619
  import { WindowMessenger, connect } from 'penpal';
620
620
 
621
621
  const messengerA = new WindowMessenger({
622
622
  remoteWindow: window.parent,
623
- allowedOrigins: ['https://parentOrigin.example.com'],
623
+ allowedOrigins: ['https://parentorigin.example.com'],
624
624
  });
625
625
 
626
626
  const connectionA = connect({
@@ -650,7 +650,7 @@ const connectionB = connect({
650
650
  });
651
651
  ```
652
652
 
653
- Although we're using `WindowMessenger` here to establish connections between two windows, channels would similarly need to be used when using `WorkerMessenger` to make parallel connections to a worker. When using `PortMessenger`, channels are only needed when establishing parallel connections over a single pair of ports.
653
+ Although we're using `WindowMessenger` here to connect between a parent window and an iframe window, channels would similarly need to be used when using `WorkerMessenger` to make parallel connections to a worker. When using `PortMessenger`, channels are only needed when establishing parallel connections over a single pair of ports.
654
654
 
655
655
  ## Errors
656
656
 
@@ -680,7 +680,7 @@ The promise returned from a method call will be rejected with this error if the
680
680
 
681
681
  When a connection is being established, the promise found at `connection.promise` will be rejected with this error if a message cannot be transmitted. When a method call is being made, the promise returned from the method call will be rejected with this error if a message cannot be transmitted.
682
682
 
683
- ### Error Code Enumeration
683
+ ### Referencing Error Codes
684
684
 
685
685
  For your convenience, the above error codes can be imported and referenced as follows:
686
686
 
@@ -725,6 +725,14 @@ const remote = await connection.promise;
725
725
  const multiplicationResult = await remote.multiply(2, 6);
726
726
  ```
727
727
 
728
+ When creating a worker, it's highly recommended that you add the following line of code at the top of your worker script depending on which type of worker you're creating:
729
+
730
+ - Dedicated (regular) worker: `declare const self: DedicatedWorkerGlobalScope;`
731
+ - Shared worker: `declare const self: SharedWorkerGlobalScope;`
732
+ - Service worker: `declare const self: ServiceWorkerGlobalScope;`
733
+
734
+ This lets TypeScript know which type of worker you're creating, and you'll run into fewer TypeScript errors.
735
+
728
736
  ### Exported Types
729
737
 
730
738
  Penpal exports several types for your usage. Import types as follows:
@@ -1,8 +1,7 @@
1
- declare const brand: unique symbol;
2
1
  declare class CallOptions {
2
+ #private;
3
3
  readonly transferables?: Transferable[];
4
4
  readonly timeout?: number;
5
- private [brand];
6
5
  constructor(options?: {
7
6
  transferables?: Transferable[];
8
7
  timeout?: number;
@@ -6,7 +6,8 @@ class CallOptions {
6
6
  timeout;
7
7
  // Allows TypeScript to distinguish between an actual instance of this
8
8
  // class versus an object that looks structurally similar.
9
- [brand] = brand;
9
+ // eslint-disable-next-line no-unused-private-class-members
10
+ #brand = brand;
10
11
  constructor(options) {
11
12
  this.transferables = options?.transferables;
12
13
  this.timeout = options?.timeout;
@@ -0,0 +1,9 @@
1
+ declare const ErrorCodeObj: {
2
+ readonly ConnectionDestroyed: "CONNECTION_DESTROYED";
3
+ readonly ConnectionTimeout: "CONNECTION_TIMEOUT";
4
+ readonly InvalidArgument: "INVALID_ARGUMENT";
5
+ readonly MethodCallTimeout: "METHOD_CALL_TIMEOUT";
6
+ readonly MethodNotFound: "METHOD_NOT_FOUND";
7
+ readonly TransmissionFailed: "TRANSMISSION_FAILED";
8
+ };
9
+ export default ErrorCodeObj;
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ // Not intended to be used internally. Can be useful externally
4
+ // in projects not using TypeScript. It has the `Obj` suffix to disambiguate
5
+ // it from the ErrorCode string union.
6
+ const ErrorCodeObj = {
7
+ ConnectionDestroyed: 'CONNECTION_DESTROYED',
8
+ ConnectionTimeout: 'CONNECTION_TIMEOUT',
9
+ InvalidArgument: 'INVALID_ARGUMENT',
10
+ MethodCallTimeout: 'METHOD_CALL_TIMEOUT',
11
+ MethodNotFound: 'METHOD_NOT_FOUND',
12
+ TransmissionFailed: 'TRANSMISSION_FAILED',
13
+ };
14
+ exports.default = ErrorCodeObj;
@@ -1,4 +1,4 @@
1
- import { ErrorCode } from './enums';
1
+ import { ErrorCode } from './types';
2
2
  declare class PenpalError extends Error {
3
3
  code: ErrorCode;
4
4
  constructor(code: ErrorCode, message: string);
package/cjs/Reply.d.ts CHANGED
@@ -1,8 +1,7 @@
1
- declare const brand: unique symbol;
2
1
  declare class Reply<T = unknown> {
2
+ #private;
3
3
  readonly value: T;
4
4
  readonly transferables?: Transferable[];
5
- private [brand];
6
5
  constructor(value: T, options?: {
7
6
  transferables?: Transferable[];
8
7
  });
package/cjs/Reply.js CHANGED
@@ -6,7 +6,8 @@ class Reply {
6
6
  transferables;
7
7
  // Allows TypeScript to distinguish between an actual instance of this
8
8
  // class versus an object that looks structurally similar.
9
- [brand] = brand;
9
+ // eslint-disable-next-line no-unused-private-class-members
10
+ #brand = brand;
10
11
  constructor(value, options) {
11
12
  this.value = value;
12
13
  this.transferables = options?.transferables;
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.downgradeMessage = exports.upgradeMessage = exports.isDeprecatedMessage = exports.DEPRECATED_PENPAL_PARTICIPANT_ID = void 0;
4
4
  const namespace_1 = require("./namespace");
5
- const enums_1 = require("./enums");
6
5
  const guards_1 = require("./guards");
7
6
  const PenpalBugError_1 = require("./PenpalBugError");
8
7
  exports.DEPRECATED_PENPAL_PARTICIPANT_ID = 'deprecated-penpal';
@@ -34,7 +33,7 @@ const upgradeMessage = (message) => {
34
33
  return {
35
34
  namespace: namespace_1.default,
36
35
  channel: undefined,
37
- type: enums_1.MessageType.Syn,
36
+ type: 'SYN',
38
37
  participantId: exports.DEPRECATED_PENPAL_PARTICIPANT_ID,
39
38
  };
40
39
  }
@@ -42,14 +41,14 @@ const upgradeMessage = (message) => {
42
41
  return {
43
42
  namespace: namespace_1.default,
44
43
  channel: undefined,
45
- type: enums_1.MessageType.Ack2,
44
+ type: 'ACK2',
46
45
  };
47
46
  }
48
47
  if (message.penpal === DeprecatedMessageType.Call) {
49
48
  return {
50
49
  namespace: namespace_1.default,
51
50
  channel: undefined,
52
- type: enums_1.MessageType.Call,
51
+ type: 'CALL',
53
52
  // Actually converting the ID to a string would break communication.
54
53
  id: message.id,
55
54
  methodPath: upgradeMethodPath(message.methodName),
@@ -61,7 +60,7 @@ const upgradeMessage = (message) => {
61
60
  return {
62
61
  namespace: namespace_1.default,
63
62
  channel: undefined,
64
- type: enums_1.MessageType.Reply,
63
+ type: 'REPLY',
65
64
  // Actually converting the ID to a string would break communication.
66
65
  callId: message.id,
67
66
  value: message.returnValue,
@@ -71,7 +70,7 @@ const upgradeMessage = (message) => {
71
70
  return {
72
71
  namespace: namespace_1.default,
73
72
  channel: undefined,
74
- type: enums_1.MessageType.Reply,
73
+ type: 'REPLY',
75
74
  // Actually converting the ID to a string would break communication.
76
75
  callId: message.id,
77
76
  isError: true,
package/cjs/connect.js CHANGED
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const PenpalError_1 = require("./PenpalError");
4
- const enums_1 = require("./enums");
5
4
  const shakeHands_1 = require("./shakeHands");
6
5
  const guards_1 = require("./guards");
7
6
  const once_1 = require("./once");
@@ -12,10 +11,10 @@ const usedMessengers = new WeakSet();
12
11
  */
13
12
  const connect = ({ messenger, methods = {}, timeout, channel, log, }) => {
14
13
  if (!messenger) {
15
- throw new PenpalError_1.default(enums_1.ErrorCode.InvalidArgument, 'messenger must be defined');
14
+ throw new PenpalError_1.default('INVALID_ARGUMENT', 'messenger must be defined');
16
15
  }
17
16
  if (usedMessengers.has(messenger)) {
18
- throw new PenpalError_1.default(enums_1.ErrorCode.InvalidArgument, 'A messenger can only be used for a single connection');
17
+ throw new PenpalError_1.default('INVALID_ARGUMENT', 'A messenger can only be used for a single connection');
19
18
  }
20
19
  usedMessengers.add(messenger);
21
20
  const connectionDestroyedHandlers = [messenger.destroy];
@@ -24,7 +23,7 @@ const connect = ({ messenger, methods = {}, timeout, channel, log, }) => {
24
23
  const destroyMessage = {
25
24
  namespace: namespace_1.default,
26
25
  channel,
27
- type: enums_1.MessageType.Destroy,
26
+ type: 'DESTROY',
28
27
  };
29
28
  try {
30
29
  messenger.sendMessage(destroyMessage);
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const errorSerialization_1 = require("./errorSerialization");
4
- const enums_1 = require("./enums");
5
4
  const Reply_1 = require("./Reply");
6
5
  const PenpalError_1 = require("./PenpalError");
7
6
  const methodSerialization_1 = require("./methodSerialization");
@@ -10,7 +9,7 @@ const namespace_1 = require("./namespace");
10
9
  const createErrorReplyMessage = (channel, callId, error) => ({
11
10
  namespace: namespace_1.default,
12
11
  channel,
13
- type: enums_1.MessageType.Reply,
12
+ type: 'REPLY',
14
13
  callId,
15
14
  isError: true,
16
15
  ...(error instanceof Error
@@ -42,7 +41,7 @@ const connectCallHandler = (messenger, methods, channel, log) => {
42
41
  try {
43
42
  const method = (0, methodSerialization_1.getMethodAtMethodPath)(methodPath, methods);
44
43
  if (!method) {
45
- throw new PenpalError_1.default(enums_1.ErrorCode.MethodNotFound, `Method \`${(0, methodSerialization_1.formatMethodPath)(methodPath)}\` is not found.`);
44
+ throw new PenpalError_1.default('METHOD_NOT_FOUND', `Method \`${(0, methodSerialization_1.formatMethodPath)(methodPath)}\` is not found.`);
46
45
  }
47
46
  let value = await method(...args);
48
47
  if (value instanceof Reply_1.default) {
@@ -52,7 +51,7 @@ const connectCallHandler = (messenger, methods, channel, log) => {
52
51
  replyMessage = {
53
52
  namespace: namespace_1.default,
54
53
  channel,
55
- type: enums_1.MessageType.Reply,
54
+ type: 'REPLY',
56
55
  callId,
57
56
  value,
58
57
  };
@@ -74,7 +73,7 @@ const connectCallHandler = (messenger, methods, channel, log) => {
74
73
  // If a consumer attempts to send an object that's not
75
74
  // cloneable (e.g., window), we want to ensure the receiver's promise
76
75
  // gets rejected.
77
- if (error.name === enums_1.NativeErrorName.DataCloneError) {
76
+ if (error.name === 'DataCloneError') {
78
77
  replyMessage = createErrorReplyMessage(channel, callId, error);
79
78
  log?.(`Sending ${(0, methodSerialization_1.formatMethodPath)(methodPath)}() reply`, replyMessage);
80
79
  messenger.sendMessage(replyMessage);
@@ -3,18 +3,18 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const generateId_1 = require("./generateId");
4
4
  const errorSerialization_1 = require("./errorSerialization");
5
5
  const methodSerialization_1 = require("./methodSerialization");
6
- const enums_1 = require("./enums");
7
6
  const CallOptions_1 = require("./CallOptions");
8
7
  const PenpalError_1 = require("./PenpalError");
9
8
  const guards_1 = require("./guards");
10
9
  const namespace_1 = require("./namespace");
10
+ const methodsToTreatAsNative = new Set(['apply', 'call', 'bind']);
11
11
  const createRemoteProxy = (callback, log, path = []) => {
12
- return new Proxy(path
12
+ return new Proxy(path.length
13
13
  ? () => {
14
14
  // Intentionally empty
15
15
  }
16
16
  : Object.create(null), {
17
- get(_target, prop) {
17
+ get(target, prop) {
18
18
  // If a promise is resolved with this proxy object, the JavaScript
19
19
  // runtime will look for a `then` property on this object to determine
20
20
  // if it should be treated as a promise (to support promise chaining).
@@ -24,24 +24,33 @@ const createRemoteProxy = (callback, log, path = []) => {
24
24
  if (prop === 'then') {
25
25
  return;
26
26
  }
27
+ // Because we're using a proxy and because Penpal supports developers
28
+ // exposing nested methods, we have a predicament. If a developer
29
+ // calls, for example, remote.auth.apply(), are they
30
+ // attempting to call a nested apply() method that a developer has
31
+ // explicitly exposed from the remote? Could they instead be attempting
32
+ // to call Function.prototype.apply() on the remote.auth() method?
33
+ // Without the remote telling the local Penpal which methods the
34
+ // developer has exposed, it has no way of knowing (and the main reason
35
+ // we use a proxy is so that Penpal doesn't have to communicate which
36
+ // methods are exposed). So, we treat certain methods as native methods
37
+ // and return the native method rather than a proxy. The downside of
38
+ // this is that if a developer has explicitly exposed a nested method
39
+ // with the same name as one of these native method names, the developer
40
+ // will be unable to call the exposed remote method because they will
41
+ // be calling the method on the Function prototype instead.
42
+ if (path.length && methodsToTreatAsNative.has(prop)) {
43
+ return Reflect.get(target, prop);
44
+ }
27
45
  return createRemoteProxy(callback, log, [...path, prop]);
28
46
  },
29
47
  apply(target, _thisArg, args) {
30
- if (log) {
31
- const lastPathSegment = path.at(-1);
32
- const builtInFunction = target[lastPathSegment];
33
- if ((0, guards_1.isFunction)(builtInFunction)) {
34
- log(`You may be attempting to call the native ` +
35
- `\`${lastPathSegment}\` method which is not supported. Call ` +
36
- `will be sent to remote.`);
37
- }
38
- }
39
48
  return callback(path, args);
40
49
  },
41
50
  });
42
51
  };
43
52
  const getDestroyedConnectionMethodCallError = (methodPath) => {
44
- return new PenpalError_1.default(enums_1.ErrorCode.ConnectionDestroyed, `Method call ${(0, methodSerialization_1.formatMethodPath)(methodPath)}() failed due to destroyed connection`);
53
+ return new PenpalError_1.default('CONNECTION_DESTROYED', `Method call ${(0, methodSerialization_1.formatMethodPath)(methodPath)}() failed due to destroyed connection`);
45
54
  };
46
55
  /**
47
56
  * Creates a proxy. When methods are called on the proxy, a "call" message will
@@ -89,10 +98,10 @@ const connectRemoteProxy = (messenger, channel, log) => {
89
98
  // running tests if we don't disambiguate the browser setTimeout
90
99
  // from node's setTimeout. There may be a better way to configure
91
100
  // Karma + Rollup + Typescript to avoid node type leakage.
92
- const timeoutId = timeout
101
+ const timeoutId = timeout !== undefined
93
102
  ? window.setTimeout(() => {
94
103
  replyHandlers.delete(callId);
95
- reject(new PenpalError_1.default(enums_1.ErrorCode.MethodCallTimeout, `Method call ${(0, methodSerialization_1.formatMethodPath)(methodPath)}() timed out after ${timeout}ms`));
104
+ reject(new PenpalError_1.default('METHOD_CALL_TIMEOUT', `Method call ${(0, methodSerialization_1.formatMethodPath)(methodPath)}() timed out after ${timeout}ms`));
96
105
  }, timeout)
97
106
  : undefined;
98
107
  replyHandlers.set(callId, { methodPath, resolve, reject, timeoutId });
@@ -100,7 +109,7 @@ const connectRemoteProxy = (messenger, channel, log) => {
100
109
  const callMessage = {
101
110
  namespace: namespace_1.default,
102
111
  channel,
103
- type: enums_1.MessageType.Call,
112
+ type: 'CALL',
104
113
  id: callId,
105
114
  methodPath,
106
115
  args: argsWithoutOptions,
@@ -109,7 +118,7 @@ const connectRemoteProxy = (messenger, channel, log) => {
109
118
  messenger.sendMessage(callMessage, transferables);
110
119
  }
111
120
  catch (error) {
112
- reject(new PenpalError_1.default(enums_1.ErrorCode.TransmissionFailed, error.message));
121
+ reject(new PenpalError_1.default('TRANSMISSION_FAILED', error.message));
113
122
  }
114
123
  });
115
124
  }, log);
package/cjs/guards.js CHANGED
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.isDestroyMessage = exports.isReplyMessage = exports.isCallMessage = exports.isAck2Message = exports.isAck1Message = exports.isSynMessage = exports.isMessage = exports.isFunction = exports.isObject = void 0;
4
4
  const namespace_1 = require("./namespace");
5
- const enums_1 = require("./enums");
6
5
  const isObject = (value) => {
7
6
  return typeof value === 'object' && value !== null;
8
7
  };
@@ -16,26 +15,26 @@ const isMessage = (data) => {
16
15
  };
17
16
  exports.isMessage = isMessage;
18
17
  const isSynMessage = (message) => {
19
- return message.type === enums_1.MessageType.Syn;
18
+ return message.type === 'SYN';
20
19
  };
21
20
  exports.isSynMessage = isSynMessage;
22
21
  const isAck1Message = (message) => {
23
- return message.type === enums_1.MessageType.Ack1;
22
+ return message.type === 'ACK1';
24
23
  };
25
24
  exports.isAck1Message = isAck1Message;
26
25
  const isAck2Message = (message) => {
27
- return message.type === enums_1.MessageType.Ack2;
26
+ return message.type === 'ACK2';
28
27
  };
29
28
  exports.isAck2Message = isAck2Message;
30
29
  const isCallMessage = (message) => {
31
- return message.type === enums_1.MessageType.Call;
30
+ return message.type === 'CALL';
32
31
  };
33
32
  exports.isCallMessage = isCallMessage;
34
33
  const isReplyMessage = (message) => {
35
- return message.type === enums_1.MessageType.Reply;
34
+ return message.type === 'REPLY';
36
35
  };
37
36
  exports.isReplyMessage = isReplyMessage;
38
37
  const isDestroyMessage = (message) => {
39
- return message.type === enums_1.MessageType.Destroy;
38
+ return message.type === 'DESTROY';
40
39
  };
41
40
  exports.isDestroyMessage = isDestroyMessage;
package/cjs/index.d.ts CHANGED
@@ -5,6 +5,6 @@ export { default as PortMessenger } from './messengers/PortMessenger';
5
5
  export { default as CallOptions } from './CallOptions';
6
6
  export { default as Reply } from './Reply';
7
7
  export { default as PenpalError } from './PenpalError';
8
+ export { default as ErrorCode } from './ErrorCodeObj';
8
9
  export { default as debug } from './debug';
9
- export { ErrorCode } from './enums';
10
10
  export { Connection, RemoteProxy, Methods } from './types';
package/cjs/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ErrorCode = exports.debug = exports.PenpalError = exports.Reply = exports.CallOptions = exports.PortMessenger = exports.WorkerMessenger = exports.WindowMessenger = exports.connect = void 0;
3
+ exports.debug = exports.ErrorCode = exports.PenpalError = exports.Reply = exports.CallOptions = exports.PortMessenger = exports.WorkerMessenger = exports.WindowMessenger = exports.connect = void 0;
4
4
  var connect_1 = require("./connect");
5
5
  Object.defineProperty(exports, "connect", { enumerable: true, get: function () { return connect_1.default; } });
6
6
  var WindowMessenger_1 = require("./messengers/WindowMessenger");
@@ -15,7 +15,7 @@ var Reply_1 = require("./Reply");
15
15
  Object.defineProperty(exports, "Reply", { enumerable: true, get: function () { return Reply_1.default; } });
16
16
  var PenpalError_1 = require("./PenpalError");
17
17
  Object.defineProperty(exports, "PenpalError", { enumerable: true, get: function () { return PenpalError_1.default; } });
18
+ var ErrorCodeObj_1 = require("./ErrorCodeObj");
19
+ Object.defineProperty(exports, "ErrorCode", { enumerable: true, get: function () { return ErrorCodeObj_1.default; } });
18
20
  var debug_1 = require("./debug");
19
21
  Object.defineProperty(exports, "debug", { enumerable: true, get: function () { return debug_1.default; } });
20
- var enums_1 = require("./enums");
21
- Object.defineProperty(exports, "ErrorCode", { enumerable: true, get: function () { return enums_1.ErrorCode; } });
@@ -4,7 +4,6 @@ import PortMessenger from './messengers/PortMessenger';
4
4
  import CallOptions from './CallOptions';
5
5
  import Reply from './Reply';
6
6
  import PenpalError from './PenpalError';
7
- import { ErrorCode } from './enums';
8
7
  declare const _default: {
9
8
  connect: <TMethods extends import("./types").Methods>({ messenger, methods, timeout, channel, log, }: {
10
9
  messenger: import("./messengers/Messenger").default;
@@ -20,6 +19,13 @@ declare const _default: {
20
19
  Reply: typeof Reply;
21
20
  PenpalError: typeof PenpalError;
22
21
  debug: (prefix?: string) => import("./types").Log;
23
- ErrorCode: typeof ErrorCode;
22
+ ErrorCode: {
23
+ readonly ConnectionDestroyed: "CONNECTION_DESTROYED";
24
+ readonly ConnectionTimeout: "CONNECTION_TIMEOUT";
25
+ readonly InvalidArgument: "INVALID_ARGUMENT";
26
+ readonly MethodCallTimeout: "METHOD_CALL_TIMEOUT";
27
+ readonly MethodNotFound: "METHOD_NOT_FOUND";
28
+ readonly TransmissionFailed: "TRANSMISSION_FAILED";
29
+ };
24
30
  };
25
31
  export default _default;
@@ -7,8 +7,8 @@ const PortMessenger_1 = require("./messengers/PortMessenger");
7
7
  const CallOptions_1 = require("./CallOptions");
8
8
  const Reply_1 = require("./Reply");
9
9
  const PenpalError_1 = require("./PenpalError");
10
+ const ErrorCodeObj_1 = require("./ErrorCodeObj");
10
11
  const debug_1 = require("./debug");
11
- const enums_1 = require("./enums");
12
12
  exports.default = {
13
13
  connect: connect_1.default,
14
14
  WindowMessenger: WindowMessenger_1.default,
@@ -18,5 +18,5 @@ exports.default = {
18
18
  Reply: Reply_1.default,
19
19
  PenpalError: PenpalError_1.default,
20
20
  debug: debug_1.default,
21
- ErrorCode: enums_1.ErrorCode,
21
+ ErrorCode: ErrorCodeObj_1.default,
22
22
  };
@@ -10,12 +10,9 @@ type Options = {
10
10
  * Handles the details of communicating on a MessagePort.
11
11
  */
12
12
  declare class PortMessenger implements Messenger {
13
- private _port;
14
- private _validateReceivedMessage?;
15
- private _messageCallbacks;
13
+ #private;
16
14
  constructor({ port }: Options);
17
15
  initialize: ({ validateReceivedMessage }: InitializeOptions) => void;
18
- private _handleMessage;
19
16
  sendMessage: (message: Message, transferables?: Transferable[]) => void;
20
17
  addMessageHandler: (callback: MessageHandler) => void;
21
18
  removeMessageHandler: (callback: MessageHandler) => void;
@@ -1,48 +1,47 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const PenpalError_1 = require("../PenpalError");
4
- const enums_1 = require("../enums");
5
4
  /**
6
5
  * Handles the details of communicating on a MessagePort.
7
6
  */
8
7
  class PortMessenger {
9
- _port;
10
- _validateReceivedMessage;
11
- _messageCallbacks = new Set();
8
+ #port;
9
+ #validateReceivedMessage;
10
+ #messageCallbacks = new Set();
12
11
  constructor({ port }) {
13
12
  if (!port) {
14
- throw new PenpalError_1.default(enums_1.ErrorCode.InvalidArgument, 'port must be defined');
13
+ throw new PenpalError_1.default('INVALID_ARGUMENT', 'port must be defined');
15
14
  }
16
- this._port = port;
15
+ this.#port = port;
17
16
  }
18
17
  initialize = ({ validateReceivedMessage }) => {
19
- this._validateReceivedMessage = validateReceivedMessage;
20
- this._port.addEventListener('message', this._handleMessage);
21
- this._port.start();
22
- };
23
- _handleMessage = ({ data }) => {
24
- if (!this._validateReceivedMessage?.(data)) {
25
- return;
26
- }
27
- for (const callback of this._messageCallbacks) {
28
- callback(data);
29
- }
18
+ this.#validateReceivedMessage = validateReceivedMessage;
19
+ this.#port.addEventListener('message', this.#handleMessage);
20
+ this.#port.start();
30
21
  };
31
22
  sendMessage = (message, transferables) => {
32
- this._port?.postMessage(message, {
23
+ this.#port?.postMessage(message, {
33
24
  transfer: transferables,
34
25
  });
35
26
  };
36
27
  addMessageHandler = (callback) => {
37
- this._messageCallbacks.add(callback);
28
+ this.#messageCallbacks.add(callback);
38
29
  };
39
30
  removeMessageHandler = (callback) => {
40
- this._messageCallbacks.delete(callback);
31
+ this.#messageCallbacks.delete(callback);
41
32
  };
42
33
  destroy = () => {
43
- this._port.removeEventListener('message', this._handleMessage);
44
- this._port.close();
45
- this._messageCallbacks.clear();
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
+ }
46
45
  };
47
46
  }
48
47
  exports.default = PortMessenger;
@@ -18,21 +18,9 @@ type Options = {
18
18
  * Handles the details of communicating with a child window.
19
19
  */
20
20
  declare class WindowMessenger implements Messenger {
21
- private _remoteWindow;
22
- private _allowedOrigins;
23
- private _log?;
24
- private _validateReceivedMessage?;
25
- private _concreteRemoteOrigin?;
26
- private _messageCallbacks;
27
- private _port?;
28
- private _isChildUsingDeprecatedProtocol;
21
+ #private;
29
22
  constructor({ remoteWindow, allowedOrigins }: Options);
30
23
  initialize: ({ log, validateReceivedMessage }: InitializeOptions) => void;
31
- private _isAllowedOrigin;
32
- private _getOriginForSendingMessage;
33
- private _destroyPort;
34
- private _handleMessageFromRemoteWindow;
35
- private _handleMessageFromPort;
36
24
  sendMessage: (message: Message, transferables?: Transferable[]) => void;
37
25
  addMessageHandler: (callback: MessageHandler) => void;
38
26
  removeMessageHandler: (callback: MessageHandler) => void;