Releases: Aaronius/penpal
v7.0.6
- Changed WorkerMessenger constructor option
workerfromWorker | DedicatedWorkerGlobalScopeto a structuralWorkerLike
(Pick<Worker, 'postMessage' | 'addEventListener' | 'removeEventListener'>). This prevents generated Penpal declaration files from requiringDedicatedWorkerGlobalScope, fixing TS2304 for consumers that do not include thewebworkerlib (see #108).
v7.0.5
- 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
v7.0.3
v7.0.2
v7.0.1
v7.0.0
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....
v6.2.2
v6.2.1
v6.2.0
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!