Skip to content

Releases: Aaronius/penpal

v7.0.6

13 Feb 04:45

Choose a tag to compare

  • Changed WorkerMessenger constructor option worker from Worker | DedicatedWorkerGlobalScope to a structural WorkerLike
    (Pick<Worker, 'postMessage' | 'addEventListener' | 'removeEventListener'>). This prevents generated Penpal declaration files from requiring DedicatedWorkerGlobalScope, fixing TS2304 for consumers that do not include the webworker lib (see #108).

v7.0.5

13 Feb 04:23

Choose a tag to compare

  • Avoids a "You've hit a bug in Penpal." error when a parent is calling a method on a child that is reloading and in the middle of a reconnection handshake. Penpal now handles this scenario properly by rejecting the method call with a TRASMISSION_FAILED PenpalError.

v7.0.4

01 Apr 02:26

Choose a tag to compare

  • Fixes #104 where running Penpal within node would result in the error ReferenceError: exports is not defined.

v7.0.3

29 Mar 21:22

Choose a tag to compare

  • Avoids a warning being logged by the browser when (1) allowedOrigins is configured with a single string origin and (2) the child iframe has been recently added to the DOM but the browser has not yet started to load the iframe document.

v7.0.2

26 Mar 00:04

Choose a tag to compare

  • Fixes an issue where bundling Penpal into applications using specific older versions of Webpack would cause an error because Webpack had very specific requirements about the order of certain keys in package.json.

v7.0.1

25 Mar 23:07

Choose a tag to compare

  • Fixes an issue when importing Penpal with Webpack (and potentially some other bundlers) because import statements within Penpal didn't include the file extension, which didn't follow esm strictly.

v7.0.0

12 Mar 02:56

Choose a tag to compare

Version 7 is here! It contains quite a few new features and breaking changes, so let's get into it.

Migration

To ease the pain of migration, running Penpal v7 in a parent window is compatible with running Penpal v6 in a child iframe. Therefore, if it's difficult to upgrade Penpal in the parent window and iframe at the same time, update code in the parent window first and then update code in the child iframe. Compatibility with v6 will be removed in the next major version of Penpal (v8). Note that running Penpal v6 in the parent window is not compatible with running Penpal v7 in the child iframe.

Breaking changes

A WindowMessenger is now required

What

Message transmission details between a parent window and a child iframe have been moved to a new WindowMessenger class. You'll now pass an instance of WindowMessenger as the messenger option when calling connect. See Usage with an Iframe in the README.

Why

Separating message transmission into a dedicated class allows Penpal to support additional contexts—such as communication between a window and a worker—while keeping the shared, high-level logic inside connect.

connectToChild and connectToParent have been renamed

What

connectToChild and connectToParent are now unified into a single connect function.

Why

With WindowMessenger receiving a reference to the iframe window instead of connectToChild, the connectToChild and connectToParent functions essentially became identical and no longer needed to be separate functions.

Origin defaults have changed

What

When calling connectToChild, the default value for the childOrigin option was previously derived from the iframe’s src attribute. This is no longer the case. Penpal now defaults to restricting communication to the origin of the parent window’s HTML document. If you'd like to derive the origin from the iframe’s src when specifying the child origin, you can use new URL(iframe.src).origin. See Usage with an Iframe in the README.

When calling connectToParent, the default value for the parentOrigin option was *. This has been changed as well. Penpal now defaults to restricting communication to the origin of the child iframe’s HTML document.

Why

In this version, Penpal only receives a reference to the iframe’s content window (iframe.contentWindow) rather than the iframe itself, so it no longer attempts to derive the child’s origin when connecting.

When connecting to the parent window from the child iframe, I wasn’t comfortable with Penpal using * as the default parentOrigin. Even though the README recommended against using the default, developers might easily overlook it. As this library is security-conscious, it seems more appropriate to encourage developers to manually specify * when necessary, rather than rely on the default.

Debugging has changed

What

Previously, to enable debugging, you needed to set the debug option to true when calling connectToChild or connectToParent. Now, you’ll need to set the log option to a function of your choice. Penpal exports a simple debug function that logs debug messages to the console, and you can use this as the value for the log option. See Debugging in the README.

Why

Allowing a function to be provided instead of a boolean increases flexibility. For instance, you can use a more advanced logging library, like the popular debug package, or write your own custom logging function.

Errors have changed

What

Errors thrown by Penpal were previously instances of the native Error class. They are now instances of a new PenpalError class, which extends from Error. Additionally, error codes (found on the code property) have been updated. The code ConnectionDestroyed is now CONNECTION_DESTROYED, and ConnectionTimeout has changed to CONNECTION_TIMEOUT. If you were using ErrorCode.ConnectionDestroyed or ErrorCode.ConnectionTimeout properties to reference the error code strings, these properties remain unchanged. The NoIframeSrc error code has been removed because Penpal is now only provided with a reference to the iframe’s content window (iframe.contentWindow) rather than the iframe itself.

Note that some error codes have been added. See Errors in the README for all the latest error codes.

Why

I added the PenpalError class because I was uncomfortable with Penpal adding a code property directly to the native Error instance. TypeScript was uncomfortable with it as well. It made more sense to create a new class that extends Error and properly supports the code property.

Object containing remote methods is now a Proxy object

What

In earlier versions of Penpal, connection.promise resolved to an object containing methods that reflected the remote methods. These methods were defined as standard properties on the object. In this version, however, this object is now a Proxy and the methods are no longer defined as standard properties.

To illustrate, let's assume we're following this example from version 6 where multiply and divide methods are being exposed from an iframe and used in the parent window.

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
  console.log(Object.keys(child)); // ['multiply', 'divide']
});

