Skip to content

Commit

Permalink
feat(types): infer orchestrate() return
Browse files Browse the repository at this point in the history
  • Loading branch information
turadg committed Jul 12, 2024
1 parent 12d04c6 commit d7948c7
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 29 deletions.
8 changes: 5 additions & 3 deletions packages/async-flow/src/async-flow.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { LogEntryShape, FlowStateShape } from './type-guards.js';
/**
* @import {WeakMapStore} from '@agoric/store'
* @import {Zone} from '@agoric/base-zone'
* @import {FlowState, GuestAsyncFunc, HostAsyncFuncWrapper, PreparationOptions} from '../src/types.js'
* @import {FlowState, GuestAsyncFunc, HostAsyncFuncWrapper, HostOf, PreparationOptions} from '../src/types.js'
* @import {ReplayMembrane} from '../src/replay-membrane.js'
*/

Expand Down Expand Up @@ -434,11 +434,12 @@ export const prepareAsyncFlowTools = (outerZone, outerOptions = {}) => {
};

/**
* @template {GuestAsyncFunc} F
* @param {Zone} zone
* @param {string} tag
* @param {GuestAsyncFunc} guestFunc
* @param {F} guestFunc
* @param {{ startEager?: boolean }} [options]
* @returns {HostAsyncFuncWrapper}
* @returns {HostOf<F>}
*/
const asyncFlow = (zone, tag, guestFunc, options = undefined) => {
const makeAsyncFlowKit = prepareAsyncFlowKit(zone, tag, guestFunc, options);
Expand All @@ -452,6 +453,7 @@ export const prepareAsyncFlowTools = (outerZone, outerOptions = {}) => {
defineProperties(wrapperFunc, {
length: { value: guestFunc.length },
});
// @ts-expect-error cast
return harden(wrapperFunc);
};

Expand Down
9 changes: 9 additions & 0 deletions packages/async-flow/src/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ type HostInterface<T> = {
[K in keyof T]: HostOf<T[K]>;
};

/**
* Convert an entire Host interface into what the Guest will receive.
*/
type GuestInterface<T> = {
[K in keyof T]: GuestOf<T[K]>;
};

/**
* The function the host must provide to match an interface the guest expects.
*
Expand All @@ -60,6 +67,8 @@ export type HostOf<F> = F extends (...args: infer A) => Promise<infer R>
? (...args: A) => Vow<R extends Passable ? R : HostInterface<R>>
: F;

export type HostArgs<GA extends any[]> = { [K in keyof GA]: HostOf<GA[K]> };

export type PreparationOptions = {
vowTools?: VowTools;
makeLogStore?: (() => LogStore) | undefined;
Expand Down
2 changes: 0 additions & 2 deletions packages/orchestration/src/examples/basic-flows.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import { provideOrchestration } from '../utils/start-helper.js';
* @import {Baggage} from '@agoric/vat-data';
* @import {Orchestrator} from '@agoric/orchestration';
* @import {OrchestrationPowers} from '../utils/start-helper.js';
* @import {ResolvedContinuingOfferResult} from '../utils/zoe-tools.js';
*/

/**
Expand Down Expand Up @@ -45,7 +44,6 @@ export const start = async (zcf, privateArgs, baggage) => {
privateArgs.marshaller,
);

/** @type {OfferHandler<Promise<ResolvedContinuingOfferResult>>} */
const makeOrchAccount = orchestrate(
'makeOrchAccount',
undefined,
Expand Down
7 changes: 0 additions & 7 deletions packages/orchestration/src/examples/swapExample.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { orcUtils } from '../utils/orc.js';
import { withOrchestration } from '../utils/start-helper.js';

/**
* @import {GuestInterface, GuestOf} from '@agoric/async-flow';
* @import {LocalTransfer} from '../utils/zoe-tools.js';
* @import {Orchestrator, CosmosValidatorAddress} from '../types.js'
* @import {TimerService} from '@agoric/time';
Expand Down Expand Up @@ -102,12 +101,6 @@ const contract = async (zcf, privateArgs, zone, { orchestrate, zoeTools }) => {
const { brands } = zcf.getTerms();

/** deprecated historical example */
/**
* @type {OfferHandler<
* unknown,
* { staked: Amount<'nat'>; validator: CosmosValidatorAddress }
* >}
*/
const swapAndStakeHandler = orchestrate(
'LSTTia',
{ zcf, localTransfer: zoeTools.localTransfer },
Expand Down
2 changes: 0 additions & 2 deletions packages/orchestration/src/examples/unbondExample.contract.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { withOrchestration } from '../utils/start-helper.js';
/**
* @import {Orchestrator, IcaAccount, CosmosValidatorAddress} from '../types.js'
* @import {TimerService} from '@agoric/time';
* @import {Baggage} from '@agoric/vat-data';
* @import {LocalChain} from '@agoric/vats/src/localchain.js';
* @import {NameHub} from '@agoric/vats';
* @import {Remote} from '@agoric/internal';
Expand Down Expand Up @@ -59,7 +58,6 @@ const unbondAndLiquidStakeFn = async (orch, { zcf }, _seat, _offerArgs) => {
* @param {OrchestrationTools} tools
*/
const contract = async (zcf, privateArgs, zone, { orchestrate }) => {
/** @type {OfferHandler} */
const unbondAndLiquidStake = orchestrate(
'LSTTia',
{ zcf },
Expand Down
27 changes: 12 additions & 15 deletions packages/orchestration/src/facade.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import { assertAllDefined } from '@agoric/internal';

/**
* @import {AsyncFlowTools} from '@agoric/async-flow';
* @import {AsyncFlowTools, GuestInterface, HostArgs} from '@agoric/async-flow';
* @import {Zone} from '@agoric/zone';
* @import {Vow, VowTools} from '@agoric/vow';
* @import {TimerService} from '@agoric/time';
Expand Down Expand Up @@ -55,24 +55,18 @@ export const makeOrchestrationFacade = ({
const { when } = vowTools;

/**
* @template GuestReturn
* @template HostReturn
* @template GuestContext
* @template HostContext
* @template {any[]} GuestArgs
* @template {any[]} HostArgs
* @template RT - return type
* @template HC - host context
* @template {any[]} GA - guest args
* @param {string} durableName - the orchestration flow identity in the zone
* (to resume across upgrades)
* @param {HostContext} hostCtx - values to pass through the async flow
* membrane
* @param {HC} hostCtx - values to pass through the async flow membrane
* @param {(
* guestOrc: Orchestrator,
* guestCtx: GuestContext,
* ...args: GuestArgs
* ) => Promise<GuestReturn>} guestFn
* @returns {(...args: HostArgs) => Promise<HostReturn>} TODO returns a
* Promise for now for compat before use of asyncFlow. But really should be
* `Vow<HostReturn>`
* guestCtx: GuestInterface<HC>,
* ...args: GA
* ) => Promise<RT>} guestFn
* @returns {(...args: HostArgs<GA>) => Promise<RT>}
*/
const orchestrate = (durableName, hostCtx, guestFn) => {
const subZone = zone.subZone(durableName);
Expand All @@ -89,7 +83,10 @@ export const makeOrchestrationFacade = ({
const orcFn = (...args) =>
// TODO remove the `when` after fixing the return type
// to `Vow<HostReturn>`
// @ts-expect-error cast
when(hostFn(wrappedOrc, wrappedCtx, ...args));

// @ts-expect-error cast
return harden(orcFn);
};

Expand Down

0 comments on commit d7948c7

Please sign in to comment.