Skip to content

improve type inference#3172

Merged
turadg merged 19 commits intomasterfrom
ta/remotable
Apr 15, 2026
Merged

improve type inference#3172
turadg merged 19 commits intomasterfrom
ta/remotable

Conversation

@turadg
Copy link
Copy Markdown
Member

@turadg turadg commented Apr 8, 2026

Refs: #3171

Description

Improves TypeScript inference across @endo/exo, @endo/patterns, @endo/pass-style, @endo/eventual-send, and @endo/ocapn, discovered while integrating Endo with agoric-sdk under TypeScript 6. The changes are almost entirely type-level — no runtime behavior changes — and each commit is a self-contained fix so they can be reviewed (and reverted) independently.

Notable fixes:

  • pass-style: CopyArray<T> is now readonly T[], so readonly tuples (e.g. readonly ["ibc"]) satisfy Passable. Backward-compatible since T[] still extends readonly T[].
  • patterns: M.remotable() defaults to any (matching M.promise()) so unparameterized remotables are assignable to concrete remotable typedefs downstream. TFRemotable, TFOr, TFOptionalTuple, TFSplitRecord, TFRestArgs, TypeFromArgGuard, and MatcherOf propagation through InterfaceGuard all tightened. Adds CastedPattern<T> for unchecked type assertions and objectExtendEach helper.
  • exo: defineExoClass, defineExoClassKit, and makeExo no longer intersect facet constraints with & Methods, which was collapsing specific facet keys into the index signature and erasing facet method inference (Pick<X, never> = {}). Guarded<M, G> is now structurally compatible across G.
  • eventual-send: short-circuits any in RemoteFunctions, PickCallable, and ECallableOrMethods. Publicly exports EMethods/EGetters and friends.
  • ocapn: parameterizes CapTP slots; general TS-6 conformance pass.

The most critical files to review are the type definitions under packages/patterns/src/types.d.ts, packages/exo/src/types.d.ts, packages/pass-style/src/types.js, and packages/eventual-send/src/types.d.ts.

Security Considerations

None. Type-only changes; no new authority, no change to mutually-suspicious component boundaries.

Scaling Considerations

None. No runtime changes.

Documentation Considerations

No user-facing API changes. Downstream consumers that were working around the inference bugs with casts may be able to remove those casts, but existing casts remain valid.

Testing Considerations

Covered by existing unit tests plus the root tsc type-check, which this PR makes pass cleanly under TypeScript 6. The real-world validation is successful integration with agoric-sdk, where these inference gaps were originally surfaced.

Compatibility Considerations

Backward-compatible at the value level. At the type level, a few overly-narrow types were widened (e.g. CopyArray<T> to readonly T[], M.remotable() default to any); downstream code that depended on the previous narrower shape may need minor adjustments, but the common case is that previously-broken inference now works without changes.

Upgrade Considerations

None — no persistent state, no migrations, no breaking runtime changes.

@turadg
Copy link
Copy Markdown
Member Author

turadg commented Apr 8, 2026

This change is part of the following stack:

Change managed by git-spice.

@turadg turadg mentioned this pull request Apr 8, 2026
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 8, 2026

🦋 Changeset detected

Latest commit: 37aa50b

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@endo/common Minor
@endo/eventual-send Minor
@endo/patterns Minor
@endo/exo Minor
@endo/pass-style Minor
@endo/ocapn Minor
@endo/marshal Patch
@endo/captp Patch
@endo/cli Patch
@endo/daemon Patch
@endo/far Patch
@endo/init Patch
@endo/lp32 Patch
@endo/netstring Patch
@endo/stream-node Patch
@endo/stream Patch
@endo/bundle-source Patch
@endo/ses-ava Patch
@endo/stream-types-test Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@turadg turadg changed the title improve types of Exo, OcapN and Patterns improve type inference Apr 8, 2026
@turadg turadg requested a review from erights April 8, 2026 21:01
@turadg turadg marked this pull request as ready for review April 13, 2026 20:29
Copilot AI review requested due to automatic review settings April 13, 2026 20:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Improves TypeScript type inference and TS6 compatibility across multiple Endo packages, primarily via type-level refinements and expanded type tests.

Changes:

  • Refines @endo/patterns type inference (e.g., M.remotable() default, void vs undefined, PromiseLike, optional tuples, rest args, and new CastedPattern<T>).
  • Updates @endo/exo guarded type plumbing to preserve facet inference and improve Guarded<..., G> structural compatibility.
  • Parameterizes OCapN CapTP slot types and adds a new @endo/common helper objectExtendEach.

Reviewed changes

Copilot reviewed 27 out of 32 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/ses/types.d.ts Adds global typing for ModuleSource (optionally installed by shim).
packages/ses/test/module-source.test.js Narrows ModuleSource to non-undefined after shim load for tests.
packages/patterns/test/types.test-d.ts Expands/updates type-level regression tests (void/PromiseLike/remotable/rest/optional tuples/CastedPattern).
packages/patterns/src/types.ts Adds CastedPattern<T> and changes M.remotable() default generic to any; tightens interface guard generic constraints.
packages/patterns/src/type-from-pattern.ts Implements CastedPattern handling and multiple inference fixes (void/PromiseLike/TFOr/TFSplitRecord/TFOptionalTuple/TFRestArgs/etc.).
packages/pass-style/src/types.d.ts Changes CopyArray<T> to readonly T[] to accept readonly tuples.
packages/ocapn/test/codecs/passable.test.js Adds casts to satisfy stricter typing for tagged passable codec tests.
packages/ocapn/test/client.test.js Adds casts for debug/message typing in tests.
packages/ocapn/test/captp/pairwise.test.js Adds casts for primitive-path slot lookup tests.
packages/ocapn/src/client/sturdyrefs.js Casts bootstrap to any for E(...) call site under stricter typing.
packages/ocapn/src/client/ref-kit.js Adds JSDoc assertions for remote promise/object value lookups.
packages/ocapn/src/client/ocapn.js Widens getRemoteBootstrap return type to any.
packages/ocapn/src/captp/types.js Parameterizes CapTP Slot type by SlotType.
packages/ocapn/src/captp/pairwise.js Propagates parameterized Slot<T> through makeSlot/parseSlot.
packages/exo/types-index.d.ts Adjusts generics to avoid facet inference collapse and improve ThisType inference in kits.
packages/exo/test/types-plain-unguarded.test-d.ts Adds regression tests for facet inference when guard kit is undefined.
packages/exo/test/types-plain-guarded.test-d.ts Updates expectations to void returns and documents kit typing trade-offs.
packages/exo/test/types-advanced.test-d.ts Updates advanced type expectations (e.g., void returns).
packages/exo/test/heap-classes.test.js Removes @ts-expect-error markers that are no longer expected under new typing.
packages/exo/src/types.d.ts Makes Guarded<M, G> structurally compatible across G via phantom method; adjusts GuardedMethods extraction.
packages/eventual-send/test/eventual-send.test.js Casts rwp(handler2) result to any under stricter checking.
packages/eventual-send/src/no-shim.js Removes an imported type from JSDoc @import list.
packages/eventual-send/src/exports.d.ts Exports additional public E() helper types.
packages/eventual-send/src/E.js Short-circuits any in several conditional helper types to avoid unusable projections.
packages/daemon/src/context.js Tightens JSDoc typing (@returns, Context['cancel']) and asserts returned object type.
packages/compartment-mapper/src/link.js Removes an unused JSDoc-imported type name.
packages/common/object-map.js Adds new objectExtendEach helper with hardened result and typed JSDoc.
.eslintignore Removes explicit un-ignore entries for many .d.ts files.
.changeset/ocapn-captp-slot-types.md Changeset for OCapN slot typing improvements.
.changeset/improve-pattern-exo-inference.md Changeset for patterns/exo/pass-style inference improvements.
.changeset/eventual-send-type-exports.md Changeset for eventual-send type exports and any short-circuiting.
.changeset/common-object-extend-each.md Changeset for new objectExtendEach helper.
Comments suppressed due to low confidence (1)

packages/patterns/src/type-from-pattern.ts:1

  • The doc comment says M.remotable<SomeTypedef>() should preserve and return the concrete Payload type, but the implementation currently returns any for all non-InterfaceGuard payloads. This makes parameterized M.remotable<T>() lose specificity and contradicts the comment (and parts of the PR description/changeset). Consider returning Payload in the non-InterfaceGuard branch, and using a separate condition to keep the unparameterized default (any) behavior.
