@agoric/deploy-script-support 0.11.0 → 0.11.1-upgrade-23-dev-bd79330.0.bd79330

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,17 +3,12 @@ const t = 'makeCoreProposalBehavior';
3
3
 
4
4
  /**
5
5
  * @import {Installation} from '@agoric/zoe/src/zoeService/utils.js';
6
+ * @import {E} from '@endo/far';
7
+ * @import {ManifestBundleRef} from './externalTypes.js';
8
+ * @import {BootstrapPowers, ChainBootstrapSpace} from '@agoric/vats/src/core/types.js';
6
9
  */
7
10
 
8
11
  /**
9
- * TODO import these from @agoric/vats when the types are better managed
10
- *
11
- * @typedef {*} ChainBootstrapSpace
12
- * @typedef {*} BootstrapPowers
13
- */
14
-
15
- /**
16
- * @import {ManifestBundleRef} from './externalTypes.js'
17
12
  * @typedef {[methodName: string, ...args: unknown[]]} FlatMethargs
18
13
  * @typedef {Record<string, Record<string, unknown>>} Manifest
19
14
  */
@@ -44,9 +39,9 @@ export const permits = {
44
39
  * @param {ManifestBundleRef} inputs.manifestBundleRef
45
40
  * @param {FlatMethargs} inputs.getManifestCall
46
41
  * @param {Manifest} [inputs.customManifest]
47
- * @param {typeof import('@endo/far').E} inputs.E
42
+ * @param {typeof E} inputs.E
48
43
  * @param {(...args: unknown[]) => void} [inputs.log]
49
- * @param {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise<import('@agoric/zoe/src/zoeService/utils.js').Installation<unknown>>} [inputs.customRestoreRef]
44
+ * @param {(ref: ManifestBundleRef) => Promise<Installation<unknown>>} [inputs.customRestoreRef]
50
45
  * @returns {(vatPowers: unknown) => Promise<unknown>}
51
46
  */
52
47
  export const makeCoreProposalBehavior = ({
@@ -83,7 +78,7 @@ export const makeCoreProposalBehavior = ({
83
78
  };
84
79
 
85
80
  const makeRestoreRef = (vatAdminSvc, zoe) => {
86
- /** @type {(ref: import('./externalTypes.js').ManifestBundleRef) => Promise<Installation<unknown>>} */
81
+ /** @type {(ref: ManifestBundleRef) => Promise<Installation<unknown>>} */
87
82
  const defaultRestoreRef = async bundleRef => {
88
83
  // extract-proposal.js creates these records, and bundleName is
89
84
  // the optional name under which the bundle was installed into
@@ -193,7 +188,7 @@ export const makeCoreProposalBehavior = ({
193
188
  /**
194
189
  * @param {object} inputs
195
190
  * @param {Array<{ ref: ManifestBundleRef, call: FlatMethargs, customManifest?: Manifest }>} inputs.metadataRecords
196
- * @param {typeof import('@endo/far').E} inputs.E
191
+ * @param {typeof E} inputs.E
197
192
  */
198
193
  export const makeEnactCoreProposalsFromBundleRef = ({ metadataRecords, E }) => {
199
194
  /**
@@ -3,7 +3,8 @@ import { E } from '@endo/far';
3
3
 
4
4
  /**
5
5
  * @import {Amount, Brand, Issuer, Payment, Purse} from '@agoric/ertp';
6
- * @import {InvitationDetails} from '@agoric/zoe';
6
+ * @import {Invitation, InvitationDetails} from '@agoric/zoe';
7
+ * @import {ERef} from '@agoric/vow';
7
8
  */
8
9
 
9
10
  /**
@@ -4,6 +4,11 @@ import { E, Far } from '@endo/far';
4
4
  import { encodeBase64, decodeBase64 } from '@endo/base64';
5
5
  import { ZipWriter } from '@endo/zip';
6
6
 
7
+ /**
8
+ * @import {ZoeService} from '@agoric/zoe';
9
+ * @import {ERef} from '@agoric/vow';
10
+ */
11
+
7
12
  export const start = () => {
8
13
  /** @type { Map<string, [string, Uint8Array]>} */
9
14
  const hashToEntry = new Map();
@@ -3,6 +3,15 @@ export {};
3
3
 
4
4
  /**
5
5
  * @import {NameHub} from '@agoric/vats';
6
+ * @import {ZoeService} from '@agoric/zoe';
7
+ * @import {BundleSource} from '@endo/bundle-source';
8
+ * @import {writeFile as WriteFile} from 'node:fs/promises';
9
+ * @import {ERef} from '@agoric/vow';
10
+ * @import {ScratchPad} from '@agoric/internal/src/scratch.js';
11
+ * @import {CoreEvalMaterialRecord} from './writeCoreEvalParts.js';
12
+ * @import {Bank} from '@agoric/vats/src/vat-bank.js';
13
+ * @import {Board} from '@agoric/vats';
14
+ * @import {NameAdmin} from '@agoric/vats';
6
15
  */
7
16
 
8
17
  // TODO move this type somewhere better
@@ -54,30 +63,33 @@ export {};
54
63
 
55
64
  /**
56
65
  * @typedef {{
57
- * bundleSource: typeof import('@endo/bundle-source').default,
66
+ * bundleSource: BundleSource,
58
67
  * cacheDir: string,
59
68
  * lookup: (...path: string[]) => unknown,
69
+ * log?: typeof console.log,
60
70
  * now: () => number,
71
+ * onWriteCoreEval?: (record: CoreEvalMaterialRecord) => void | Promise<void>,
61
72
  * pathResolve: (...path: string[]) => string,
62
73
  * publishBundle: PublishBundleRef,
63
74
  * scriptArgs?: string[],
75
+ * writeFile?: WriteFile,
64
76
  * }} DeployScriptEndownments
65
77
  */
66
78
 
67
79
  /**
68
80
  * @typedef {{
69
- * scratch: ERef<import('@agoric/internal/src/scratch.js').ScratchPad>,
81
+ * scratch: ERef<ScratchPad>,
70
82
  * }} CommonHome
71
83
  */
72
84
 
73
- // TODO wallet as import('@agoric/wallet-backend/src/types').WalletAdmin once it's a module
85
+ // TODO wallet as import('@agoric/wallet-backend/src/types.js').WalletAdmin once it's a module
74
86
  /**
75
87
  * @typedef {CommonHome & {
76
88
  * agoricNames: ERef<NameHub>,
77
- * bank: ERef<import("@agoric/vats/src/vat-bank.js").Bank>,
78
- * board: ERef<import("@agoric/vats").Board>,
89
+ * bank: ERef<Bank>,
90
+ * board: ERef<Board>,
79
91
  * faucet: unknown,
80
- * myAddressNameAdmin: ERef<import("@agoric/vats").NameAdmin>,
92
+ * myAddressNameAdmin: ERef<NameAdmin>,
81
93
  * namesByAddress: ERef<NameHub>,
82
94
  * wallet: any,
83
95
  * zoe: ERef<ZoeService>,
@@ -1,9 +1,9 @@
1
1
  // @ts-check
2
2
  import { Fail } from '@endo/errors';
3
3
  import { deeplyFulfilledObject } from '@agoric/internal';
4
- import fs from 'fs';
5
- import { createRequire } from 'module';
6
- import path from 'path';
4
+ import fs from 'node:fs';
5
+ import { createRequire } from 'node:module';
6
+ import path from 'node:path';
7
7
 
8
8
  import { defangAndTrim, stringify } from './code-gen.js';
9
9
  import {
@@ -11,6 +11,11 @@ import {
11
11
  makeEnactCoreProposalsFromBundleRef,
12
12
  } from './coreProposalBehavior.js';
13
13
 
14
+ /**
15
+ * @import {CoreEvalBuilder} from './externalTypes.js';
16
+ * @import {PublishBundleRef} from './externalTypes.js';
17
+ */
18
+
14
19
  /**
15
20
  * @typedef {string | {module: string, entrypoint?: string, args?: Array<unknown>}} ConfigProposal
16
21
  */
@@ -155,7 +160,7 @@ export const extractCoreProposalBundles = async (
155
160
  const thisProposalSequence = getSequenceForProposal(key);
156
161
  const initPath = findModule(dirname, module);
157
162
  const initDir = path.dirname(initPath);
158
- /** @type {Record<string, import('./externalTypes.js').CoreEvalBuilder>} */
163
+ /** @type {Record<string, CoreEvalBuilder>} */
159
164
  const ns = await import(initPath);
160
165
  const install = (srcSpec, bundlePath) => {
161
166
  const absoluteSrc = findModule(initDir, srcSpec);
@@ -181,7 +186,7 @@ export const extractCoreProposalBundles = async (
181
186
  );
182
187
  return bundleHandle;
183
188
  };
184
- /** @type {import('./externalTypes.js').PublishBundleRef} */
189
+ /** @type {PublishBundleRef} */
185
190
  const publishRef = async handleP => {
186
191
  const handle = await handleP;
187
192
  bundleHandleToAbsolutePaths.has(handle) ||
@@ -11,9 +11,13 @@
11
11
  * linked with https://github.com/agoric/agoric-sdk/issues/4564
12
12
  */
13
13
  import { E } from '@endo/far';
14
- import url from 'url';
14
+ import url from 'node:url';
15
15
 
16
- /** @typedef {ReturnType<import('./endo-pieces-contract.js')['start']>['publicFacet']} BundleMaker */
16
+ /**
17
+ * @import {start} from './endo-pieces-contract.js';
18
+ */
19
+
20
+ /** @typedef {ReturnType<typeof start>['publicFacet']} BundleMaker */
17
21
  /** @typedef {ReturnType<BundleMaker['makeBundler']>} Bundler */
18
22
 
19
23
  export const makeGetBundlerMaker =
package/src/helpers.js CHANGED
@@ -1,12 +1,10 @@
1
1
  // @ts-check
2
2
 
3
- /// <reference path="../../zoe/exported.js" />
4
-
5
3
  import { E } from '@endo/far';
6
4
  import bundleSource from '@endo/bundle-source';
7
5
 
8
- import fs from 'fs/promises';
9
- import os from 'os';
6
+ import fs from 'node:fs/promises';
7
+ import os from 'node:os';
10
8
 
11
9
  import { makeInstall } from './install.js';
12
10
  import { makeOfferAndFindInvitationAmount } from './offer.js';
@@ -19,6 +17,13 @@ import { assertOfferResult } from './assertOfferResult.js';
19
17
  import { installInPieces } from './installInPieces.js';
20
18
  import { makeWriteCoreEval } from './writeCoreEvalParts.js';
21
19
 
20
+ /**
21
+ * @import {CommonHome} from './externalTypes.js';
22
+ * @import {AgSoloHome} from './externalTypes.js';
23
+ * @import {DeployScriptEndownments} from './externalTypes.js';
24
+ * @import {WriteCoreEval} from './writeCoreEvalParts.js';
25
+ */
26
+
22
27
  export * from '@agoric/internal/src/node/createBundles.js';
23
28
  export { parseScriptArgs } from './parseCoreEvalArgs.js';
24
29
 
@@ -54,8 +59,8 @@ const makeLazyObject = sourceObject => {
54
59
  };
55
60
 
56
61
  /**
57
- * @param {Promise<import('./externalTypes.js').CommonHome | import('./externalTypes.js').AgSoloHome>} homePromise
58
- * @param {import('./externalTypes.js').DeployScriptEndownments} endowments
62
+ * @param {Promise<CommonHome | AgSoloHome>} homePromise
63
+ * @param {DeployScriptEndownments} endowments
59
64
  */
60
65
  export const makeHelpers = async (homePromise, endowments) => {
61
66
  // Endowments provided via `agoric run` or `agoric deploy`.
@@ -65,6 +70,9 @@ export const makeHelpers = async (homePromise, endowments) => {
65
70
  publishBundle,
66
71
  pathResolve,
67
72
  cacheDir = pathResolve(os.homedir(), '.agoric/cache'),
73
+ onWriteCoreEval,
74
+ writeFile,
75
+ log,
68
76
  } = endowments;
69
77
 
70
78
  // Internal-to-this-function lazy dependencies.
@@ -146,11 +154,14 @@ export const makeHelpers = async (homePromise, endowments) => {
146
154
  get getBundlerMaker() {
147
155
  return makeGetBundlerMaker(homePromise, { bundleSource, lookup });
148
156
  },
149
- /** @returns {import('./writeCoreEvalParts.js').WriteCoreEval} */
157
+ /** @returns {WriteCoreEval} */
150
158
  get writeCoreEval() {
151
159
  return makeWriteCoreEval(homePromise, endowments, {
152
160
  getBundleSpec: deps.cacheAndGetBundleSpec,
153
161
  getBundlerMaker: helpers.getBundlerMaker,
162
+ ...(onWriteCoreEval && { onWriteCoreEval }),
163
+ ...(log && { log }),
164
+ ...(writeFile && { writeFile }),
154
165
  });
155
166
  },
156
167
  /** @deprecated use writeCoreEval */
@@ -158,6 +169,9 @@ export const makeHelpers = async (homePromise, endowments) => {
158
169
  return makeWriteCoreEval(homePromise, endowments, {
159
170
  getBundleSpec: deps.cacheAndGetBundleSpec,
160
171
  getBundlerMaker: helpers.getBundlerMaker,
172
+ ...(onWriteCoreEval && { onWriteCoreEval }),
173
+ ...(log && { log }),
174
+ ...(writeFile && { writeFile }),
161
175
  });
162
176
  },
163
177
  });
package/src/install.js CHANGED
@@ -3,13 +3,18 @@ import './externalTypes.js';
3
3
 
4
4
  import { E } from '@endo/far';
5
5
 
6
- /** @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js' */
6
+ /**
7
+ * @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js'
8
+ * @import {Installation, ZoeService} from '@agoric/zoe';
9
+ * @import {InstallationManager} from './startInstance.js';
10
+ * @import {ERef} from '@agoric/vow';
11
+ */
7
12
 
8
13
  // XXX board is Board but specifying that leads to type errors with imports which aren't worth fixing right now
9
14
  /**
10
15
  * @param {typeof import('@endo/bundle-source')['default']} bundleSource
11
16
  * @param {ERef<ZoeService>} zoe
12
- * @param {ERef<import('./startInstance.js').InstallationManager>} installationManager
17
+ * @param {ERef<InstallationManager>} installationManager
13
18
  * @param {ERef<any>} board
14
19
  * @param {(bundle: any) => any} [publishBundle]
15
20
  * @param {(path: string) => string} [pathResolve]
@@ -2,7 +2,7 @@
2
2
  import { E } from '@endo/far';
3
3
  import { ZipReader } from '@endo/zip';
4
4
  import { encodeBase64, decodeBase64 } from '@endo/base64';
5
- import crypto from 'crypto';
5
+ import crypto from 'node:crypto';
6
6
 
7
7
  const computeSha512 = bytes => {
8
8
  const hash = crypto.createHash('sha512');
package/src/offer.js CHANGED
@@ -3,11 +3,13 @@ import { assert } from '@endo/errors';
3
3
  import { E } from '@endo/far';
4
4
  // Avoid pulling in too many dependencies like notifiers
5
5
  import { AmountMath } from '@agoric/ertp/src/amountMath.js';
6
+ import { objectMap } from '@agoric/internal';
6
7
 
7
8
  /**
8
9
  * @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js';
9
10
  * @import {Amount, Brand, Issuer, Payment, Purse} from '@agoric/ertp';
10
- * @import {InvitationDetails, Keyword, Proposal} from '@agoric/zoe';
11
+ * @import {Invitation, InvitationAmount, InvitationDetails, Keyword, Proposal, ProposalRecord, ZoeService} from '@agoric/zoe';
12
+ * @import {ERef} from '@agoric/vow';
11
13
  */
12
14
 
13
15
  /**
@@ -53,17 +55,22 @@ export const makeOfferAndFindInvitationAmount = (
53
55
  return AmountMath.make(invitationAmount.brand, value);
54
56
  };
55
57
 
58
+ /**
59
+ * @param {Partial<ProposalRecord>} proposal
60
+ * @param {Record<Keyword, Petname>} paymentsWithPursePetnames
61
+ * @returns {Record<Keyword, ERef<Payment>>} payments
62
+ */
56
63
  const withdrawPayments = (proposal, paymentsWithPursePetnames) => {
57
- return Object.fromEntries(
58
- Object.entries(paymentsWithPursePetnames).map(
59
- ([keyword, pursePetname]) => {
60
- const purse = E(walletAdmin).getPurse(pursePetname);
61
- const amountToWithdraw = proposal.give[keyword];
62
- const paymentP = E(purse).withdraw(amountToWithdraw);
63
- return [keyword, paymentP];
64
- },
65
- ),
66
- );
64
+ return objectMap(paymentsWithPursePetnames, (pursePetname, keyword) => {
65
+ const purse = E(walletAdmin).getPurse(pursePetname);
66
+ assert(
67
+ 'give' in proposal && proposal.give,
68
+ `proposal.give is required to withdraw`,
69
+ );
70
+ const amountToWithdraw = proposal.give[keyword];
71
+ const paymentP = E(purse).withdraw(amountToWithdraw);
72
+ return paymentP;
73
+ });
67
74
  };
68
75
 
69
76
  const withdrawInvitation = async invitationDetails => {
@@ -2,7 +2,7 @@
2
2
  * To customize proposals for multiple environments, we pass the "variant"
3
3
  * identifier in scriptArgs. The variant must match a knownVariant.
4
4
  *
5
- * @param {import('./externalTypes.js').DeployScriptEndownments} endowments
5
+ * @param {DeployScriptEndownments} endowments
6
6
  * @param {string} name a name to use in error messages or Usage suggestions.
7
7
  * @param {string[]} knownVariants
8
8
  */
@@ -12,6 +12,10 @@ export const parseScriptArgs = async (endowments, name, knownVariants) => {
12
12
  const variantOrConfig =
13
13
  scriptArgs && scriptArgs.length > 0 ? scriptArgs : undefined;
14
14
 
15
+ /**
16
+ * @import {DeployScriptEndownments} from './externalTypes.js';
17
+ */
18
+
15
19
  console.log(`${name}`, variantOrConfig);
16
20
 
17
21
  const Usage = `agoric run ${name}.js ${[...knownVariants, '<json-config>'].join(' | ')}`;
package/src/saveIssuer.js CHANGED
@@ -4,12 +4,14 @@ import { E } from '@endo/far';
4
4
  /**
5
5
  * @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js';
6
6
  * @import {Amount, Brand, Issuer, Payment} from '@agoric/ertp';
7
+ * @import {IssuerManager} from './startInstance.js';
8
+ * @import {ERef} from '@agoric/vow';
7
9
  */
8
10
 
9
11
  /**
10
12
  * @param {ERef<any>} walletAdmin - an internal type of the
11
13
  * wallet, not defined here
12
- * @param {ERef<import('./startInstance.js').IssuerManager>} issuerManager
14
+ * @param {ERef<IssuerManager>} issuerManager
13
15
  */
14
16
  export const makeSaveIssuer = (walletAdmin, issuerManager) => {
15
17
  /**
@@ -1,11 +1,13 @@
1
1
  // @ts-check
2
+ import { objectMap } from '@agoric/internal';
2
3
  import { assert } from '@endo/errors';
3
4
  import { E, passStyleOf } from '@endo/far';
4
5
 
5
6
  /**
6
7
  * @import {Petname} from '@agoric/deploy-script-support/src/externalTypes.js';
7
8
  * @import {Amount, Brand, Issuer, Payment, Purse} from '@agoric/ertp';
8
- * @import {IssuerKeywordRecord, Keyword} from '@agoric/zoe';
9
+ * @import {Instance, Installation, IssuerKeywordRecord, Keyword, ZoeService} from '@agoric/zoe';
10
+ * @import {ERef} from '@agoric/vow';
9
11
  */
10
12
 
11
13
  /**
@@ -36,13 +38,8 @@ export const makeStartInstance = (
36
38
  zoeInvitationPurse,
37
39
  ) => {
38
40
  const makeIssuerKeywordRecord = issuerPetnameKeywordRecord => {
39
- return Object.fromEntries(
40
- Object.entries(issuerPetnameKeywordRecord).map(
41
- ([keyword, issuerPetname]) => {
42
- const issuerP = E(issuerManager).get(issuerPetname);
43
- return [keyword, issuerP];
44
- },
45
- ),
41
+ return objectMap(issuerPetnameKeywordRecord, issuerPetname =>
42
+ E(issuerManager).get(issuerPetname),
46
43
  );
47
44
  };
48
45
 
@@ -0,0 +1,150 @@
1
+ /* global globalThis */
2
+ /**
3
+ * @file Reusable wallet utilities for portfolio contract testing and operations
4
+ *
5
+ * This module consolidates wallet-related utilities that were previously
6
+ * duplicated across multichain-testing and a3p-integration.
7
+ */
8
+
9
+ import { retryUntilCondition } from '@agoric/client-utils';
10
+ import { YMAX_CONTROL_WALLET_KEY } from '@agoric/portfolio-api/src/portfolio-constants.js';
11
+
12
+ /**
13
+ * @import {UpdateRecord} from '@agoric/smart-wallet/src/smartWallet.js';
14
+ * @import {RetryOptions} from '@agoric/client-utils';
15
+ * @import {SigningSmartWalletKit} from '@agoric/client-utils';
16
+ * @import {Instance} from '@agoric/zoe';
17
+ * @import {BridgeAction} from '@agoric/smart-wallet/src/smartWallet.js';
18
+ */
19
+
20
+ /**
21
+ * Helper to wait for specific wallet updates
22
+ *
23
+ * This provides a higher-level API over retryUntilCondition for common
24
+ * wallet update patterns.
25
+ *
26
+ * @param {() => Promise<UpdateRecord>} getLastUpdate
27
+ * @param {RetryOptions & {
28
+ * log: (...args: unknown[]) => void;
29
+ * setTimeout: typeof globalThis.setTimeout;
30
+ * }} retryOpts
31
+ */
32
+ export const walletUpdates = (getLastUpdate, retryOpts) => {
33
+ return harden({
34
+ /**
35
+ * Wait for an invocation to complete
36
+ * @param {string | number} id
37
+ */
38
+ invocation: async id => {
39
+ const done = /** @type {UpdateRecord & { updated: 'invocation' }} */ (
40
+ await retryUntilCondition(
41
+ getLastUpdate,
42
+ update =>
43
+ update.updated === 'invocation' &&
44
+ update.id === id &&
45
+ !!(update.result || update.error),
46
+ `${id}`,
47
+ retryOpts,
48
+ )
49
+ );
50
+ if (done.error) throw Error(done.error);
51
+ return done.result;
52
+ },
53
+
54
+ /**
55
+ * Wait for an offer to complete
56
+ * @param {string | number} id
57
+ */
58
+ offerResult: async id => {
59
+ const done = await retryUntilCondition(
60
+ getLastUpdate,
61
+ update =>
62
+ // walletAction implies an error, so also stop on that
63
+ update.updated === 'walletAction' ||
64
+ // if it's offerStatus, it can be in progress until result or error
65
+ (update.updated === 'offerStatus' &&
66
+ update.status.id === id &&
67
+ (!!update.status.result || !!update.status.error)),
68
+ `${id}`,
69
+ retryOpts,
70
+ );
71
+ switch (done.updated) {
72
+ case 'walletAction':
73
+ throw Error(`walletAction failure: ${done.status.error}`);
74
+ case 'offerStatus':
75
+ if (done.status.error) {
76
+ throw Error(`offerStatus failure: ${done.status.error}`);
77
+ }
78
+ if (!done.status.result) {
79
+ throw Error(`offerStatus missing result`);
80
+ }
81
+ return done.status.result;
82
+ default:
83
+ throw Error(`unexpected update type ${done.updated}`);
84
+ }
85
+ },
86
+ });
87
+ };
88
+
89
+ /**
90
+ * Redeem the ymaxControl invitation from the postal service
91
+ *
92
+ * This is a common pattern in ymax testing where we need to redeem
93
+ * the control facet invitation delivered via postal service.
94
+ *
95
+ * @param {{
96
+ * sig: SigningSmartWalletKit;
97
+ * postalServiceInstance: Instance;
98
+ * fresh: () => string | number;
99
+ * log?: (...args: unknown[]) => void;
100
+ * }} options
101
+ * @returns {Promise<void>}
102
+ */
103
+ export const redeemYmaxControlInvitation = async ({
104
+ sig,
105
+ postalServiceInstance,
106
+ fresh,
107
+ log = () => {},
108
+ }) => {
109
+ const id = `redeem-${YMAX_CONTROL_WALLET_KEY}-${fresh()}`;
110
+ log('Redeeming ymaxControl invitation', id);
111
+
112
+ /** @type {BridgeAction} */
113
+ const redeemAction = harden({
114
+ method: 'executeOffer',
115
+ offer: {
116
+ id,
117
+ invitationSpec: {
118
+ source: 'purse',
119
+ instance: postalServiceInstance,
120
+ description: `deliver ${YMAX_CONTROL_WALLET_KEY}`,
121
+ },
122
+ proposal: {},
123
+ saveResult: { name: YMAX_CONTROL_WALLET_KEY, overwrite: true },
124
+ },
125
+ });
126
+
127
+ const tx = await sig.sendBridgeAction(redeemAction);
128
+ if (tx.code !== 0) {
129
+ throw Error(`Failed to redeem invitation: ${tx.rawLog}`);
130
+ }
131
+
132
+ const wup = walletUpdates(sig.query.getLastUpdate, {
133
+ setTimeout: globalThis.setTimeout,
134
+ log,
135
+ });
136
+
137
+ await wup.offerResult(id);
138
+ log('ymaxControl invitation redeemed successfully');
139
+ };
140
+
141
+ /**
142
+ * Helper to create action IDs with a consistent format
143
+ *
144
+ * @param {string} description
145
+ * @param {() => string | number} [fresh]
146
+ * @returns {string}
147
+ */
148
+ export const makeActionId = (description, fresh = () => Date.now()) => {
149
+ return `${description}.${fresh()}`;
150
+ };
@@ -1,5 +1,5 @@
1
1
  // @ts-check
2
- import fs from 'fs';
2
+ import fs from 'node:fs';
3
3
  import { E } from '@endo/far';
4
4
  import { deeplyFulfilled } from '@endo/marshal';
5
5
 
@@ -12,7 +12,9 @@ import {
12
12
 
13
13
  /**
14
14
  * @import {BundleSource, BundleSourceResult} from '@endo/bundle-source';
15
- * @import {AgSoloHome, CanonicalHome, CommonHome, CoreEvalBuilder, CoreEvalDescriptor, ManifestBundleRef} from './externalTypes.js';
15
+ * @import {AgSoloHome, CommonHome, CoreEvalBuilder, CoreEvalDescriptor, ManifestBundleRef} from './externalTypes.js';
16
+ * @import {BundleMaker} from './getBundlerMaker.js';
17
+ * @import {Bundler} from './getBundlerMaker.js';
16
18
  */
17
19
 
18
20
  /**
@@ -20,7 +22,14 @@ import {
20
22
  * @property {string} name
21
23
  * @property {string} permit
22
24
  * @property {string} script
23
- * @property {{entrypoint: string, bundleID: string, fileName: string}[]} bundles
25
+ * @property {{entrypoint: string, bundleID?: string, bundleName?: string, fileName?: string}[]} bundles
26
+ */
27
+ /**
28
+ * @typedef {{
29
+ * plan: CoreEvalPlan,
30
+ * eval: { json_permits: string, js_code: string },
31
+ * bundles: { entrypoint: string, bundleID?: string, bundleName?: string, fileName?: string, bundle: BundleSourceResult<'endoZipBase64'> }[],
32
+ * }} CoreEvalMaterialRecord
24
33
  */
25
34
 
26
35
  /**
@@ -40,9 +49,10 @@ import {
40
49
  * pathResolve: (path: string) => string,
41
50
  * }} endowments
42
51
  * @param {{
43
- * getBundlerMaker: () => Promise<import('./getBundlerMaker.js').BundleMaker>,
44
- * getBundleSpec: (bundle: Promise<BundleSourceResult<'endoZipBase64'>>, getBundle: () => import('./getBundlerMaker.js').Bundler, opts?: any) => Promise<ManifestBundleRef>,
52
+ * getBundlerMaker: () => Promise<BundleMaker>,
53
+ * getBundleSpec: (bundle: Promise<BundleSourceResult<'endoZipBase64'>>, getBundle: () => Bundler, opts?: any) => Promise<ManifestBundleRef>,
45
54
  * log?: typeof console.log,
55
+ * onWriteCoreEval?: (record: CoreEvalMaterialRecord) => void | Promise<void>,
46
56
  * writeFile?: typeof fs.promises.writeFile
47
57
  * }} io
48
58
  * @returns {WriteCoreEval}
@@ -54,13 +64,14 @@ export const makeWriteCoreEval = (
54
64
  getBundlerMaker,
55
65
  getBundleSpec,
56
66
  log = console.log,
67
+ onWriteCoreEval = () => {},
57
68
  writeFile = fs.promises.writeFile,
58
69
  },
59
70
  ) => {
60
71
  const { bundleSource, pathResolve } = endowments;
61
72
 
62
73
  let bundlerCache;
63
- /** @returns {import('./getBundlerMaker.js').Bundler} */
74
+ /** @returns {Bundler} */
64
75
  const getBundler = () => {
65
76
  if (!bundlerCache) {
66
77
  bundlerCache = E(getBundlerMaker()).makeBundler({
@@ -118,7 +129,8 @@ export const makeWriteCoreEval = (
118
129
  return ns.default;
119
130
  };
120
131
 
121
- const bundles = [];
132
+ /** @type {CoreEvalMaterialRecord['bundles']} */
133
+ const bundleRecords = [];
122
134
 
123
135
  /**
124
136
  * Install an entrypoint.
@@ -134,9 +146,13 @@ export const makeWriteCoreEval = (
134
146
  // Serialise the installations.
135
147
  mutex = E.when(mutex, async () => {
136
148
  // console.log('installing', { filePrefix, entrypoint, bundlePath });
137
- const spec = await getBundleSpec(bundle, getBundler, opts);
138
- bundles.push({
149
+ const [spec, builtBundle] = await Promise.all([
150
+ getBundleSpec(bundle, getBundler, opts),
151
+ bundle,
152
+ ]);
153
+ bundleRecords.push({
139
154
  entrypoint,
155
+ bundle: builtBundle,
140
156
  ...spec,
141
157
  });
142
158
  return spec;
@@ -203,13 +219,21 @@ behavior;
203
219
  name: filePrefix,
204
220
  script: codeFile,
205
221
  permit: permitFile,
206
- bundles,
222
+ bundles: bundleRecords.map(({ bundle: _bundle, ...spec }) => spec),
207
223
  };
208
224
 
209
225
  await writeFile(
210
226
  `${filePrefix}-plan.json`,
211
227
  `${JSON.stringify(plan, null, 2)}\n`,
212
228
  );
229
+ await onWriteCoreEval({
230
+ plan,
231
+ eval: {
232
+ json_permits: JSON.stringify(evalPermits, null, 2),
233
+ js_code: trimmed,
234
+ },
235
+ bundles: bundleRecords,
236
+ });
213
237
 
214
238
  log(`\
215
239
  You can now run a governance submission command like: