Skip to content

feat(compartment-mapper): Import and export subpath patterns#3048

Merged
kriskowal merged 8 commits intomasterfrom
kriskowal-subpath-pattern-replacement
Apr 15, 2026
Merged

feat(compartment-mapper): Import and export subpath patterns#3048
kriskowal merged 8 commits intomasterfrom
kriskowal-subpath-pattern-replacement

Conversation

@kriskowal
Copy link
Copy Markdown
Member

@kriskowal kriskowal commented Jan 9, 2026

Closes: #2897

Description

Adds support for Node.js subpath pattern replacement in package.json exports and imports fields to the compartment-mapper. This enables patterns like:

{
  "exports": {
    "./features/*.js": "./src/features/*.js"
  },
  "imports": {
    "#internal/*.js": "./lib/*.js"
  }
}

The implementation matches Node.js semantics where * is a string replacement token that matches any substring, including across / path separators. Patterns are matched by specificity: the pattern with the longest matching prefix wins, and exact entries always take precedence over wildcard patterns.

Security Considerations

Pattern-matched module imports go through the same policy enforcement (enforcePolicyByModule) as other module resolutions. Cross-compartment patterns (from dependency exports) resolve within the dependency's compartment, maintaining compartment isolation. The prefix/suffix string matching approach avoids regex-based matching, eliminating potential ReDoS concerns.

Scaling Considerations

Pattern matching is O(p) where p is the number of wildcard patterns, sorted by prefix length for specificity. Exact entries are checked first via a Map lookup. Results are cached via write-back to moduleDescriptors, so each specifier is matched at most once.

Documentation Considerations

Users can now use wildcard patterns in their package.json exports and imports fields when using compartment-mapper. The patterns follow Node.js subpath pattern semantics:

  • * matches any substring, including across / separators
  • Exact entries take precedence over wildcard patterns
  • Longer prefix wins when multiple patterns match
  • Null targets (null values) exclude subpaths from resolution
  • Conditional pattern values are resolved through the same condition-matching rules as non-pattern exports
  • Globstar (**) patterns are silently ignored (matching Node.js behavior)
  • Array fallback values are deliberately not supported (see design doc for rationale)
  • Pattern and replacement must have matching wildcard counts

Testing Considerations

  • 13 unit tests cover the pattern matcher: exact match, wildcard matching, cross-/ matching, specificity ordering, #-imports patterns, null-target exclusion, error cases (globstar rejection, wildcard count mismatch), and various input formats (tuples, PatternDescriptor array, record object)
  • Scaffold integration tests verify the full pipeline through loadLocation, importLocation, mapNodeModules, makeArchive, parseArchive, writeArchive, loadArchive, importArchive
  • Node.js parity tests run the same fixtures under plain Node.js, ensuring behavioral equivalence by construction. Assertions are shared via _subpath-patterns-assertions.js.
  • User-specified conditions tested via ses-ava with --conditions=blue-moon to verify the correct branch is selected by both Node.js and the Compartment Mapper
  • Policy enforcement tested: pattern-matched imports allowed when package is permitted, rejected when not
  • Archive stripping tested: inspects compartment-map.json in archive and asserts no compartment has a patterns property
  • Tests verify that patterns work correctly through archiving (patterns are expanded to concrete module entries)

Compatibility Considerations

This is a purely additive feature. Existing packages without wildcard patterns are unaffected. The patterns field is only added to compartment descriptors when patterns exist (using conditional spread), so existing snapshot tests pass without modification.

Upgrade Considerations

No breaking changes. Packages can start using wildcard patterns in exports/imports immediately after upgrading to a version with this feature.

@kriskowal kriskowal requested a review from boneskull January 9, 2026 07:01
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.

No real concerns here. Not even nits, really

Comment thread packages/compartment-mapper/src/types/node-modules.ts Outdated
Comment thread packages/compartment-mapper/src/types/pattern-replacement.ts
Comment thread packages/compartment-mapper/src/infer-exports.js Outdated
Comment thread packages/compartment-mapper/src/infer-exports.js
Comment thread packages/compartment-mapper/src/infer-exports.js Outdated
* @param {string} segment
* @returns {boolean}
*/
const hasWildcard = segment => segment.includes(WILDCARD);
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.

(could) Refactor and share with infer-exports.js

return patternSegment === specifierSegment ? '' : null;
}

const wildcardIndex = patternSegment.indexOf(WILDCARD);
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.

(could) if we're able to assert here, I'd probably want to assert that wildcardIndex is a non-negative integer

`Globstar (**) patterns are not supported in pattern: "${pattern}"`,
);
}
if (replacement.includes(GLOBSTAR)) {
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.

(could) hasGlobstar()

Comment on lines +13 to +14
t.is(node.value, null);
t.deepEqual(Object.keys(node.children), []);
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.

(could) refactor to t.like(node, {value: null, children: []}) assuming it works the way I think it should

});

