Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/pass-style/NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@ User-visible changes in `@endo/pass-style`:

# Next release

- deprecates `assertChecker`. Use `Fail` in the confirm/reject pattern instead, as supported by `@endo/errors/rejector.js`.
- Deprecates `assertChecker`. Use `Fail` in the confirm/reject pattern instead, as supported by `@endo/errors/rejector.js`.
- Enables `passStyleOf` to make errors passable as a side-effect when SES locks
down with `hardenTaming` set to `unsafe`, which impacts errors on V8 starting
with Node.js 21, and similar engines, that own a `stack` getter and setter
that would otherwise be repaired as a side-effect of `harden`.
- Update typing of `CopyArray<T>` to be compatible with `ReadonlyArray<T>` since
we know dynamically that the CopyArray is hardened, so we may as well show
statically that mutation is not allowed.

# 1.6.3 (2025-07-11)

Expand Down
18 changes: 13 additions & 5 deletions packages/pass-style/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export type PassStyled<S extends PassStyleMarker, I extends InterfaceSpec> = {

export type ExtractStyle<P extends PassStyled<any, any>> = P[typeof PASS_STYLE];

export type PassByCopy = Atom | Error | CopyArray | CopyRecord | CopyTagged;
export type PassByCopy = Atom | Error | CopyArray | CopyReadonlyArray | CopyRecord | CopyTagged;

export type PassByRef =
| RemotableObject
Expand Down Expand Up @@ -114,13 +114,16 @@ export type Passable<

export type Container<PC extends PassableCap, E extends Error> =
| CopyArrayInterface<PC, E>
| CopyReadonlyArrayInterface<PC, E>
| CopyRecordInterface<PC, E>
| CopyTaggedInterface<PC, E>;
interface CopyArrayInterface<PC extends PassableCap, E extends Error>
export interface CopyArrayInterface<PC extends PassableCap, E extends Error>
extends CopyArray<Passable<PC, E>> {}
interface CopyRecordInterface<PC extends PassableCap, E extends Error>
export interface CopyReadonlyArrayInterface<PC extends PassableCap, E extends Error>
extends CopyReadonlyArray<Passable<PC, E>> {}
export interface CopyRecordInterface<PC extends PassableCap, E extends Error>
extends CopyRecord<Passable<PC, E>> {}
interface CopyTaggedInterface<PC extends PassableCap, E extends Error>
export interface CopyTaggedInterface<PC extends PassableCap, E extends Error>
extends CopyTagged<string, Passable<PC, E>> {}

export type PassStyleOf = {
Expand All @@ -134,7 +137,7 @@ export type PassStyleOf = {
(p: Promise<any>): 'promise';
(p: Error): 'error';
(p: CopyTagged): 'tagged';
(p: any[]): 'copyArray';
(p: readonly any[]): 'copyArray';
(p: Iterable<any>): 'remotable';
(p: Iterator<any, any, undefined>): 'remotable';
<T extends PassStyled<PassStyleMarker, any>>(p: T): ExtractStyle<T>;
Expand Down Expand Up @@ -204,6 +207,11 @@ export type PassableCap =
*/
export type CopyArray<T extends Passable = any> = Array<T>;

/**
* A Passable and Readonly sequence of Passable values.
*/
export type CopyReadonlyArray<T extends Passable = any> = ReadonlyArray<T>;

/**
* A hardened immutable ArrayBuffer.
*/
Expand Down
24 changes: 23 additions & 1 deletion packages/pass-style/src/types.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { expectAssignable, expectType, expectNotType } from 'tsd';
import { Far } from './make-far.js';
import { passStyleOf } from './passStyleOf.js';
import { makeTagged } from './makeTagged.js';
import type { Checker, CopyTagged, Passable, PassStyle } from './types.js';
import type { Checker, CopyArray, CopyReadonlyArray, CopyTagged, Passable, PassStyle } from './types.js';
import { PASS_STYLE } from './passStyle-helpers.js';
import { passableSymbolForName } from './symbol.js';

Expand Down Expand Up @@ -35,6 +35,22 @@ const expectPassable = (val: Passable) => {};

const fn = () => {};

// CopyArray is mutable, so we can test mutation methods.
const arr: CopyArray<number> = [];
arr.push(1);
arr.slice(0, 1);
arr.shift();
expectPassable(arr);

// Not so for CopyReadonlyArray.
const roArr: CopyReadonlyArray<number> = [];
// @ts-expect-error not mutable
roArr.push(1);
roArr.slice(0, 1);
// @ts-expect-error not mutable
roArr.shift();
expectPassable(roArr);

expectPassable(1);
expectPassable(null);
expectPassable('str');
Expand All @@ -44,6 +60,12 @@ expectPassable(fn());

expectPassable({});
expectPassable({ a: {} });
expectPassable({ a: { b: {} } });
expectPassable(['car', 'cdr']);
expectPassable(['car', 'cdr'] as string[]);
expectPassable([['a'], ['b']] as const);
expectPassable(['car', 'cdr'] as Readonly<string[]>);
expectPassable(['car', 'cdr'] as Readonly<[string, string]>);
// @ts-expect-error not passable
expectPassable(fn);
// FIXME promise for a non-Passable is not Passable
Expand Down