/// <reference types="ses"/>

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 266 to +282
/**
* Map a tuple to elements that may be undefined (approximates optional).
* Map a tuple of patterns to a tuple of inferred types whose elements are
* truly optional (`[X?, Y?]`), not just `T | undefined`.
*
* TS limitation: We cannot produce `[X?, Y?]` from a recursive conditional
* type — `Partial<Tuple>` only works on concrete tuples. For splitArray
* optional elements we use `T | undefined` instead, meaning the array
* must still be the full length. If TS gains support for producing truly
* optional tuple elements from conditional types, this should be revised.
* Uses a homomorphic mapped type with the `?` modifier
* (`{ [K in keyof T]?: ... }`). Despite an earlier comment claiming this
* was impossible, TypeScript *does* support producing optional tuple elements
* from a homomorphic mapped type — the `?` modifier on the mapping projects
* to truly-optional positions when the source `T` is a tuple type.
*
* The `& {}` removes the `length` and `Array.prototype` keys that the
* mapped type would otherwise keep, leaving a clean tuple shape that
* matches consumer typedefs declared with `[X?, Y?]` syntax.
*/
type TFOptionalTuple<T extends readonly any[]> = T extends readonly [
infer H,
...infer R,
]
? [TypeFromPattern<H> | undefined, ...TFOptionalTuple<R>]
: [];
type TFOptionalTuple<T extends readonly any[]> = {
[K in keyof T]?: TypeFromPattern<T[K]>;
};
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — the comment was stale. The & {} intersection is not needed and not present: TypeScript's homomorphic-mapped-type-over-tuple special case preserves tuple-ness on its own, so { [K in keyof T]?: ... } already produces a clean [X?, Y?] shape without length/prototype pollution. The test at types.test-d.ts:402 pins this down with expectType<[string, bigint?, boolean?]> (exact-type match), which the current impl passes.

Updated the doc comment to drop the misleading paragraph and explain the preservation via the homomorphic-mapped-type special case instead.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — the comment was stale. The & {} intersection is not needed and not present: TypeScript's homomorphic-mapped-type-over-tuple special case preserves tuple-ness on its own, so { [K in keyof T]?: ... } already produces a clean [X?, Y?] shape without length/prototype pollution. The test at types.test-d.ts:402 pins this down with expectType<[string, bigint?, boolean?]> (exact-type match), which the current impl passes.

Updated the doc comment to drop the misleading paragraph and explain the preservation via the homomorphic-mapped-type special case instead.

Comment thread packages/common/object-map.js Outdated
Comment on lines +104 to +117
* @template {Record<string, unknown>} O
* @template {Record<string, unknown>} Ex
* @param {O} original
* @param {(value: O[keyof O & string], key: string & keyof O) => Ex} extendFn
* @returns {{ [K in keyof O]: O[K] & Ex }}
*/
export const objectExtendEach = (original, extendFn) => {
const newEntries = typedMap(
typedEntries(original),
/** @type {([k, v]: [string, object]) => [string, object]} */
([k, v]) => [k, { ...v, ...extendFn(v, k) }],
);
return /** @type {any} */ (harden(fromTypedEntries(newEntries)));
};
Comment thread .eslintignore
Comment thread packages/patterns/src/types.ts
Copy link
Copy Markdown
Member

@boneskull boneskull left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is pretty big, but I went over it about as well as can be expected. I don't see any blockers; just some questions and suggestions.

