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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .changeset/bundle-source-cache-load-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@endo/bundle-source': minor
---

`BundleCache.load()` now has a conditional return type based on the `format` option:
- Omitted (default) → `Promise<BundleSourceResult<'endoZipBase64'>>`
- Specific format literal → `Promise<BundleSourceResult<format>>`
- Runtime-typed `ModuleFormat` → `Promise<BundleSourceResult<ModuleFormat>>`

Previously `load()` returned `Promise<unknown>`, requiring callers to assert the bundle shape.
12 changes: 12 additions & 0 deletions .changeset/daemon-ts6-type-precision.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
'@endo/daemon': patch
---

TypeScript 6 conformance: public types in `types.d.ts` are now more precise.

- `Context.thisDiesIfThatDies` and `thatDiesIfThisDies` parameters tightened from `string` to `FormulaIdentifier` (a branded string type).
- `RemoteControl` and `RemoteControlState` interface parameters updated from `Promise<EndoGateway>` to `ERef<EndoGateway>` and `cancelled` widened from `Promise<never>` to `Promise<unknown>`.
- `EndoInspector` generic type parameter renamed from `Record` to `RecordT` to avoid shadowing the built-in `Record` utility type.
- `SerialJobs.enqueue` parameter widened from `() => Promise<T>` to `() => T | Promise<T>`, matching the runtime behavior (the implementation already awaits the result, so sync callbacks were always supported).

TypeScript consumers implementing or calling these interfaces may need to update their types accordingly.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ coverage

