diff --git a/packages/internal/src/index.js b/packages/internal/src/index.js index 2313cb3d5f5..c8e36af48ef 100644 --- a/packages/internal/src/index.js +++ b/packages/internal/src/index.js @@ -8,5 +8,8 @@ export * from './utils.js'; export * from './method-tools.js'; export * from './typeGuards.js'; +// eslint-disable-next-line import/export -- just types +export * from './types.js'; + export { objectMap } from '@endo/common/object-map.js'; export { fromUniqueEntries } from '@endo/common/from-unique-entries.js'; diff --git a/packages/internal/src/types.d.ts b/packages/internal/src/types.d.ts index 45b3dbf4dc3..e54952e4ab2 100644 --- a/packages/internal/src/types.d.ts +++ b/packages/internal/src/types.d.ts @@ -1,4 +1,7 @@ /* eslint-disable max-classes-per-file */ +import type { Callable, RemotableBrand } from '@endo/eventual-send'; +import type { Primitive } from '@endo/pass-style'; + export declare class Callback any> { private iface: I; @@ -18,3 +21,37 @@ export declare class SyncCallback< public isSync: true; } + +/** +Returns a boolean for whether the given type is primitive value or primitive type. + +@example +``` +IsPrimitive<'string'> +//=> true + +IsPrimitive +//=> true + +IsPrimitive +//=> false +``` + */ +export type IsPrimitive = [T] extends [Primitive] ? true : false; + +/** Recursively extract the non-callable properties of T */ +export type DataOnly = + IsPrimitive extends true + ? T + : T extends Callable + ? never + : { [P in keyof T as T[P] extends Callable ? never : P]: DataOnly }; + +/** + * A type that doesn't assume its parameter is local, but is satisfied with both + * local and remote references. It accepts both near and marshalled references + * that were returned from `Remotable` or `Far`. + */ +export type Remote> = + | Primary + | RemotableBrand; diff --git a/packages/internal/src/types.js b/packages/internal/src/types.js new file mode 100644 index 00000000000..d382eb5feaf --- /dev/null +++ b/packages/internal/src/types.js @@ -0,0 +1,2 @@ +// Empty JS file to correspond with its .d.ts twin +export {}; diff --git a/packages/internal/test/types.test-d.ts b/packages/internal/test/types.test-d.ts new file mode 100644 index 00000000000..9b63697ac33 --- /dev/null +++ b/packages/internal/test/types.test-d.ts @@ -0,0 +1,23 @@ +import { expectNotType, expectType } from 'tsd'; +import { E, ERef } from '@endo/far'; +import type { Remote } from '../src/types.js'; +import type { StorageNode } from '../src/lib-chainStorage.js'; + +const eventualStorageNode: ERef = null as any; +const remoteStorageNode: Remote = null as any; + +{ + // When awaited, ERef makes the object look local + const storageNode = await eventualStorageNode; + expectType(storageNode); + expectType(storageNode.getPath()); +} + +{ + // When awaited, Remote is correct + const storageNode = await remoteStorageNode; // no-op + expectType>(storageNode); + // @ts-expect-error cannot call remote methods directly + storageNode.getPath(); + expectType>(E(storageNode).getPath()); +} diff --git a/packages/orchestration/src/examples/stakeAtom.contract.js b/packages/orchestration/src/examples/stakeAtom.contract.js index 4c87f855f74..ff189ee10d4 100644 --- a/packages/orchestration/src/examples/stakeAtom.contract.js +++ b/packages/orchestration/src/examples/stakeAtom.contract.js @@ -3,6 +3,7 @@ */ import { makeTracer, StorageNodeShape } from '@agoric/internal'; +import { TimerServiceShape } from '@agoric/time'; import { V as E } from '@agoric/vow/vat.js'; import { prepareRecorderKitMakers } from '@agoric/zoe/src/contractSupport'; import { InvitationShape } from '@agoric/zoe/src/typeGuards.js'; @@ -22,8 +23,8 @@ export const meta = harden({ privateArgsShape: { orchestration: M.remotable('orchestration'), storageNode: StorageNodeShape, - marshaller: M.remotable('Marshaller'), - timer: M.remotable('TimerService'), + marshaller: M.remotable('marshaller'), + timer: TimerServiceShape, }, }); export const privateArgsShape = meta.privateArgsShape; diff --git a/packages/orchestration/src/examples/swapExample.contract.js b/packages/orchestration/src/examples/swapExample.contract.js index 8fca312ecd3..ac63c9c75bd 100644 --- a/packages/orchestration/src/examples/swapExample.contract.js +++ b/packages/orchestration/src/examples/swapExample.contract.js @@ -1,4 +1,5 @@ import { StorageNodeShape } from '@agoric/internal'; +import { TimerServiceShape } from '@agoric/time'; import { withdrawFromSeat } from '@agoric/zoe/src/contractSupport/zoeHelpers.js'; import { Far } from '@endo/far'; import { deeplyFulfilled } from '@endo/marshal'; @@ -10,7 +11,7 @@ import { orcUtils } from '../utils/orc.js'; * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' * @import {TimerService} from '@agoric/time'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; - * @import {ERef} from '@endo/far' + * @import {Remote} from '@agoric/internal'; * @import {OrchestrationService} from '../service.js'; * @import {Zone} from '@agoric/zone'; */ @@ -18,10 +19,10 @@ import { orcUtils } from '../utils/orc.js'; /** @type {ContractMeta} */ export const meta = { privateArgsShape: { - localchain: M.any(), - orchestrationService: M.any(), + localchain: M.remotable('localchain'), + orchestrationService: M.or(M.remotable('orchestration'), null), storageNode: StorageNodeShape, - timerService: M.any(), + timerService: M.or(TimerServiceShape, null), zone: M.any(), }, upgradability: 'canUpgrade', @@ -40,10 +41,10 @@ export const makeNatAmountShape = (brand, min) => /** * @param {ZCF} zcf * @param {{ - * localchain: ERef; - * orchestrationService: ERef; - * storageNode: ERef; - * timerService: ERef; + * localchain: Remote; + * orchestrationService: Remote | null; + * storageNode: Remote; + * timerService: Remote | null; * zone: Zone; * }} privateArgs */ diff --git a/packages/orchestration/src/examples/unbondExample.contract.js b/packages/orchestration/src/examples/unbondExample.contract.js index 86e11a98c6a..ff2beac44d0 100644 --- a/packages/orchestration/src/examples/unbondExample.contract.js +++ b/packages/orchestration/src/examples/unbondExample.contract.js @@ -6,7 +6,7 @@ import { makeOrchestrationFacade } from '../facade.js'; * @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js' * @import {TimerService} from '@agoric/time'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; - * @import {ERef} from '@endo/far' + * @import {Remote} from '@agoric/internal'; * @import {OrchestrationService} from '../service.js'; * @import {Zone} from '@agoric/zone'; */ @@ -14,10 +14,10 @@ import { makeOrchestrationFacade } from '../facade.js'; /** * @param {ZCF} zcf * @param {{ - * localchain: ERef; - * orchestrationService: ERef; - * storageNode: ERef; - * timerService: ERef; + * localchain: Remote; + * orchestrationService: Remote; + * storageNode: Remote; + * timerService: Remote; * zone: Zone; * }} privateArgs */ diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index ed507e4ab77..c905534ca18 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -6,7 +6,7 @@ import { E } from '@endo/far'; * @import {Zone} from '@agoric/zone'; * @import {TimerService} from '@agoric/time'; * @import {LocalChain} from '@agoric/vats/src/localchain.js'; - * @import {ERef} from '@endo/far'; + * @import {Remote} from '@agoric/internal'; * @import {OrchestrationService} from './service.js'; * @import {Chain, ChainInfo, OrchestrationAccount, Orchestrator} from './types.js'; */ @@ -15,7 +15,7 @@ import { E } from '@endo/far'; const anyVal = null; /** - * @param {ERef} localchain + * @param {Remote} localchain * @returns {Chain} */ const makeLocalChainFacade = localchain => { @@ -134,11 +134,11 @@ const makeRemoteChainFacade = name => { * * @param {{ * zone: Zone; - * timerService: ERef; + * timerService: Remote | null; * zcf: ZCF; - * storageNode: ERef; - * orchestrationService: ERef; - * localchain: ERef; + * storageNode: Remote; + * orchestrationService: Remote | null; + * localchain: Remote; * }} powers */ export const makeOrchestrationFacade = ({ diff --git a/packages/orchestration/src/service.js b/packages/orchestration/src/service.js index be46cdd0288..84905922962 100644 --- a/packages/orchestration/src/service.js +++ b/packages/orchestration/src/service.js @@ -12,6 +12,7 @@ import { /** * @import { Zone } from '@agoric/base-zone'; + * @import {Remote} from '@agoric/internal'; * @import { Port, PortAllocator } from '@agoric/network'; * @import { IBCConnectionID } from '@agoric/vats'; * @import { ICQConnection, IcaAccount, ICQConnectionKit } from './types.js'; @@ -21,7 +22,7 @@ const { Fail, bare } = assert; /** * @typedef {object} OrchestrationPowers - * @property {ERef} portAllocator + * @property {Remote} portAllocator */ /** diff --git a/packages/vats/src/types.d.ts b/packages/vats/src/types.d.ts index 6369ae6a5b7..ec9ecc84191 100644 --- a/packages/vats/src/types.d.ts +++ b/packages/vats/src/types.d.ts @@ -1,8 +1,7 @@ +import type { BridgeIdValue, Remote } from '@agoric/internal'; import type { Bytes } from '@agoric/network'; import type { PromiseVow, Remote } from '@agoric/vow'; import type { Guarded } from '@endo/exo'; -import type { ERef } from '@endo/far'; -import type { BridgeIdValue } from '@agoric/internal'; export type Board = ReturnType< ReturnType diff --git a/packages/vats/test/vat-bank.test.js b/packages/vats/test/vat-bank.test.js index aff6065e622..e23468725ce 100644 --- a/packages/vats/test/vat-bank.test.js +++ b/packages/vats/test/vat-bank.test.js @@ -9,7 +9,7 @@ import { subscribeEach } from '@agoric/notifier'; import { buildRootObject } from '../src/vat-bank.js'; /** - * @import {Remote} from '@agoric/vow'; + * @import {Remote} from '@agoric/internal'; * @import {BridgeHandler, ScopedBridgeManager} from '../src/types.js'; */ diff --git a/packages/vow/src/index.js b/packages/vow/src/index.js index d3033e6933f..4b41d02b15a 100644 --- a/packages/vow/src/index.js +++ b/packages/vow/src/index.js @@ -5,3 +5,6 @@ export { VowShape, toPassableCap } from './vow-utils.js'; // eslint-disable-next-line import/export export * from './types.js'; + +// XXX re-exporting the Remote type for back-compat +export * from '@agoric/internal/src/types.js'; diff --git a/packages/vow/src/types.js b/packages/vow/src/types.js index ac7a94bcf56..974e28bb796 100644 --- a/packages/vow/src/types.js +++ b/packages/vow/src/types.js @@ -5,10 +5,10 @@ export {}; * @import {RemotableBrand} from '@endo/eventual-send' * @import {CopyTagged} from '@endo/pass-style' * @import {RemotableObject} from '@endo/pass-style'; - * @import {PromiseVow, Remote} from '@agoric/vow'; + * @import {IsPrimitive, Remote} from '@agoric/internal'; + * @import {PromiseVow} from '@agoric/vow'; * @import {prepareVowTools} from './tools.js' */ -/** @typedef {(...args: any[]) => any} Callable */ /** * @template T @@ -21,29 +21,6 @@ export {}; * @typedef {T | PromiseLike} ERef */ -/** - * @template T - * @typedef {( - * T extends bigint ? true : - * T extends boolean ? true : - * T extends null ? true : - * T extends number ? true : - * T extends string ? true : - * T extends symbol ? true : - * T extends undefined ? true : - * false - * )} IsPrimitive Whether T is a primitive type. - */ - -/** - * @template T - * @typedef {( - * IsPrimitive extends true ? T : - * T extends Callable ? never : - * { [P in keyof T as T[P] extends Callable ? never : P]: DataOnly } - * )} DataOnly Recursively extract the non-callable properties of T. - */ - /** * Follow the chain of vow shortening to the end, returning the final value. * This is used within E, so we must narrow the type to its remote form. @@ -57,16 +34,6 @@ export {}; * )} Unwrap */ -/** - * A type that accepts both near and marshalled references that were - * returned from `Remotable` or `Far`. - * @template Primary The type of the primary reference. - * @template [Local=DataOnly] The local properties of the object. - * @typedef {Primary | RemotableBrand} Remote A type that - * doesn't assume its parameter is local, but is satisfied with both local - * and remote references. - */ - /** * @template [T=any] * @typedef {object} VowV0 The first version of the vow implementation