test('assertMatchingWildcardCount - throws for mismatched counts', t => {
const error = t.throws(() => assertMatchingWildcardCount('./*/a/*', './*'));
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.

(complaining) t.throws() is weaksauce.

expect(
  () => assertMatchingWildcardCount('./*/a/*', './*'),
  'to throw',
  {
    message: expect.it(
      'to match', /wildcard count mismatch/i,
      'and', 'to match', /2/,
      'and', 'to match', /1/
    )
  }
);

(imperative) feel the power of BUPKIS

@kriskowal kriskowal force-pushed the kriskowal-subpath-pattern-replacement branch from e72403c to fca6c85 Compare March 22, 2026 06:39
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 22, 2026

🦋 Changeset detected

Latest commit: 7a9dd33

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

This PR includes changesets to release 7 packages
Name Type
@endo/compartment-mapper Minor
@endo/bundle-source Patch
@endo/check-bundle Patch
@endo/daemon Patch
@endo/import-bundle Patch
@endo/test262-runner Patch
@endo/cli 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

@kriskowal kriskowal force-pushed the kriskowal-subpath-pattern-replacement branch 3 times, most recently from df71dc8 to 122ea31 Compare March 23, 2026 04:35
@kriskowal kriskowal requested a review from turadg March 23, 2026 04:36
@kriskowal kriskowal marked this pull request as ready for review March 23, 2026 04:37
@kriskowal kriskowal force-pushed the kriskowal-subpath-pattern-replacement branch 2 times, most recently from 8f8db1e to e9d5c73 Compare March 23, 2026 04:51
@boneskull boneskull added the enhancement New feature or request label Mar 24, 2026
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.

See suggested fix to the conditional in interpretImports. Once this is addressed I'll approve.

Otherwise, just a bunch of questions and suggestions.

Comment thread packages/compartment-mapper/designs/subpath-pattern-replacement.md
* `*` matches any substring including `/` (Node.js semantics).
* Stripped during digest/archiving - expanded patterns become concrete module entries.
*/
patterns?: PatternDescriptor[];
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.

Suggested change
patterns?: PatternDescriptor[];
patterns?: Array<PatternDescriptor>;

I'm pretty sure we're almost exclusively using this form.

Comment thread packages/compartment-mapper/src/types/node-modules.ts
path: never;
retained: never;
scopes: never;
patterns: never;
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 appears redundant, since this field does not appear in CompartmentMapDescriptor. Its presence in a DigestedCompartmentDescriptor should cause an error, even without the above addition.

Suggested change
patterns: never;

Comment thread packages/compartment-mapper/src/types/pattern-replacement.ts
Comment on lines +108 to +121
const wildcardIndex = pattern.indexOf('*');
if (wildcardIndex === -1) {
exactEntries.set(pattern, { replacement: null, compartment });
} else {
const prefix = pattern.slice(0, wildcardIndex);
const suffix = pattern.slice(wildcardIndex + 1);
wildcardEntries.push({
prefix,
suffix,
replacementPrefix: null,
replacementSuffix: null,
compartment,
});
}
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.

(could) split out into function, and L138-L150 as well


// Sort wildcard entries by prefix length descending for specificity.
// Node.js selects the pattern with the longest matching prefix.
wildcardEntries.sort((a, b) => b.prefix.length - a.prefix.length);
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.

I'm gonna guess wildcardEntries doesn't get big enough to start worrying about incurring another loop over it.

Comment thread packages/compartment-mapper/src/pattern-replacement.js
Comment thread CONTRIBUTING.md
Copy link
Copy Markdown
Member

@turadg turadg left a comment

Choose a reason for hiding this comment

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

I took the liberty of letting Codex find and fix a Node parity issue, and pushing it.

With that I approve of HEAD. I assume you'll squash merge.

@kriskowal kriskowal force-pushed the kriskowal-subpath-pattern-replacement branch from 3d7aac6 to e9d5c73 Compare April 11, 2026 06:14
kriskowal and others added 7 commits April 15, 2026 07:43
Applies boneskull's PR #3048 review: reject array imports field, log
unsupported imports values, drop redundant globstar check, tighten
wildcard-count validation, remove dead inferExportsAndAliases code,
and reference type-fest in imports/exports type docs. Expands fixture
coverage for imports/exports/browser/main field edge cases and renames
fixtures-subpath-patterns to fixtures-package-imports-exports to reflect
the broader scope.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove unused _name parameter from interpretImports
- Extract classifyPatternEntry from makeMultiSubpathReplacer
- Move ResolvedPattern typedef from JSDoc to types/pattern-replacement.ts
- Use typeof normalizedEntries cast for conciseness
- Tighten compartmentName from string to FileUrlString in link.js

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ld, and unmatched conditions

- Add absolute-pattern fixtures confirming subpath patterns cannot escape
  the package directory via absolute paths
- Add module-field fixtures exercising the package.json "module" field
  branch in inferExportsEntries
- Add unmatched conditional import to imports-edge-cases fixture
- Add corresponding Node.js parity tests

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@kriskowal kriskowal force-pushed the kriskowal-subpath-pattern-replacement branch from e9d5c73 to 5d0f385 Compare April 15, 2026 07:45
@kriskowal kriskowal requested a review from boneskull April 15, 2026 07:45
… Node parity test

Node 18/20 throws ERR_PACKAGE_PATH_NOT_EXPORTED while Node 22+ throws
ERR_MODULE_NOT_FOUND for non-object exports fields. Drop the code
assertion to support all versions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

ship it

@kriskowal kriskowal merged commit 9943eb2 into master Apr 15, 2026
26 checks passed
@kriskowal kriskowal deleted the kriskowal-subpath-pattern-replacement branch April 15, 2026 21:41
@kriskowal kriskowal mentioned this pull request Apr 15, 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

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compartment map support for subpath wildcard pattern replacement in exports (and imports)

3 participants