Note how multiply and divide are both keys on child. Let's see how this plays out in version 7:

connection.promise.then((child) => {
  child.multiply(2, 6).then((total) => console.log(total));
  child.divide(12, 4).then((total) => console.log(total));
  console.log(Object.keys(child)); // []
});

The calls to multiply and divide are still the same and function properly, but notice how Object.keys returns an empty array. The child object is not pre-built with multiply and divide properties, but instead dynamically handles method calls as they occur.

Why

Using a proxy object simplifies and reduces the amount of work Penpal needs to perform as well as minimizes required code. Penpal no longer needs to extract names and "paths" of methods, send them to the remote, and then rebuild objects with the same structure.

Types have changed

What

The AsyncMethodReturns type has been renamed to RemoteProxy. The CallSender type has been removed.

Why

The name AsyncMethodReturns was overly focused on implementation details. The new name, RemoteProxy, more accurately reflects its role as a proxy for methods exposed by the remote. Additionally, the type has been enhanced to support new features such as method call timeouts and transferable objects.

The CallSender type was redundant. The existing Methods type serves as the replacement for CallSender.

New features

Support for workers, windows, and other things using ports

Penpal now supports workers (dedicated workers, shared workers, and service workers), windows opened using window.open(), and other things that use MessagePorts. This is facilitated by the new WindowMessenger, WorkerMessenger, and PortMessenger classes. See the usage examples in the README for more information.

Method call timeouts

When calling a remote method, you can now specify a timeout. If the timeout elapses before hearing back from the remote, the promise returned from the method call with be rejected with an error. See Method Call Timeouts for more information.

Support for transferable objects

Browsers natively support transferable objects for transferring large data between contexts. This functionality is now available in Penpal. See Transferring Large Data for more details.

Support for specifying multiple origins from either side of the connection

When connecting from an iframe to a parent window, you've been able to use a regular expression to restrict communication to multiple origins. However, this feature was not available when connecting from the parent window to an iframe. Now, this capability is available and identical when connecting from either direction. Furthermore, instead of specifying just one origin or regular expression, you can now provide an array of origins or regular expressions, making things easier and more flexible.

Enhanced handshake protocol

When establishing a connection, Penpal performs a handshake to ensure both participants can send and receive messages. Previously, this process required calling connectToChild in the parent window before calling connectToParent in the iframe....

Read more

v6.2.2

06 Mar 21:58

Choose a tag to compare

Fixes #85 which is an issue where an error would occur under specific timing scenarios when the child iframe is removed from the DOM at about the same time it sends a SYN message. The error didn't cause operational issues, but would still be an uncaught error.

v6.2.1

14 Oct 04:22

Choose a tag to compare

Added some documentation to the readme regarding TypeScript usage.

v6.2.0

14 Oct 04:21

Choose a tag to compare

Added support for a wildcard as a value for childOrigin. This allows the parent to communicate within any child origin.

Thanks @KutnerUri for the contribution!