diff --git a/packages/compartment-mapper/src/map-parser.js b/packages/compartment-mapper/src/map-parser.js index 49b2acfa66..91dcdd7dad 100644 --- a/packages/compartment-mapper/src/map-parser.js +++ b/packages/compartment-mapper/src/map-parser.js @@ -18,6 +18,9 @@ * SyncModuleTransform, * SyncModuleTransforms * } from './types.js'; + * @import { + * EReturn + * } from '@endo/eventual-send'; */ import { syncTrampoline, asyncTrampoline } from '@endo/trampoline'; @@ -82,7 +85,7 @@ const makeExtensionParser = ( * @param {string} location * @param {string} packageLocation * @param {*} options - * @returns {Generator|ReturnType, ParseResult, Awaited|ReturnType>>} + * @returns {Generator|ReturnType, ParseResult, EReturn>} */ function* getParserGenerator( bytes, diff --git a/packages/daemon/test/endo.test.js b/packages/daemon/test/endo.test.js index 4e6cd36ec9..d8b9107186 100644 --- a/packages/daemon/test/endo.test.js +++ b/packages/daemon/test/endo.test.js @@ -28,6 +28,10 @@ import { makeCryptoPowers } from '../src/daemon-node-powers.js'; import { formatId } from '../src/formula-identifier.js'; import { idFromLocator, parseLocator } from '../src/locator.js'; +/** + * @import {EReturn} from '@endo/eventual-send'; + */ + const cryptoPowers = makeCryptoPowers(crypto); const { raw } = String; @@ -227,7 +231,7 @@ test.beforeEach(t => { test.afterEach.always(async t => { await Promise.allSettled( - /** @type {Awaited>[]} */ (t.context).flatMap( + /** @type {EReturn[]} */ (t.context).flatMap( ({ cancel, cancelled, config }) => { cancel(Error('teardown')); return [cancelled, stop(config)]; diff --git a/packages/eventual-send/src/E.js b/packages/eventual-send/src/E.js index 579aa37f4d..a114e3ccb2 100644 --- a/packages/eventual-send/src/E.js +++ b/packages/eventual-send/src/E.js @@ -254,8 +254,11 @@ export default makeE; /** @typedef {ReturnType} EProxy */ /** - * Creates a type that accepts both near and marshalled references that were - * returned from `Remotable` or `Far`, and also promises for such references. + * Declare an object that is potentially a far reference of type Primary whose + * auxilliary data has type Local. This should be used only for consumers of + * Far objects in arguments and declarations; the only creators of Far objects + * are distributed object creator components like the `Far` or `Remotable` + * functions. * * @template Primary The type of the primary reference. * @template [Local=DataOnly] The local properties of the object. @@ -274,6 +277,16 @@ export default makeE; * @see {@link https://github.com/microsoft/TypeScript/issues/31394} * @template T * @typedef {PromiseLike | T} ERef + * Declare that `T` may or may not be a Promise. This should be used only for + * consumers of arguments and declarations; return values should specifically be + * `Promise` or `T` itself. + */ + +/** + * The awaited return type of a function. + * + * @template {(...args: any[]) => any} T + * @typedef {T extends (...args: any[]) => infer R ? Awaited : never} EReturn */ /** @@ -281,7 +294,7 @@ export default makeE; * @typedef {( * ReturnType extends PromiseLike // if function returns a promise * ? T // return the function - * : (...args: Parameters) => Promise>> // make it return a promise + * : (...args: Parameters) => Promise> // make it return a promise * )} ECallable */ @@ -399,8 +412,9 @@ export default makeE; */ /** - * Type for an object that must only be invoked with E. It supports a given - * interface but declares all the functions as asyncable. + * Declare a near object that must only be invoked with E, even locally. It + * supports the `T` interface but additionally permits `T`'s methods to return + * `PromiseLike`s even if `T` declares them as only synchronous. * * @template T * @typedef {( diff --git a/packages/eventual-send/src/exports.d.ts b/packages/eventual-send/src/exports.d.ts index 3134d5c51a..0dec8d4795 100644 --- a/packages/eventual-send/src/exports.d.ts +++ b/packages/eventual-send/src/exports.d.ts @@ -12,6 +12,7 @@ export type { ERef, EProxy, EOnly, + EReturn, RemoteFunctions, LocalRecord, FilteredKeys, diff --git a/packages/eventual-send/src/exports.test-d.ts b/packages/eventual-send/src/exports.test-d.ts index ce3b641941..feda0d5b2e 100644 --- a/packages/eventual-send/src/exports.test-d.ts +++ b/packages/eventual-send/src/exports.test-d.ts @@ -1,7 +1,7 @@ /* eslint-disable @endo/no-polymorphic-call, import/no-extraneous-dependencies, no-restricted-globals */ import { expectType } from 'tsd'; import { E } from '../test/_get-hp.js'; -import type { ERef, FarRef } from './exports.js'; +import type { ERef, EReturn, FarRef } from './exports.js'; // Check the legacy ERef type const foo = async (a: ERef<{ bar(): string; baz: number }>) => { @@ -21,6 +21,19 @@ const foo = async (a: ERef<{ bar(): string; baz: number }>) => { a.bar(); }; +// EReturn +{ + const makeFoo = async () => 'foo' as const; + expectType>(makeFoo()); + type Foo = EReturn; + expectType('foo'); + + const fooP = Promise.resolve('foo' as const); + expectType>(fooP); + // @ts-expect-error takes only functions + EReturn; +} + // FarRef const foo2 = async (a: FarRef<{ bar(): string; baz: number }>) => { const { baz } = await a; diff --git a/packages/far/src/exports.d.ts b/packages/far/src/exports.d.ts new file mode 100644 index 0000000000..92104c141b --- /dev/null +++ b/packages/far/src/exports.d.ts @@ -0,0 +1 @@ +export { FarRef, ERef, EOnly, EReturn } from '@endo/eventual-send'; diff --git a/packages/far/src/exports.js b/packages/far/src/exports.js new file mode 100644 index 0000000000..b59f8e9710 --- /dev/null +++ b/packages/far/src/exports.js @@ -0,0 +1,2 @@ +// Just a dummy to use exports.d.ts and satisfy runtime imports. +export {}; diff --git a/packages/far/src/index.js b/packages/far/src/index.js index 58decf5966..eaae3df61c 100644 --- a/packages/far/src/index.js +++ b/packages/far/src/index.js @@ -1,30 +1,5 @@ export { E } from '@endo/eventual-send'; export { Far, getInterfaceOf, passStyleOf } from '@endo/pass-style'; -// TODO re-export from eventual-send, may require .d.ts -/** - * @template Primary - * @template [Local=import('@endo/eventual-send').DataOnly] - * @typedef {import('@endo/eventual-send').FarRef} FarRef - * Declare an object that is potentially a far reference of type Primary whose - * auxilliary data has type Local. This should be used only for consumers of - * Far objects in arguments and declarations; the only creators of Far objects - * are distributed object creator components like the `Far` or `Remotable` - * functions. - */ - -/** - * @template T - * @typedef {import('@endo/eventual-send').ERef} ERef - * Declare that `T` may or may not be a Promise. This should be used only for - * consumers of arguments and declarations; return values should specifically be - * `Promise` or `T` itself. - */ - -/** - * @template T - * @typedef {import('@endo/eventual-send').EOnly} EOnly - * Declare a near object that must only be invoked with E, even locally. It - * supports the `T` interface but additionally permits `T`'s methods to return - * `PromiseLike`s even if `T` declares them as only synchronous. - */ +// eslint-disable-next-line import/export +export * from './exports.js';