case 'get': {
const noGet = new HandledPromise((_, _2, rwp) => {
const obj = rwp(handler2);
const obj = /** @type {any} */ (rwp(handler2));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't like it 😄

Copy link
Copy Markdown
Member Author

@turadg turadg Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would you prefer a ts-expect-error? it is just a test

> = StripIndexSignature<M> & {
__getInterfaceGuard__?: () => G | undefined;
__getInterfaceGuard__?: () => InterfaceGuard | undefined;
__interfaceGuard__?(g?: G): void;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be:

Suggested change
__interfaceGuard__?(g?: G): void;
__interfaceGuard__?(g?: G | undefined): void;

..?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure. what drives the question?

*/
export const parseSlot = slot => {
const type = slot[0];
const type = /** @type {T} */ (slot[0]);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is interesting and makes me think about how to avoid the type assertion. I don't think it's avoidable. That said, it should be possible to create a type and function which would extract the SlotType from any Slot (though the function itself would contain a type assertion).

type ExtractSlotType<Slot extends string> = Slot extends 
  `${infer S extends SlotType}${'+' | '-'}${string}` ? S : never;

function extractSlotType<T extends Slot<SlotType>>(slot: T): ExtractPrefix<T> {
  return s[0] as ExtractPrefix<T>;
}

Of course, this is of dubious value, but I just got nerd-sniped, so I'm sharing.

Comment thread packages/ocapn/src/client/ref-kit.js Outdated
provideRemotePromiseValue: position => {
const slot = makeSlot('p', false, position);
let value = ocapnTable.getValueForSlot(slot);
let value = /** @type {Promise<unknown> | undefined} */ (
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are these needed?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch. from an earlier rev. removing

Comment on lines +115 to +118
// produced). TypeScript's distinction between `void` and `undefined`
// is that a `void`-returning function may actually return any value
// (callers must ignore it), while an `undefined`-returning function
// must return literally `undefined`. At a parameter/return position
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL!

Comment thread packages/ses/test/module-source.test.js Outdated
Comment thread packages/ses/types.d.ts Outdated
new (source: string, opts?: string | object): ModuleSourceInstance;
readonly prototype: ModuleSourceInstance;
}
var ModuleSource: ModuleSourceConstructor | undefined;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't it @endo/module-source's responsibility to add this global?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. Its shim does add the global. I think it was because this module defines other globals but I've moved it to module-source.

Comment thread .eslintignore Outdated
Comment on lines -17 to -34
!packages/bundle-source/src/exports.d.ts
!packages/captp/src/ts-types.d.ts
!packages/cli/test/_types.d.ts
!packages/compartment-mapper/src/types-external.d.ts
!packages/compartment-mapper/src/types.d.ts
!packages/daemon/src/types.d.ts
!packages/daemon/types.d.ts
!packages/eventual-send/src/exports.d.ts
!packages/eventual-send/src/types.d.ts
!packages/exo/src/types.d.ts
!packages/far/src/exports.d.ts
!packages/lp32/types.d.ts
!packages/pass-style/src/types.d.ts
!packages/ses/src/reporting-types.d.ts
!packages/ses/types.d.ts
!packages/stream/types.d.ts
!packages/trampoline/types.d.ts
!packages/where/types.d.ts
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

landed this in the TS6 bump

Comment on lines +394 to +397
// Required + optional: produces truly optional tuple elements `[X?, Y?]`
// (not just `T | undefined`). The optional positions in `splitArray`'s
// second argument become positions you can omit from the call site,
// matching consumer typedefs like `TransferPart = [a?, b?, c?, d?]`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What changed so that this claim is now true?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 1155ec691 ("fix(patterns): TFOptionalTuple emits truly optional elements") changed TFOptionalTuple from a recursive conditional type to a homomorphic mapped type.

Before:

type TFOptionalTuple<T extends readonly any[]> = T extends readonly [infer H, ...infer R]
  ? [TypeFromPattern<H> | undefined, ...TFOptionalTuple<R>]
  : [];

Produced [X | undefined, Y | undefined] — each position a union with undefined, not optional. Callers had to pass all N elements with explicit undefined placeholders.

After:

type TFOptionalTuple<T extends readonly any[]> = {
  [K in keyof T]?: TypeFromPattern<T[K]>;
};

Produces [X?, Y?] — truly optional positions callers can omit.

The prior code comment claimed TS couldn't produce [X?, Y?] from a recursive conditional. That's technically true (conditional types can't emit optional positions) but the wrong framing — the fix swaps tools from conditional recursion to a homomorphic mapped type, where the ? modifier attaches to each position rather than the value type. When T is a tuple, { [K in keyof T]?: ... } iterates the tuple indices and preserves tuple-ness; the tuple-ness of the input is load-bearing.

The test assertion at this line was updated in the same commit from [X | undefined, Y | undefined] to [X, Y?, Z?].

Comment on lines +247 to +253
{
const innerShape = M.string();
// A pattern value can be cast to CastedPattern<T> at the type level
const casted = innerShape as unknown as CastedPattern<'agoric1xyz'>;
type T = TypeFromPattern<typeof casted>;
expectType<'agoric1xyz'>(null as unknown as T);
}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems dubious. Why even declare innerShape if we throw away the type? Why use typeof casted when we could use CastedPattern<'agoric1xyz'> instead?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. I've tightened up the test to verify CastedPattern's phantom is optional.

const casted: CastedPattern<'agoric1xyz'> = innerShape;

Comment on lines +250 to 251
setData(val: string) {
expectType<string>(val);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the val: string, the assertion is pretty useless.

@turadg turadg changed the base branch from typescript-6 to master April 14, 2026 23:24
@turadg turadg enabled auto-merge April 14, 2026 23:59
@turadg turadg disabled auto-merge April 15, 2026 00:01
turadg and others added 11 commits April 14, 2026 17:06
Three independent fixes discovered while integrating with Agoric SDK:

1. **pass-style: CopyArray accepts readonly arrays.**

   `CopyArray<T>` was `Array<T>`, rejecting readonly tuples like
   `readonly ["ibc"]`. All passables are hardened at runtime, so the
   type should reflect immutability. Changed to `readonly T[]`. This is
   backward-compatible since `Array<T>` extends `ReadonlyArray<T>`,
   so existing mutable arrays remain assignable, but readonly tuples
   now also satisfy `Passable`.

2. **patterns: M.remotable() default and TFRemotable fallback are `any`.**

   Previously, `M.remotable<T extends Passable = RemotableObject |
   RemotableBrand<any, any>>()` resolved unparameterized remotables to
   a type that wasn't assignable to concrete remotable typedefs (like
   StorageNode in agoric-sdk). The default is now `any`, matching
   `M.promise<T = any>()`.

   We could express the tighter constraint "object with only methods,
   no data" as `Record<PropertyKey, (...args: any[]) => any>`, but
   TypeScript index signatures don't satisfy specific named properties
   (`Record<string, F>` is not assignable to `{ foo: F }`), so it
   doesn't help downstream consumers without forcing casts at every
   use site. `any` is the pragmatic choice; the parameterized form
   `M.remotable<typeof SomeInterfaceGuard>()` still provides precise
   inference when needed.

3. **exo: defineExoClassKit removes `& Methods` from facet constraint.**

   The constraint
     `F extends { [K in keyof GK]: TypeFromInterfaceGuard<GK[K]> & Methods }`
   caused TypeScript to absorb specific facet method names into the
   `string | number | symbol` index signature (`'view' | string`
   collapses to `string`), making `FilteredKeys` return `never` and
   producing `Pick<X, never> = {}`. Result: callers like
   `E(viewCounter).view()` failed with "Property 'view' does not
   exist", because the facet's methods were collapsed to an empty
   record.

   Removing `& Methods` preserves the concrete method names while
   still enforcing guard-method compatibility via
   `TypeFromInterfaceGuard<GK[K]>` alone.

Updated `types.test-d.ts` to assert the new `M.remotable()` resolution
(`any` instead of `RemotableObject | RemotableBrand<any, any>`).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Same issue as the previous defineExoClassKit fix: the `& Methods`
intersection in the M constraint causes TypeScript to absorb specific
method names into the `string | number | symbol` index signature,
making `keyof M` collapse to `PropertyKey` and `FilteredKeys` in
PickCallable return `never`. Result: `Pick<X, never> = {}`, and
callers like `E(creatorFacet).addAsset()` fail with "Property
'addAsset' does not exist".

The single-facet `defineExoClass` and `makeExo` had the same
constraint pattern as `defineExoClassKit`, just less obvious because
single-facet exos don't always trigger the issue. They DO trigger it
when consumed via `E()` (which goes through `RemoteFunctions` →
`PickCallable` → `FilteredKeys`).

Verified that the strict tests in `types-plain-guarded.test-d.ts`
still catch wrong arg/return types and missing methods — the constraint
`M extends TypeFromInterfaceGuard<G>` is sufficient on its own.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
`.rest(P)` matches the rest portion of the args array (as a single
array) against P. Two cases:

- If P infers to an array type (e.g. `M.arrayOf(M.string())` →
  `string[]`), the rest type IS that array — don't wrap.
- If P infers to a non-array (e.g. `M.any()` → `Passable`), each
  individual rest arg matches P, so the rest type is `P[]`.

Previously TFRestArgs always wrapped with `[]`, double-wrapping array
patterns. For example, `M.call().rest(M.arrayOf(M.string()))` inferred
the rest as `string[][]` instead of `string[]`. This affected real
code in agoric-sdk's @agoric/vats nameHub: `.rest(PathShape)` where
PathShape = M.arrayOf(M.string()) was inferring as `string[][]`,
breaking the impl signature `(...path: string[])`.

Added regression tests for both cases.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
`CastedPattern<T>` is a Pattern carrying an unchecked static type
assertion via a phantom property. Like a TypeScript `as` cast, it is
trusted by the type system but unverifiable at runtime — the runtime
pattern check still validates the structural shape it always did, while
T expresses a developer claim about the matched values.

Motivating cases (any of which downstream packages can now express
without restructuring their patterns):

1. **Discriminated unions through structural patterns.** A pattern like
   `{ brand: BrandShape, value: AmountValueShape }` infers structurally
   to the cross-product `{ brand: Brand, value: NatValue | SetValue | ... }`,
   not the discriminated union `Amount = NatAmount | SetAmount | ...`.
   With `CastedPattern<Amount>`, the inferred type IS the union.

2. **Branded / template literal types.** `M.string()` infers as `string`,
   but a guard for an address may want `\`agoric1${string}\``. Casting
   the pattern lets the type carry the brand without changing runtime.

3. **Nominal typedef recovery.** Many Agoric typedefs (StorageNode,
   Connection, Vow<X>) are plain object types whose structural shape
   the inference can't recover from a Matcher. Casting bridges the gap.

`TypeFromPattern` extracts the asserted type when the phantom is set to
a concrete type. The `unknown extends Asserted` check distinguishes a
real cast from an unset phantom (which falls through to the existing
structural inference), so patterns without a cast are unaffected.

The phantom uses a string-constant key rather than `unique symbol` to
avoid declaration-emit issues with downstream packages re-exporting the
type — this is the same approach the deprecated `validatedType` used.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eGuard

When TFRemotable returns Payload directly for non-InterfaceGuard cases,
`Payload = any` causes the conditional to distribute. The true branch
produces a `Simplify<...>` mapped type that doesn't collapse with the
`any` from the false branch — TypeScript shows the structural Passable
union, breaking downstream consumers that expected `any`.

Reverting this branch to `any` matches `M.promise()`'s default. Users
who want to express a specific type should use `CastedPattern<X>`
(which TypeFromPattern now handles via a phantom-property check),
not the unparameterized `M.remotable<X>()` form.

Fixed two regression boundaries (lines 902 and 1058 of types.test-d.ts)
that asserted contradictory things; both now agree the default M.remotable()
resolves to `any`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Restructure the `methodsKit` parameter on both `defineExoClassKit`
overloads from a per-key intersection to an outer-level intersection,
and wrap the `facets` self-reference with `NoInfer<...>`.

The previous form

  methodsKit: { [K in keyof F]: F[K] & ThisType<{ facets: GuardedKit<F>; ... }> }

prevented TypeScript from back-inferring `F[K]` from the argument
because the per-facet intersection with `ThisType<...>` cannot be
cleanly subtracted during inference. As a result, `F` degraded to its
constraint default `Record<FacetName, Methods>`, and consumers of the
returned kit saw

  GuardedKit<Record<string, Methods>, { [x: string]: InterfaceGuard<...> }>

— losing all facet names and method signatures. The new form

  methodsKit: F & ThisType<{ facets: NoInfer<GuardedKit<F>>; ... }>

fixes both halves of the problem:

* Lifting `ThisType` outside the mapped type lets TS match the
  argument shape against `F` directly. Inference latches onto the
  methods literal.

* `NoInfer<GuardedKit<F>>` blocks the `this.facets` self-reference
  from re-introducing a circular inference path that would otherwise
  collapse `F` back to its constraint default.

`ThisType` propagation into nested facet methods is preserved at any
nesting depth (verified in the new regression test).

Add a regression test in `types-plain-unguarded.test-d.ts` covering
the exact shapes that broke in the wild — an empty facet alongside a
populated one, and direct facet access on a returned kit instance —
both reported in agoric-sdk's `packages/orchestration/src/utils/progress.js`
and `packages/portfolio-contract/src/portfolio.exo.ts`.

Impact in the agoric-sdk monorepo:
  yarn typecheck-quick: 293 errors -> 120 errors (-173, -59%)
with zero new errors introduced.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous check `G extends { payload: { argGuard: infer P } }` was
intended to detect `AwaitArgGuard` (whose payload is literally
`{ argGuard: Pattern }`).  However, any matcher whose `Payload` type
parameter happens to be `any` — for example `M.array()` which returns
`MatcherOf<'arrayOf'>` (default Payload `any`) — *also* trivially
satisfies that shape test, because `any extends { argGuard: infer P }`
unifies and `infer P` distributes oddly.  The result was that arg
positions for `M.array()` (and any other matcher with a wide payload)
were inferred as `unknown` instead of `any[]`.

Fix: gate the structural check behind a `[Symbol.toStringTag]:
'guard:awaitArgGuard'` tag check first, mirroring the discrimination
already used for `'guard:rawGuard'`.  This is the canonical TypeScript
pattern for tagged unions: discriminate on the tag rather than on the
payload shape, especially when the payload may be `any`.

Verified by typechecking agoric-sdk's
`packages/orchestration/src/examples/axelar-gmp-account-kit.js` —
`args` in `makeEVMTransactionInvitation(method, args)` is now
correctly inferred as `any[]` instead of `unknown`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Widen the MethodGuard constraint in InterfaceGuard, InterfaceGuardPayload,
MakeInterfaceGuardStrict, and MakeInterfaceGuardGeneral from the bare
`MethodGuard` to `MethodGuard<any, any, any, any, any>` (all type
parameters set to `any`).

When TypeScript contextually types an inline expression like
`M.call().returns(M.promise())` against the constraint
`Record<PropertyKey, MethodGuard>`, the bare `MethodGuard` defaults its
type parameters to their constraints — so `RetGuard` becomes
`SyncValueGuard` and `MatcherOf<'promise', any>`'s `Payload` parameter
drifts from `any` to a non-canonical unknown form
(`void | RawGuardPayload | null`).  TypeScript displays the structural
equivalent of `unknown` as that three-way union but does not recognize
it as `unknown`, so `TypeFromPattern`'s `unknown extends Payload`
guard in the `'promise'` branch fails and the wide payload leaks
through as the inferred return type.

Setting all `MethodGuard` type parameters to `any` in the constraint
removes the contextual narrowing pressure: TypeScript no longer tries
to fit the inline expression into a narrower default, and the
inferred `MatcherOf<'promise', any>` survives with its `any` payload
intact.  The same fix protects every other `MatcherOf<Tag, T>` whose
`T` would otherwise drift through inline expressions in
`M.interface(...)` calls.

This resolves the `void | RawGuardPayload | null` mystery union
documented as XXX tech debt in agoric-sdk's
`packages/vats/src/nameHub.js` and `packages/vats/src/bridge.js`,
and eliminates 3 errors in agoric-sdk's
`packages/fast-usdc-contract/` (`fast-usdc.contract.ts:274`,
`test/contract-setup.ts:323` and `:352`).  Many more errors get
dramatically cleaner messages because their inferred types no longer
include the wide `[x: string]: ... | RawGuardPayload | ...` index
signatures.

Endo's own `lint:types` and `test-d` files remain clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…e, ECallableOrMethods

When `T = any`, the existing distributive conditionals in
`RemoteFunctions<T>`, `PickCallable<T>`, `ECallableOrMethods<T>`, and
`ESendOnlyCallableOrMethods<T>` produce a sprawling, unsimplifiable
display type that includes `Pick<any, string>` and a union of
`(...args: unknown[]) => any` / `(...args: unknown[]) => Promise<any>`
crossed with `EMethods<Required<...>>`.  TypeScript still resolves
property access on the value (since the underlying type is `any`),
but error messages and IDE hovers display the wide form, which is
unhelpful.

Add the standard `0 extends (1 & T)` short-circuit at the top of each
helper so `any` propagates through cleanly.  This matches the pattern
already used in sibling helpers `EAwaitedResult` and `ECallableReturn`.

Defensive change: this does not fix any currently-failing call site
in agoric-sdk because the failing sites all import `heapVowE` from
`@agoric/vow/vat.js`, which has its own fork of these type helpers.
A parallel fix should be applied in agoric-sdk's
`packages/vow/src/E.js`.  This commit improves consumer experience
for any code path that goes through `@endo/far`'s `E`.

Endo's own `lint:types` and `test-d` files remain clean.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The previous public type surface from `@endo/eventual-send`'s
`exports.d.ts` re-exported the headline helpers (`RemoteFunctions`,
`PickCallable`, `LocalRecord`, etc.) but omitted the more granular
ones (`ECallable`, `EMethods`, `EGetters`, `ESendOnlyCallable`,
`ESendOnlyMethods`, `ESendOnlyCallableOrMethods`, `ECallableOrMethods`).

This is fine for direct callers of `E(x)` (whose result type is
already wrapped in the public helpers) but it forces downstream
forks of the E type machinery — like agoric-sdk's
`packages/vow/src/E.js` — to maintain duplicate copies of these
helpers locally.  Promoting them to the public surface lets vow's
fork re-export the byte-equivalent ones via JSDoc and keep only the
helpers whose semantics actually differ (those that unwrap Vows via
`EUnwrap` rather than just Promises via `Awaited`).

No type changes; existing call sites that already imported these via
`@endo/eventual-send/src/E.js` continue to work unchanged.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
turadg and others added 8 commits April 14, 2026 17:06
…se() → PromiseLike

Two related improvements to TypeFromPattern that align inference with the
runtime semantics of patterns:

1. TFOptionalTuple uses a homomorphic mapped type with `?`, producing truly
   optional tuple elements (`[X?, Y?]`) instead of `[X | undefined, Y |
   undefined]`.  An earlier comment claimed this was impossible because
   `Partial<Tuple>` only works on concrete tuples and conditional types
   can't produce optional elements — but TypeScript *does* support
   producing optional elements via `{ [K in keyof T]?: ... }` when `T` is
   a tuple, regardless of whether `T` is generic.  The new form is both
   simpler and structurally correct.

   This unblocks `M.splitArray(req, opt)` whose inferred type now
   matches consumer typedefs like
   `TransferPart = [a?, b?, c?, d?]` instead of forcing every caller to
   pass exactly N elements with explicit `undefined` placeholders.

2. `M.promise()` now infers as `PromiseLike<T>` rather than `Promise<T>`.
   At runtime `M.promise()` checks `passStyleOf === 'promise'`, which is
   duck-typed for any thenable, so accepting `PromiseLike<T>` is the
   honest type.  The previous `Promise<T>` was too narrow — impls
   returning `ERef<X>` (= `PromiseLike<X> | X`) failed to match guards
   declared with `M.promise()`, even though they would have passed the
   runtime check.

Fixes the cascade root in agoric-sdk's
`packages/fast-usdc-contract/src/exos/liquidity-pool.ts`, where
`getPublicTopics` returned `{ poolMetrics: PublicTopic<PoolMetrics> }`
whose `storagePath: ERef<string>` field couldn't satisfy the guard's
inferred `Promise<Passable> | string` shape.  Once the
`liquidity-pool` no-overload error clears, the `LiquidityPoolKit` type
becomes well-formed again, which in turn unblocks the 9 `repay`
guarded-mismatch errors in `test/exos/settler.test.ts`.

Also updates the test-d assertions in `types.test-d.ts` to match the
new behavior:
- `M.promise()` → `PromiseLike<any>` (was `Promise<any>`)
- `M.eref(M.string())` → `string | PromiseLike<any>`
- `M.splitArray([...], [...])` → `[X, Y?, Z?]` (was `[X, Y | undefined, Z | undefined]`)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…kit F constraint

Two coordinated changes that let consumers compare exo class kits across
boundaries (e.g. mock vs real impl) without spurious type mismatches.

1. Guarded<M, G>'s G slot is no longer carried via a function-return
   field, which is invariant under assignment.  Two `Guarded<M, G1>` and
   `Guarded<M, G2>` with structurally-compatible `M` would otherwise
   fail to assign even when only `G` differs.  Now G is split between:
   - `__getInterfaceGuard__?: () => InterfaceGuard | undefined` — the
     runtime accessor, with a wide return that doesn't constrain G;
   - `__interfaceGuard__?(g?: G): void` — a phantom *method* (not a
     field).  Method shorthand syntax gives the parameter bivariant
     treatment under assignment, so the field is structurally compatible
     across any G.  `GuardedMethods<E>` reads the specific G from this
     phantom via `infer`.

2. defineExoClassKit's `F` constraint is widened from
   `{ [K in keyof GK]: TypeFromInterfaceGuard<GK[K]> }` to
   `Record<FacetName, Methods>`.  The narrow form caused TypeScript to
   apply contextual typing from the guard-derived shape *into* the impl
   method signatures inside `methodsKit` — overwriting the JSDoc/TS
   types the implementation author wrote with the guard-derived ones
   (e.g. `(args_0: Passable, args_1: Passable) => any` instead of
   `(sourceTransfer: TransferPart, amounts: AmountKWR) => void`).

   Consumers of the returned kit (e.g. `LiquidityPoolKit['repayer']`)
   would then see the guard-derived shape, which doesn't match real
   impls or test mocks, breaking subtype checks across module
   boundaries.

   The trade-off: we lose the compile-time check that impl methods
   conform to the guard signature.  Runtime conformance is still
   enforced by the guard machinery.

Together, these two changes resolve all 15 `repay` guarded-mismatch
errors in agoric-sdk's
`packages/fast-usdc-contract/test/exos/settler.test.ts`, where a mock
`Guarded<{ repay(t, a): void }>` is passed to a function expecting the
`Guarded<{ repay(t, s): void }, InterfaceGuard<...>>` shape derived
from the real impl.

Updates `types-plain-guarded.test-d.ts` to reflect that kit method
params are now driven by the impl's TS types (annotate explicitly to
get param types in kits), not by guard-driven contextual narrowing.
The `makeExo` and `defineExoClass` overloads still narrow params from
the guard.

Repo error count: 117 → 21 (-96, -82%) in `yarn typecheck-quick`.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…array fallback in TFOr/TFAnd

Three small but impactful fixes to TypeFromPattern's handling of
M.or/M.and and the .returns() default:

1. TFOr and TFAnd now accept arrays, not just tuples.  The previous
   tuple-only form `[infer H, ...infer R]` evaluated to `never` when
   the argument was a homogeneous array like `Object.values(Enum)`,
   silently collapsing downstream types.  Example from agoric-sdk:

     M.or(...Object.values(PendingTxStatus))

   produced `match:or` with payload `string[]` (not a tuple), so
   `TFOr<string[]>` → `never`, and consumers saw
   `{ txHash; status: never }` for `matchAndDequeueSettlement`'s
   return.  The new fallback handles this by returning
   `TypeFromPattern<E>` when the input is a bare array.

2. TFKindMap['undefined'] is now `void` rather than `undefined`.  At
   runtime `M.undefined()` only checks that the value *is*
   `undefined`, which a void-returning impl satisfies trivially (JS
   returns `undefined` when no value is produced).  TypeScript's
   distinction is that a void-returning function may actually return
   any value (callers must ignore it), while an undefined-returning
   function must literally return `undefined`.  `void` is the honest
   return type — it lets guarded method impls use `): void` without
   the guard rejecting them.

   Example from agoric-sdk: in fast-usdc-contract's status-manager,
   guards like `disbursed: M.call(...).returns(M.undefined())`
   previously rejected impls declared `disbursed(...): void` with
   "Type 'void' is not assignable to type 'undefined'".

3. Update test-d assertions in both `patterns` and `exo` to reflect
   the new `void`-based return types for `M.undefined()`,
   `M.call().returns()`, and `M.opt(X)` (which now gives `X | void`
   instead of `X | undefined`).

Combined with the agoric-sdk-side guard tightening (tightening
status-manager's method guards to use `M.string<NobleAddress>()`,
`M.string<CaipChainId>()`, `PendingTxShape` for the return of
`matchAndDequeueSettlement`, and `TypedPattern<...>` casts on
AmountKeywordRecord/destination shapes), this clears the
status-manager `zone.exo` no-overload error and its cascade: 19 repo
errors fixed overall.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…cord fix

Two changes to close the remaining application-level "objectMap generic
collapse" errors in agoric-sdk without resorting to casts:

1. @endo/common/object-map.js gains a new `objectExtendEach` helper:

     export const objectExtendEach: <O, Ex>(
       original: O,
       extendFn: <K extends string & keyof O>(value: O[K], key: K) => Ex,
     ) => { [K in keyof O]: O[K] & Ex }

   It is the correlation-preserving form for the common case of "take
   an object and add a few fields to every value".  The existing
   `objectMap<O, R>` collapses R across all keys to a single inferred
   type, losing the K-specific correlation; `objectExtendEach` splits
   the signature so each returned value is declaratively
   `O[K] & Ex` — TypeScript evaluates `O[K]` per key in the return
   type expression, so the per-key specific value type survives.

   Used in agoric-sdk's `packages/orchestration/tools/contract-tests.ts`
   and `packages/fast-usdc-deploy/src/utils/deploy-config.js` to
   replace `objectMap(ci, v => ({ ...v, chainId: ... }))` patterns
   that previously needed `as unknown as` casts.

2. `TFSplitRecord` in @endo/patterns now treats an empty-record rest
   pattern `M.splitRecord(req, opt, {})` the same as no rest pattern.
   The `{}` is canonically used to mean "refuse unsupported options"
   at runtime, but TypeFromPattern used to emit a literal
   `[key: string]: {}` index signature for it, which:
   - disallows `undefined` values for known keys (since `{}` excludes
     `undefined`, and the index signature applies to all keys), and
   - pollutes consumers with a wildcard that breaks excess-property
     checking on the enclosing object.

   The fix checks `[keyof Rest] extends [never]` and skips emitting
   the index signature in that case.  Non-empty rest patterns are
   unaffected.

   Fixes the `contract-control.contract.js:199` error where
   `self.start({ installation, issuers, privateArgsOverrides })`
   couldn't pass `issuers: IssuerKeywordRecord | undefined` because
   the contextual type had `[x: string]: {}` forbidding undefined.

Endo's own `lint:types` remains clean (modulo the 2 pre-existing
`@ts-expect-error` directives in `packages/exo/test/heap-classes.test.js`).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@turadg turadg enabled auto-merge April 15, 2026 00:06
@turadg turadg merged commit be471a9 into master Apr 15, 2026
26 checks passed
@turadg turadg deleted the ta/remotable branch April 15, 2026 00:13
@kriskowal kriskowal mentioned this pull request Apr 14, 2026
turadg added a commit that referenced this pull request Apr 16, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to master, this PR
will be updated.


# Releases
## @endo/ocapn@1.0.0

### Major Changes

- [#3183](#3183)
[`279c0c4`](279c0c4)
Thanks [@kumavis](https://github.com/kumavis)! - Initial public release
of `@endo/ocapn`. The package is no longer private and is now published
to npm.

Tested against the python test suite from 2026-01-06
<https://github.com/ocapn/ocapn-test-suite/commits/f0273f21c5ee05a28785b51c231535124f28bca9>

### Minor Changes

- [#3172](#3172)
[`6405b36`](6405b36)
Thanks [@turadg](https://github.com/turadg)! - Parameterize CapTP slot
types and improve TypeScript 6 conformance across the OCapN client
surface. Compile-time type changes only; no runtime behavior changes.

### Patch Changes

- Updated dependencies
\[[`f65b000`](f65b000),
[`d1d9625`](d1d9625),
[`88bc2b9`](88bc2b9),
[`e619205`](e619205),
[`43165e5`](43165e5),
[`6ada52b`](6ada52b)]:
    -   @endo/eventual-send@1.5.0
    -   @endo/promise-kit@1.2.1
    -   @endo/pass-style@1.8.0
    -   @endo/marshal@1.9.1
    -   @endo/harden@1.1.0
    -   @endo/nat@5.2.0

## ses@2.0.0

### Major Changes

- [#3153](#3153)
[`e619205`](e619205)
Thanks [@erights](https://github.com/erights)! - # Plug NaN Side-channel

The JavaScript language can leak the bit encoding of a NaN via shared
TypedArray views of an common ArrayBuffer. Although the JavaScript
language has only one NaN value, the underlying IEEE 754
double-precision floating-point representation has many different bit
patterns that represent NaN. This can be exploited as a side-channel to
leak information. This actually happens on some platforms such as v8.

@ChALkeR explains at
<tc39/ecma262#758 (comment)> that
the behavior of this side-channel on v8. At
<https://junk.rray.org/poc/nani.html> he demonstrates it, and it indeed
even worse than I expected.

    To plug this side-channel, we make two coordinated changes.

- We stop listing the `Float*Array` constructors as universal globals.
This prevents them from being implicitly endowed to created
compartments, because they are not harmless. However, we still keep them
on the start compartment (the original global), consider them
intrinsics, and still repair and harden them on `lockdown()`. Thus, they
can be explicitly endowed to child compartments at the price of enabling
code in that compartment to read the side-channel.
- On `lockdown()`, we repair the `DataView.prototype.setFloat*` methods
so that they only write canonical NaNs into the underlying ArrayBuffer.

The `@endo.marshal` package's `encodePassable` encodings need to obtain
the bit representation of floating point values. It had used
`Float64Array` for that. However, sometimes the `@endo/marshal` package
is evaluated in a created compartment that would now lack that
constructor. (This reevaluation typically occurs when bundling bundles
in that package.) So instead, `encodePassable` now uses the `DataView`
methods which are now safe.

### Minor Changes

- [#3129](#3129)
[`a675d8e`](a675d8e)
Thanks [@erights](https://github.com/erights)! - `overrideTaming:
'moderate'` includes `overrideTaming: 'min'`.

Previously `overrideTaming: 'min'` correctly enabled
`Iterator.prototype.constructor` to be overridden by assignment, but due
to an oversight, `overrideTaming: 'moderate'` did not. Now it does.

To make such mistakes less likely, this PR also adopts a style where all
records within larger enablements triple-dot the corresponding record
from a smaller enablement, if present.

## @endo/bundle-source@4.3.0

### Minor Changes

- [#3180](#3180)
[`7f7ae8e`](7f7ae8e)
Thanks [@turadg](https://github.com/turadg)! - `BundleCache.load()` is
now generic on the `format` option:

- Omitted (default) → `Promise<BundleSourceResult<'endoZipBase64'>>`
    -   Literal format → `Promise<BundleSourceResult<format>>`
- Runtime-typed `ModuleFormat` →
`Promise<BundleSourceResult<ModuleFormat>>`

Previously `load()` returned `Promise<unknown>`, requiring callers to
assert the bundle shape.

### Patch Changes

- Updated dependencies
\[[`154102b`](154102b),
[`2b674ca`](2b674ca),
[`d1d9625`](d1d9625),
[`b4820dc`](b4820dc),
[`acbacba`](acbacba),
[`cdb6eae`](cdb6eae),
[`6ada52b`](6ada52b),
[`6ad084a`](6ad084a),
[`1cd1246`](1cd1246)]:
    -   @endo/compartment-mapper@2.1.0
    -   @endo/promise-kit@1.2.1
    -   @endo/harden@1.1.0

## @endo/common@1.4.0

### Minor Changes

- [#3172](#3172)
[`98c89b7`](98c89b7)
Thanks [@turadg](https://github.com/turadg)! - Add `objectExtendEach`
helper for merging a sequence of objects into an accumulator, with
precise TypeScript inference of the resulting intersection type.

### Patch Changes

- Updated dependencies
\[[`f65b000`](f65b000),
[`d1d9625`](d1d9625)]:
    -   @endo/eventual-send@1.5.0
    -   @endo/promise-kit@1.2.1
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0

## @endo/compartment-mapper@2.1.0

### Minor Changes

- [#3132](#3132)
[`b4820dc`](b4820dc)
Thanks [@boneskull](https://github.com/boneskull)! - Expose
`_redundantPreloadHook` option in `captureFromMap()`, which will be
called for each item in the `_preload` array that was already indirectly
loaded via the entry `Compartment`.

Fixes a bug in the type of `_preload` option, which now allows for mixed
arrays.

Fixes a bug in the preloader, which was not exhaustively checking if a
non-entry module was already loaded via the entry `Compartment`.

- [#3048](#3048)
[`6ad084a`](6ad084a)
Thanks [@kriskowal](https://github.com/kriskowal)! - Add support for
Node.js subpath pattern replacement in `package.json` `exports` and
`imports` fields. Patterns like `"./features/*.js":
"./src/features/*.js"` and `"#internal/*.js": "./lib/*.js"` are now
resolved at link time using prefix/suffix string matching with
specificity ordering. Null-target patterns exclude matching specifiers.
Conditional pattern values are resolved through the standard
condition-matching rules. Patterns are expanded to concrete module
entries during archiving.

### Patch Changes

- [#3111](#3111)
[`154102b`](154102b)
Thanks [@boneskull](https://github.com/boneskull)! - Fix type of
`PackageDataHook.packageData` which now correctly allows `$root$` as a
key.

- [#3182](#3182)
[`2b674ca`](2b674ca)
Thanks [@kriskowal](https://github.com/kriskowal)! - Cull
underscore-prefixed internal properties (like `__createdBy`) from
serialized compartment maps in archives. The compartment map validator
    now also ignores underscore-prefixed properties when checking for
    extraneous fields.

- [#3173](#3173)
[`acbacba`](acbacba)
Thanks [@boneskull](https://github.com/boneskull)! - Fixes potential
issue wherein a canonical name may be computed incorrectly. Includes
performance improvements.

- [#3157](#3157)
[`cdb6eae`](cdb6eae)
Thanks [@boneskull](https://github.com/boneskull)! - Dramatically
improve performance of canonical name (shortest path) computation in
`mapNodeModules()`.

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- [#3115](#3115)
[`1cd1246`](1cd1246)
Thanks [@boneskull](https://github.com/boneskull)! - Remove unused
"error" `ModuleSourceHookModuleSource` type.

- Updated dependencies
\[[`e619205`](e619205),
[`6ada52b`](6ada52b),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0
    -   @endo/module-source@1.4.1

## @endo/eventual-send@1.5.0

### Minor Changes

- [#3172](#3172)
[`f65b000`](f65b000)
Thanks [@turadg](https://github.com/turadg)! - Improve `E()` type
inference and publicly export method-projection helpers.

- `RemoteFunctions`, `PickCallable`, and `ECallableOrMethods` now
short-circuit on `any`, preventing `E(anyValue)` from collapsing to an
unusable type.
- `EMethods`, `EGetters`, and related helpers are now part of the public
type surface, so downstream packages can name the projected shapes `E()`
produces.

    Compile-time type changes only; no runtime behavior changes.

### Patch Changes

-   Updated dependencies \[]:
    -   @endo/harden@1.1.0

## @endo/exo@1.7.0

### Minor Changes

- [#3172](#3172)
[`88bc2b9`](88bc2b9)
Thanks [@turadg](https://github.com/turadg)! - Improve TypeScript
inference for patterns, exo, and pass-style. These are compile-time type
changes only; no runtime behavior changes.

- **pass-style**: `CopyArray<T>` is now `readonly T[]` so readonly
tuples (e.g. `readonly ['ibc']`) satisfy `Passable`. Backward-compatible
because `T[]` still extends `readonly T[]`.
- **patterns**: `M.remotable()` defaults to `any` (matching
`M.promise()`), so unparameterized remotables are assignable to concrete
remotable typedefs. The parameterized form `M.remotable<typeof
SomeInterfaceGuard>()` still yields precise inference.
- **patterns**: `TFRemotable` returns `any` (not `Payload`) for
non-`InterfaceGuard` arguments.
- **patterns**: `TFOr` handles array-of-patterns and falls back through
`TFAnd`; `M.undefined()` maps to `void`.
- **patterns**: `TFOptionalTuple` emits truly optional elements;
`M.promise()` maps to `PromiseLike`.
- **patterns**: `TFSplitRecord` handles the empty-rest case correctly.
    -   **patterns**: `TFRestArgs` unwraps array patterns.
- **patterns**: `TypeFromArgGuard` discriminates by `toStringTag`, not
structural shape.
- **patterns**: `MatcherOf` payload is preserved through
`InterfaceGuard`.
- **patterns**: new `CastedPattern<T>` for unchecked type assertions in
pattern position.
- **exo**: `defineExoClass`, `defineExoClassKit`, and `makeExo` no
longer intersect facet constraints with `& Methods`. The previous
constraint collapsed specific facet keys into the `string | number |
symbol` index signature, making `FilteredKeys` return `never` and
erasing facet method inference (`Pick<X, never> = {}`).
- **exo**: `Guarded<M, G>` is now structurally compatible across `G`,
and the kit `F` constraint is widened.
- **exo**: `defineExoClassKit` preserves facet inference when no guard
is supplied.

TypeScript consumers that were working around the previous inference
gaps with casts may be able to remove those casts. Downstream code that
depended on the narrower `CopyArray<T> = T[]` or the previous
`M.remotable()` default may need minor adjustments.

- [#3133](#3133)
[`9111b4e`](9111b4e)
Thanks [@turadg](https://github.com/turadg)! - feat: infer TypeScript
types from pattern guards

- `TypeFromPattern<P>` — infer static types from any pattern matcher
- `TypeFromMethodGuard<G>` — infer function signatures from `M.call()` /
`M.callWhen()` guards
- `TypeFromInterfaceGuard<G>` — infer method records from interface
guard definitions
- `M.remotable<typeof Guard>()` — facet-isolated return types in exo
kits
- `M.infer<typeof pattern>` — namespace shorthand analogous to `z.infer`
- `matches` and `mustMatch` now narrow the specimen type via type
predicates
- `makeExo`, `defineExoClass`, and `defineExoClassKit` enforce method
signatures against guards at compile time

These are compile-time type changes only; there are no runtime
behavioral changes.
Existing TypeScript consumers may see new type errors where method
signatures diverge from their guards.

### Patch Changes

- Updated dependencies
\[[`8195a5a`](8195a5a),
[`98c89b7`](98c89b7),
[`f65b000`](f65b000),
[`88bc2b9`](88bc2b9),
[`9111b4e`](9111b4e),
[`43165e5`](43165e5),
[`df84eea`](df84eea),
[`6ada52b`](6ada52b)]:
    -   @endo/patterns@1.9.0
    -   @endo/common@1.4.0
    -   @endo/eventual-send@1.5.0
    -   @endo/pass-style@1.8.0
    -   @endo/errors@1.3.1
    -   @endo/far@1.1.14
    -   @endo/harden@1.1.0

## @endo/pass-style@1.8.0

### Minor Changes

- [#3172](#3172)
[`88bc2b9`](88bc2b9)
Thanks [@turadg](https://github.com/turadg)! - Improve TypeScript
inference for patterns, exo, and pass-style. These are compile-time type
changes only; no runtime behavior changes.

- **pass-style**: `CopyArray<T>` is now `readonly T[]` so readonly
tuples (e.g. `readonly ['ibc']`) satisfy `Passable`. Backward-compatible
because `T[]` still extends `readonly T[]`.
- **patterns**: `M.remotable()` defaults to `any` (matching
`M.promise()`), so unparameterized remotables are assignable to concrete
remotable typedefs. The parameterized form `M.remotable<typeof
SomeInterfaceGuard>()` still yields precise inference.
- **patterns**: `TFRemotable` returns `any` (not `Payload`) for
non-`InterfaceGuard` arguments.
- **patterns**: `TFOr` handles array-of-patterns and falls back through
`TFAnd`; `M.undefined()` maps to `void`.
- **patterns**: `TFOptionalTuple` emits truly optional elements;
`M.promise()` maps to `PromiseLike`.
- **patterns**: `TFSplitRecord` handles the empty-rest case correctly.
    -   **patterns**: `TFRestArgs` unwraps array patterns.
- **patterns**: `TypeFromArgGuard` discriminates by `toStringTag`, not
structural shape.
- **patterns**: `MatcherOf` payload is preserved through
`InterfaceGuard`.
- **patterns**: new `CastedPattern<T>` for unchecked type assertions in
pattern position.
- **exo**: `defineExoClass`, `defineExoClassKit`, and `makeExo` no
longer intersect facet constraints with `& Methods`. The previous
constraint collapsed specific facet keys into the `string | number |
symbol` index signature, making `FilteredKeys` return `never` and
erasing facet method inference (`Pick<X, never> = {}`).
- **exo**: `Guarded<M, G>` is now structurally compatible across `G`,
and the kit `F` constraint is widened.
- **exo**: `defineExoClassKit` preserves facet inference when no guard
is supplied.

TypeScript consumers that were working around the previous inference
gaps with casts may be able to remove those casts. Downstream code that
depended on the narrower `CopyArray<T> = T[]` or the previous
`M.remotable()` default may need minor adjustments.

- [#3184](#3184)
[`43165e5`](43165e5)
Thanks [@turadg](https://github.com/turadg)! - Unblock TypeScript
declaration emit in downstream packages that structurally expose
`PassStyled`/`Container` types. Compile-time type changes only; no
runtime behavior changes.

- `PASS_STYLE` is now typed as the string-literal `'Symbol(passStyle)'`
rather than `unique symbol`. The runtime value is unchanged (still
`Symbol.for('passStyle')`), and computed-key indexing like
`obj[PASS_STYLE]` continues to work because JS computed keys accept any
value. This removes TS4023 / TS9006 errors in consumers whose inferred
types structurally contain `[PASS_STYLE]` (via `PassStyled`,
`ExtractStyle`, object spread of a `PassStyled`, etc.). A `unique
symbol` is only nameable via its original declaration module, which
consumers have no reason to import; a string-literal type has no such
nameability requirement.
- `CopyArrayInterface`, `CopyRecordInterface`, and `CopyTaggedInterface`
are now exported, so downstream `.d.ts` emit can name them when they
appear through structural expansion of `Passable`/`Container`.
- The `PassStyleOf` array overload is widened from `(p: any[]) =>
'copyArray'` to `(p: readonly any[]) => 'copyArray'`, so `as const`
tuples and `readonly T[]` values classify as `'copyArray'`. This aligns
the classifier with `CopyArray<T>`, which is already `readonly T[]`.
Backward-compatible because `T[]` still extends `readonly T[]`.

Obviates the `@endo/pass-style` patch that agoric-sdk has been carrying
in `.yarn/patches/`.

TypeScript consumers that relied on `typeof PASS_STYLE` being `unique
symbol` (e.g. annotating a value as `symbol` from `PASS_STYLE`) will
need minor adjustments — widen the annotation to `symbol | string`, or
cast via `unknown`.

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- Updated dependencies
\[[`98c89b7`](98c89b7),
[`f65b000`](f65b000),
[`d1d9625`](d1d9625)]:
    -   @endo/common@1.4.0
    -   @endo/eventual-send@1.5.0
    -   @endo/promise-kit@1.2.1
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0

## @endo/patterns@1.9.0

### Minor Changes

- [#3067](#3067)
[`8195a5a`](8195a5a)
Thanks [@gibson042](https://github.com/gibson042)! - - Updates
`containerHasSplit` to consider copyArray elements in forward order,
    better aligning with intuition.

- [#3172](#3172)
[`88bc2b9`](88bc2b9)
Thanks [@turadg](https://github.com/turadg)! - Improve TypeScript
inference for patterns, exo, and pass-style. These are compile-time type
changes only; no runtime behavior changes.

- **pass-style**: `CopyArray<T>` is now `readonly T[]` so readonly
tuples (e.g. `readonly ['ibc']`) satisfy `Passable`. Backward-compatible
because `T[]` still extends `readonly T[]`.
- **patterns**: `M.remotable()` defaults to `any` (matching
`M.promise()`), so unparameterized remotables are assignable to concrete
remotable typedefs. The parameterized form `M.remotable<typeof
SomeInterfaceGuard>()` still yields precise inference.
- **patterns**: `TFRemotable` returns `any` (not `Payload`) for
non-`InterfaceGuard` arguments.
- **patterns**: `TFOr` handles array-of-patterns and falls back through
`TFAnd`; `M.undefined()` maps to `void`.
- **patterns**: `TFOptionalTuple` emits truly optional elements;
`M.promise()` maps to `PromiseLike`.
- **patterns**: `TFSplitRecord` handles the empty-rest case correctly.
    -   **patterns**: `TFRestArgs` unwraps array patterns.
- **patterns**: `TypeFromArgGuard` discriminates by `toStringTag`, not
structural shape.
- **patterns**: `MatcherOf` payload is preserved through
`InterfaceGuard`.
- **patterns**: new `CastedPattern<T>` for unchecked type assertions in
pattern position.
- **exo**: `defineExoClass`, `defineExoClassKit`, and `makeExo` no
longer intersect facet constraints with `& Methods`. The previous
constraint collapsed specific facet keys into the `string | number |
symbol` index signature, making `FilteredKeys` return `never` and
erasing facet method inference (`Pick<X, never> = {}`).
- **exo**: `Guarded<M, G>` is now structurally compatible across `G`,
and the kit `F` constraint is widened.
- **exo**: `defineExoClassKit` preserves facet inference when no guard
is supplied.

TypeScript consumers that were working around the previous inference
gaps with casts may be able to remove those casts. Downstream code that
depended on the narrower `CopyArray<T> = T[]` or the previous
`M.remotable()` default may need minor adjustments.

- [#3133](#3133)
[`9111b4e`](9111b4e)
Thanks [@turadg](https://github.com/turadg)! - feat: infer TypeScript
types from pattern guards

- `TypeFromPattern<P>` — infer static types from any pattern matcher
- `TypeFromMethodGuard<G>` — infer function signatures from `M.call()` /
`M.callWhen()` guards
- `TypeFromInterfaceGuard<G>` — infer method records from interface
guard definitions
- `M.remotable<typeof Guard>()` — facet-isolated return types in exo
kits
- `M.infer<typeof pattern>` — namespace shorthand analogous to `z.infer`
- `matches` and `mustMatch` now narrow the specimen type via type
predicates
- `makeExo`, `defineExoClass`, and `defineExoClassKit` enforce method
signatures against guards at compile time

These are compile-time type changes only; there are no runtime
behavioral changes.
Existing TypeScript consumers may see new type errors where method
signatures diverge from their guards.

- [#3133](#3133)
[`df84eea`](df84eea)
Thanks [@turadg](https://github.com/turadg)! - Add optional `label`
parameter to `M.promise()`, aligning its signature
    with `M.remotable(label?)`. When a label is provided, runtime error
messages include it for diagnostics (e.g., "Must be a promise Foo, not
    remotable").

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- Updated dependencies
\[[`98c89b7`](98c89b7),
[`f65b000`](f65b000),
[`88bc2b9`](88bc2b9),
[`e619205`](e619205),
[`43165e5`](43165e5),
[`6ada52b`](6ada52b)]:
    -   @endo/common@1.4.0
    -   @endo/eventual-send@1.5.0
    -   @endo/pass-style@1.8.0
    -   @endo/marshal@1.9.1
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0

## @endo/check-bundle@1.1.1

### Patch Changes

- [#3182](#3182)
[`2b674ca`](2b674ca)
Thanks [@kriskowal](https://github.com/kriskowal)! - Cull
underscore-prefixed internal properties (like `__createdBy`) from
serialized compartment maps in archives. The compartment map validator
    now also ignores underscore-prefixed properties when checking for
    extraneous fields.
- Updated dependencies
\[[`154102b`](154102b),
[`2b674ca`](2b674ca),
[`b4820dc`](b4820dc),
[`acbacba`](acbacba),
[`cdb6eae`](cdb6eae),
[`6ada52b`](6ada52b),
[`6ad084a`](6ad084a),
[`1cd1246`](1cd1246)]:
    -   @endo/compartment-mapper@2.1.0
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0

## @endo/errors@1.3.1

### Patch Changes

- Updated dependencies
\[[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0
    -   @endo/harden@1.1.0

## @endo/import-bundle@1.6.1

### Patch Changes

- Updated dependencies
\[[`154102b`](154102b),
[`2b674ca`](2b674ca),
[`b4820dc`](b4820dc),
[`acbacba`](acbacba),
[`e619205`](e619205),
[`cdb6eae`](cdb6eae),
[`6ada52b`](6ada52b),
[`6ad084a`](6ad084a),
[`1cd1246`](1cd1246),
[`a675d8e`](a675d8e)]:
    -   @endo/compartment-mapper@2.1.0
    -   ses@2.0.0
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0

## @endo/lockdown@1.0.19

### Patch Changes

- Updated dependencies
\[[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0

## @endo/lp32@1.2.1

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

-   Updated dependencies \[]:
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0
    -   @endo/stream@1.3.1

## @endo/marshal@1.9.1

### Patch Changes

- [#3153](#3153)
[`e619205`](e619205)
Thanks [@erights](https://github.com/erights)! - # Plug NaN Side-channel

The JavaScript language can leak the bit encoding of a NaN via shared
TypedArray views of an common ArrayBuffer. Although the JavaScript
language has only one NaN value, the underlying IEEE 754
double-precision floating-point representation has many different bit
patterns that represent NaN. This can be exploited as a side-channel to
leak information. This actually happens on some platforms such as v8.

@ChALkeR explains at
<tc39/ecma262#758 (comment)> that
the behavior of this side-channel on v8. At
<https://junk.rray.org/poc/nani.html> he demonstrates it, and it indeed
even worse than I expected.

    To plug this side-channel, we make two coordinated changes.

- We stop listing the `Float*Array` constructors as universal globals.
This prevents them from being implicitly endowed to created
compartments, because they are not harmless. However, we still keep them
on the start compartment (the original global), consider them
intrinsics, and still repair and harden them on `lockdown()`. Thus, they
can be explicitly endowed to child compartments at the price of enabling
code in that compartment to read the side-channel.
- On `lockdown()`, we repair the `DataView.prototype.setFloat*` methods
so that they only write canonical NaNs into the underlying ArrayBuffer.

The `@endo.marshal` package's `encodePassable` encodings need to obtain
the bit representation of floating point values. It had used
`Float64Array` for that. However, sometimes the `@endo/marshal` package
is evaluated in a created compartment that would now lack that
constructor. (This reevaluation typically occurs when bundling bundles
in that package.) So instead, `encodePassable` now uses the `DataView`
methods which are now safe.

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- Updated dependencies
\[[`98c89b7`](98c89b7),
[`f65b000`](f65b000),
[`88bc2b9`](88bc2b9),
[`43165e5`](43165e5),
[`6ada52b`](6ada52b)]:
    -   @endo/common@1.4.0
    -   @endo/eventual-send@1.5.0
    -   @endo/pass-style@1.8.0
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0
    -   @endo/nat@5.2.0

## @endo/memoize@1.2.1

### Patch Changes

- [#3107](#3107)
[`05cdb5f`](05cdb5f)
Thanks [@erights](https://github.com/erights)! - `@endo/memoize` no
longer depends on `ses`, just `@endo/harden`

-   Updated dependencies \[]:
    -   @endo/harden@1.1.0

## @endo/module-source@1.4.1

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- Updated dependencies
\[[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0

## @endo/netstring@1.1.1

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

- Updated dependencies
\[[`d1d9625`](d1d9625)]:
    -   @endo/promise-kit@1.2.1
    -   @endo/harden@1.1.0
    -   @endo/stream@1.3.1

## @endo/promise-kit@1.2.1

### Patch Changes

- [#3108](#3108)
[`d1d9625`](d1d9625)
Thanks [@erights](https://github.com/erights)! - `@endo/promise-kit` no
longer depends on `ses`, just `@endo/harden`

-   Updated dependencies \[]:
    -   @endo/harden@1.1.0

## @endo/ses-ava@1.4.1

### Patch Changes

- Updated dependencies
\[[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0
    -   @endo/harden@1.1.0

## @endo/stream@1.3.1

### Patch Changes

- Updated dependencies
\[[`f65b000`](f65b000),
[`d1d9625`](d1d9625),
[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   @endo/eventual-send@1.5.0
    -   @endo/promise-kit@1.2.1
    -   ses@2.0.0
    -   @endo/harden@1.1.0

## @endo/stream-node@1.2.1

### Patch Changes

- [#3127](#3127)
[`6ada52b`](6ada52b)
Thanks [@turadg](https://github.com/turadg)! - Remove stale runtime
dependencies from package manifests.

-   Updated dependencies \[]:
    -   @endo/errors@1.3.1
    -   @endo/harden@1.1.0
    -   @endo/stream@1.3.1

## @endo/daemon@2.5.3

### Patch Changes

- Updated dependencies
\[[`8195a5a`](8195a5a),
[`154102b`](154102b),
[`2b674ca`](2b674ca),
[`f65b000`](f65b000),
[`d1d9625`](d1d9625),
[`b4820dc`](b4820dc),
[`88bc2b9`](88bc2b9),
[`9111b4e`](9111b4e),
[`acbacba`](acbacba),
[`e619205`](e619205),
[`df84eea`](df84eea),
[`cdb6eae`](cdb6eae),
[`6ada52b`](6ada52b),
[`6ad084a`](6ad084a),
[`1cd1246`](1cd1246),
[`a675d8e`](a675d8e)]:
    -   @endo/patterns@1.9.0
    -   @endo/compartment-mapper@2.1.0
    -   @endo/eventual-send@1.5.0
    -   @endo/promise-kit@1.2.1
    -   @endo/exo@1.7.0
    -   ses@2.0.0
    -   @endo/marshal@1.9.1
    -   @endo/netstring@1.1.1
    -   @endo/stream-node@1.2.1
    -   @endo/captp@4.5.0
    -   @endo/errors@1.3.1
    -   @endo/far@1.1.14
    -   @endo/harden@1.1.0
    -   @endo/import-bundle@1.6.1
    -   @endo/stream@1.3.1

## @endo/stream-types-test@1.0.19

### Patch Changes

- Updated dependencies
\[[`e619205`](e619205),
[`a675d8e`](a675d8e)]:
    -   ses@2.0.0
    -   @endo/nat@5.2.0
    -   @endo/stream@1.3.1

## @endo/test262-runner@0.1.50

### Patch Changes

- Updated dependencies
\[[`154102b`](154102b),
[`2b674ca`](2b674ca),
[`b4820dc`](b4820dc),
[`acbacba`](acbacba),
[`e619205`](e619205),
[`cdb6eae`](cdb6eae),
[`6ada52b`](6ada52b),
[`6ad084a`](6ad084a),
[`1cd1246`](1cd1246),
[`a675d8e`](a675d8e)]:
    -   @endo/compartment-mapper@2.1.0
    -   ses@2.0.0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants