From 34c391a49ded28b780f303f0a5c36d5eef8229ac Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Fri, 24 May 2024 09:32:55 -0700 Subject: [PATCH 1/5] feat: export types --- packages/internal/src/index.js | 3 +++ packages/internal/src/types.js | 2 ++ 2 files changed, 5 insertions(+) create mode 100644 packages/internal/src/types.js 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.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 {}; From e395920ab0cd3ff1596010e6e357614df31655c8 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 23 May 2024 11:31:19 -0700 Subject: [PATCH 2/5] refactor(types): Remote, DataOnly, IsPrimitive --- packages/internal/src/types.d.ts | 37 ++++++++++++++++++++++++++ packages/internal/test/types.test-d.ts | 23 ++++++++++++++++ packages/vats/src/types.d.ts | 3 +-- packages/vow/src/index.js | 3 +++ packages/vow/src/types.js | 37 ++------------------------ 5 files changed, 66 insertions(+), 37 deletions(-) create mode 100644 packages/internal/test/types.test-d.ts 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/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/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/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 From dbad3543fc5d3fa832a31d0d04023be4f023b1a5 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 23 May 2024 10:49:09 -0700 Subject: [PATCH 3/5] chore(types): BridgeHandler is Remote --- packages/vats/test/vat-bank.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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'; */ From eea0f4ef87ffc429852ac3836db13af21c7f43e2 Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 23 May 2024 11:42:55 -0700 Subject: [PATCH 4/5] chore(types): use Remote --- .../src/examples/swapExample.contract.js | 10 +++++----- .../src/examples/unbondExample.contract.js | 10 +++++----- packages/orchestration/src/facade.js | 12 ++++++------ packages/orchestration/src/service.js | 3 ++- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/packages/orchestration/src/examples/swapExample.contract.js b/packages/orchestration/src/examples/swapExample.contract.js index 8fca312ecd3..3c2a0ff8f59 100644 --- a/packages/orchestration/src/examples/swapExample.contract.js +++ b/packages/orchestration/src/examples/swapExample.contract.js @@ -10,7 +10,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'; */ @@ -40,10 +40,10 @@ export const makeNatAmountShape = (brand, min) => /** * @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/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..5734d3c9dce 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; * zcf: ZCF; - * storageNode: ERef; - * orchestrationService: ERef; - * localchain: ERef; + * storageNode: Remote; + * orchestrationService: Remote; + * 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 */ /** From 730b349ee23de4dac88243ef58b979969d25afae Mon Sep 17 00:00:00 2001 From: Turadg Aleahmad Date: Thu, 23 May 2024 13:57:26 -0700 Subject: [PATCH 5/5] test: improve privateArgsShape --- .../orchestration/src/examples/stakeAtom.contract.js | 5 +++-- .../src/examples/swapExample.contract.js | 11 ++++++----- packages/orchestration/src/facade.js | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) 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 3c2a0ff8f59..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'; @@ -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', @@ -41,9 +42,9 @@ export const makeNatAmountShape = (brand, min) => * @param {ZCF} zcf * @param {{ * localchain: Remote; - * orchestrationService: Remote; + * orchestrationService: Remote | null; * storageNode: Remote; - * timerService: Remote; + * timerService: Remote | null; * zone: Zone; * }} privateArgs */ diff --git a/packages/orchestration/src/facade.js b/packages/orchestration/src/facade.js index 5734d3c9dce..c905534ca18 100644 --- a/packages/orchestration/src/facade.js +++ b/packages/orchestration/src/facade.js @@ -134,10 +134,10 @@ const makeRemoteChainFacade = name => { * * @param {{ * zone: Zone; - * timerService: Remote; + * timerService: Remote | null; * zcf: ZCF; * storageNode: Remote; - * orchestrationService: Remote; + * orchestrationService: Remote | null; * localchain: Remote; * }} powers */