# LLM tools
.claude/*.local.*
# UNTIL https://github.com/anthropics/claude-code/issues/27282
.claude/worktrees/

# Platform metadata
.DS_Store
Expand Down
2 changes: 1 addition & 1 deletion .yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ catalogs:
eslint-plugin-eslint-comments: ^3.2.0
eslint-plugin-import: ^2.31.0
tsd: ^0.32.0
typescript: ~5.9.2
typescript: ~6.0.2

enableScripts: false

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"type-coverage": "^2.29.1",
"typedoc": "^0.28.17",
"typedoc-plugin-mermaid": "^1.12.0",
"typescript": "~5.9.2",
"typescript": "catalog:dev",
"typescript-eslint": "8.39.1",
"yaml": "^2.8.1",
"zx": "^8.1.8"
Expand Down
2 changes: 1 addition & 1 deletion packages/base64/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"c8": "catalog:dev",
"eslint": "catalog:dev",
"prettier": "^3.5.3",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/benchmark/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
"esvu": "^1.2.16",
"rollup": "^4.34.6",
"tsd": "catalog:dev",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/benchmark/src/benchmark.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ async function test(name, fn) {
await fn({ assert, truthy });
console.log(`✅ Passed`);
} catch (err) {
console.log(`❌ Failed: ${err.message}`);
console.log(`❌ Failed: ${/** @type {Error} */ (err).message}`);
}
}

Expand Down
31 changes: 19 additions & 12 deletions packages/bundle-source/cache.js
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,20 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => {

const bundle = await bundleSource(
rootPath,
{
/** @type {import('./src/types.js').BundleOptions<ModuleFormat>} */ ({
...bundleOptions,
noTransforms,
elideComments,
format,
conditions: sortedConditions,
},
{
}),
/** @type {{ read?: import('./src/types.js').ReadFn, canonical?: import('./src/types.js').CanonicalFn, externals?: string[] }} */ ({
...readPowers,
read: loggedRead,
},
canonical: /** @type {import('./src/types.js').CanonicalFn} */ (
readPowers.canonical
),
}),
);

const code = encodeBundle(bundle);
Expand Down Expand Up @@ -362,18 +365,22 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => {
* Load a bundle by target name, validating existing cache entries or creating
* them on demand. Results are memoized per `targetName`.
*
* @template {BundleCacheOperationOptions | undefined} [Opts=undefined]
* @param {string} rootPath
* @param {string} [targetName]
* @param {Logger} [log]
* @param {BundleCacheOperationOptions} [options]
* @returns {Promise<unknown>}
* @param {Opts} [options]
* @returns {Promise<
* Opts extends { format: infer F }
* ? F extends ModuleFormat
* ? import('./src/types.js').BundleSourceResult<F>
* : import('./src/types.js').BundleSourceResult<'endoZipBase64'>
Comment on lines +374 to +377
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

This JSDoc return-type conditional has the same issue as the exported BundleCache.load type: checking Opts extends { format: ... } will treat BundleCacheOperationOptions (where format is optional) as the “no format” case, narrowing the return type to the default even when a runtime format may be present. Align this with the fixed signature (likely via overload-style JSDoc or by matching format? and extracting ModuleFormat).

Suggested change
* Opts extends { format: infer F }
* ? F extends ModuleFormat
* ? import('./src/types.js').BundleSourceResult<F>
* : import('./src/types.js').BundleSourceResult<'endoZipBase64'>
* Opts extends { format?: infer F }
* ? Extract<F, ModuleFormat> extends never
* ? import('./src/types.js').BundleSourceResult<'endoZipBase64'>
* : import('./src/types.js').BundleSourceResult<Extract<F, ModuleFormat>>

Copilot uses AI. Check for mistakes.
* : import('./src/types.js').BundleSourceResult<'endoZipBase64'>
* >}
*/
const load = async (
rootPath,
targetName = readPowers.basename(rootPath, '.js'),
log = defaultLog,
options = {},
) => {
const load = async (rootPath, targetName, log, options) => {
targetName = targetName ?? readPowers.basename(rootPath, '.js');
log = log ?? defaultLog;
const found = loaded.get(targetName);
// console.log('load', { targetName, found: !!found, rootPath });
if (found && found.rootPath === rootPath) {
Expand Down
2 changes: 1 addition & 1 deletion packages/bundle-source/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"c8": "catalog:dev",
"eslint": "catalog:dev",
"ses": "workspace:^",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"keywords": [],
"files": [
Expand Down
2 changes: 2 additions & 0 deletions packages/bundle-source/src/endo.js
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,7 @@ export const makeBundlingKit = (
};
}

/** @type {import('../../compartment-mapper/src/types.js').ParserImplementation} */
const mtsParser = {
parse(
sourceBytes,
Expand All @@ -212,6 +213,7 @@ export const makeBundlingKit = (
synchronous: false,
};

/** @type {import('../../compartment-mapper/src/types.js').ParserImplementation} */
const ctsParser = {
parse(
sourceBytes,
Expand Down
22 changes: 19 additions & 3 deletions packages/bundle-source/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,28 @@ export interface BundleCache {
log?: Logger | undefined,
options?: BundleCacheOperationOptions | undefined,
) => Promise<BundleMeta>;
load: (
/**
* The result type is conditional on the `format` option:
* - omitted → `BundleSourceResult<'endoZipBase64'>` (the default)
* - present → `BundleSourceResult<format>`
*
* Callers that don't pass a `format` option get the default
* `endoZipBase64` shape directly. Callers that pass a known literal
* format get the corresponding bundle shape. Callers that pass a
* runtime-typed `ModuleFormat` get the union of all possible shapes.
*/
load: <Opts extends BundleCacheOperationOptions | undefined = undefined>(
rootPath: string,
targetName?: string | undefined,
log?: Logger | undefined,
options?: BundleCacheOperationOptions | undefined,
) => Promise<unknown>;
options?: Opts,
) => Promise<
Opts extends { format: infer F }
? F extends ModuleFormat
? BundleSourceResult<F>
: BundleSourceResult<'endoZipBase64'>
: BundleSourceResult<'endoZipBase64'>
Comment on lines +97 to +101
Copy link

Copilot AI Apr 8, 2026

Choose a reason for hiding this comment

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

The conditional return type for BundleCache.load won’t behave as described for callers that pass an options variable typed as BundleCacheOperationOptions (where format is optional): BundleCacheOperationOptions does not satisfy { format: ... }, so the return type collapses to the default 'endoZipBase64' even though options.format may be set at runtime. Consider using overloads (no options → default; options with format: FBundleSourceResult<F>; otherwise → BundleSourceResult<ModuleFormat>) or changing the conditional to account for optional/undefined formats (e.g. match { format?: infer F } and use Extract<F, ModuleFormat>).

Copilot uses AI. Check for mistakes.
>;
}

export interface FileReader {
Expand Down
2 changes: 1 addition & 1 deletion packages/cache-map/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"c8": "catalog:dev",
"eslint": "catalog:dev",
"tsd": "catalog:dev",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/captp/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
"c8": "catalog:dev",
"eslint": "catalog:dev",
"ses": "workspace:^",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"dependencies": {
"@endo/errors": "workspace:^",
Expand Down
8 changes: 6 additions & 2 deletions packages/captp/src/captp.js
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,7 @@ export const makeCapTP = (

/** @type {any} */
let unplug = false;
/** @type {(reason?: any, returnIt?: boolean) => Promise<any>} */
const quietReject = (reason = undefined, returnIt = true) => {
if ((unplug === false || reason !== unplug) && reason !== undefined) {
onReject(reason);
Expand Down Expand Up @@ -657,7 +658,7 @@ export const makeCapTP = (
} catch (error) {
// Promote serialization errors to rejections.
isReject = true;
serial = serialize(harden(error));
serial = serialize(harden(/** @type {any} */ (error)));
}

send({
Expand Down Expand Up @@ -758,7 +759,10 @@ export const makeCapTP = (
if (!e) {
Fail`trapGuest expected trapHost AsyncIterator(${questionID}) to be done, but it wasn't`;
}
annotateError(e, X`trapHost AsyncIterator(${questionID}) threw`);
annotateError(
/** @type {Error} */ (e),
X`trapHost AsyncIterator(${questionID}) threw`,
);
throw e;
}
};
Expand Down
2 changes: 1 addition & 1 deletion packages/check-bundle/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.5.3",
"ses": "workspace:^",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
7 changes: 4 additions & 3 deletions packages/cjs-module-analyzer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,11 +74,12 @@ export function analyzeCommonJS(cjsSource, name = '<unknown>') {
try {
parseSource(cjsSource);
} catch (e) {
e.message += `\n at ${name}:${
const err = /** @type {Error & { loc?: number }} */ (e);
err.message += `\n at ${name}:${
cjsSource.slice(0, pos).split('\n').length
}:${pos - cjsSource.lastIndexOf('\n', pos - 1)}`;
e.loc = pos;
throw e;
err.loc = pos;
throw err;
}
const result = {
exports: [...myexports].filter(expt => !unsafeGetters.has(expt)),
Expand Down
2 changes: 1 addition & 1 deletion packages/cjs-module-analyzer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
"ava": "catalog:dev",
"c8": "catalog:dev",
"eslint": "catalog:dev",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.31.0",
"execa": "^9.3.0",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/_daemon-context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import { Context } from './types' */
/** @import { Context } from './_types.js' */

/**
* Provides test setup and teardown hooks that purge the local endo
Expand Down
12 changes: 7 additions & 5 deletions packages/cli/test/_section.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/** @import {Execa} from 'execa' */
/** @import {t} from 'ava' */
/** @import {TestRoutine} from './types' */
/** @import {ExecaMethod} from 'execa' */
/** @import {ExecutionContext} from 'ava' */
/** @import {TestCommand, TestRoutine} from './_types.js' */

/**
* Transforms a testRoutine into an ava test.
Expand All @@ -12,9 +12,9 @@
* when run under a vscode JavaScript Debug Terminal
* @see https://github.com/endojs/endo/issues/2702
*
* @param {Execa} execa - the command execution environment
* @param {ExecaMethod} execa - the command execution environment
* @param {TestRoutine} testRoutine - the test logic implementation
* @returns {(t: t) => Promise<void>}
* @returns {(t: ExecutionContext) => Promise<void>}
*/
export function makeSectionTest(execa, testRoutine) {
return async t => {
Expand All @@ -25,13 +25,15 @@ export function makeSectionTest(execa, testRoutine) {
errMsg,
);
};
/** @type {TestCommand} */
const testCommand = async (command, expectation) => {
const result = await command;
if (expectation !== undefined) {
const errMsg = JSON.stringify({ expectation, result }, null, 2);
matchExpecation(expectation.stdout ?? '', result.stdout, errMsg);
matchExpecation(expectation.stderr ?? /.*/, result.stderr, errMsg);
}
return true;
};
await testRoutine(execa, testCommand);
};
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/_with-context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {Context, TestRoutine} from '../types' */
/** @import {Context, TestRoutine} from './_types.js' */
/**
* Creates a wrapper which wraps a test routine with an execa-curried setup and teardown routine.
*
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/demo/counter-example.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {Context, TestRoutine} from '../types' */
/** @import {Context, TestRoutine} from '../_types.js' */

/** @type {TestRoutine} */
export const section = async (execa, testLine) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/demo/doubler-agent.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {Context, TestRoutine} from '../types' */
/** @import {Context, TestRoutine} from '../_types.js' */

/** @type {TestRoutine} */
export const section = async (execa, testLine) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/demo/mailboxes-are-symmetric.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {TestRoutine} from '../types' */
/** @import {TestRoutine} from '../_types.js' */

/** @type {TestRoutine} */
export const section = async (execa, testLine) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/demo/names-in-transit.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {Context, TestRoutine} from '../types' */
/** @import {Context, TestRoutine} from '../_types.js' */

/** @type {TestRoutine} */
export const section = async (execa, testLine) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/demo/sending-messages.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/** @import {Context, TestRoutine} from '../types' */
/** @import {Context, TestRoutine} from '../_types.js' */

/** @type {TestRoutine} */
export const section = async (execa, testLine) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/common/apply-labeling-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export const applyLabelingError = (func, args, label = undefined) => {
try {
result = func(...args);
} catch (err) {
throwLabeled(err, label);
throwLabeled(/** @type {Error} */ (err), label);
}
if (isPromise(result)) {
// Cannot be at-ts-expect-error because there is no type error locally.
Expand Down
2 changes: 1 addition & 1 deletion packages/common/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@
"eslint": "catalog:dev",
"ses": "workspace:^",
"tsd": "catalog:dev",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion packages/compartment-mapper/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@
"eslint-plugin-import": "^2.31.0",
"prettier": "^3.5.3",
"ses": "workspace:^",
"typescript": "~5.9.2"
"typescript": "catalog:dev"
},
"files": [
"./*.d.ts",
Expand Down
Loading
Loading