@agoric/deploy-script-support 0.10.3 → 0.10.4-calypso-dev-84eb287.0

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.
@@ -0,0 +1,227 @@
1
+ // @ts-check
2
+ import fs from 'fs';
3
+ import { E } from '@endo/far';
4
+ import { deeplyFulfilled } from '@endo/marshal';
5
+
6
+ import { createBundles } from '@agoric/internal/src/node/createBundles.js';
7
+ import { defangAndTrim, mergePermits, stringify } from './code-gen.js';
8
+ import {
9
+ makeCoreProposalBehavior,
10
+ permits as defaultPermits,
11
+ } from './coreProposalBehavior.js';
12
+
13
+ /**
14
+ * @import {CoreEvalDescriptor} from './externalTypes.js';
15
+ */
16
+
17
+ /**
18
+ * @typedef CoreEvalPlan
19
+ * @property {string} name
20
+ * @property {string} permit
21
+ * @property {string} script
22
+ * @property {{entrypoint: string, bundleID: string, fileName: string}[]} bundles
23
+ */
24
+
25
+ /**
26
+ * @callback WriteCoreEval write to disk the files needed for a CoreEval (js code to`${filePrefix}.js`, permits to `${filePrefix}-permit.json`, an overall
27
+ * summary to `${filePrefix}-plan.json), plus whatever bundles bundles the code loads)
28
+ * see CoreEval in {@link '/golang/cosmos/x/swingset/types/swingset.pb.go'}
29
+ * @param {string} filePrefix name on disk
30
+ * @param {import('./externalTypes.js').CoreEvalBuilder} builder
31
+ * @returns {Promise<CoreEvalPlan>}
32
+ */
33
+
34
+ /**
35
+ *
36
+ * @param {*} homeP
37
+ * @param {{
38
+ * bundleSource: (path: string) => Promise<NodeModule>,
39
+ * pathResolve: (path: string) => string,
40
+ * }} endowments
41
+ * @param {{
42
+ * getBundlerMaker: () => Promise<import('./getBundlerMaker.js').BundleMaker>,
43
+ * getBundleSpec: (...args: *) => Promise<import('./externalTypes.js').ManifestBundleRef>,
44
+ * log?: typeof console.log,
45
+ * writeFile?: typeof fs.promises.writeFile
46
+ * }} io
47
+ * @returns {WriteCoreEval}
48
+ */
49
+ export const makeWriteCoreEval = (
50
+ homeP,
51
+ endowments,
52
+ {
53
+ getBundlerMaker,
54
+ getBundleSpec,
55
+ log = console.log,
56
+ writeFile = fs.promises.writeFile,
57
+ },
58
+ ) => {
59
+ const { bundleSource, pathResolve } = endowments;
60
+
61
+ let bundlerCache;
62
+ /** @returns {import('./getBundlerMaker.js').Bundler} */
63
+ const getBundler = () => {
64
+ if (!bundlerCache) {
65
+ bundlerCache = E(getBundlerMaker()).makeBundler({
66
+ zoe: E.get(homeP).zoe,
67
+ });
68
+ }
69
+ return bundlerCache;
70
+ };
71
+
72
+ /**
73
+ *
74
+ * @param {CoreEvalDescriptor} coreEval
75
+ * @param {*} additionalPermits
76
+ */
77
+ const mergeEvalPermit = async (coreEval, additionalPermits) => {
78
+ const {
79
+ sourceSpec,
80
+ getManifestCall: [manifestGetterName, ...manifestGetterArgs],
81
+ } = coreEval;
82
+
83
+ const moduleNamespace = await import(pathResolve(sourceSpec));
84
+
85
+ // We only care about the manifest, not any restoreRef calls.
86
+ const { manifest } = await moduleNamespace[manifestGetterName](
87
+ harden({ restoreRef: x => `restoreRef:${x}` }),
88
+ ...manifestGetterArgs,
89
+ );
90
+
91
+ const mergedPermits = mergePermits(manifest);
92
+ return {
93
+ manifest,
94
+ permits: mergePermits({ mergedPermits, additionalPermits }),
95
+ };
96
+ };
97
+
98
+ let mutex =
99
+ /** @type {Promise<import('./externalTypes.js').ManifestBundleRef | undefined>} */ (
100
+ Promise.resolve()
101
+ );
102
+ /** @type {WriteCoreEval} */
103
+ const writeCoreEval = async (filePrefix, builder) => {
104
+ /**
105
+ *
106
+ * @param {string} entrypoint
107
+ * @param {string} [bundlePath]
108
+ * @returns {Promise<NodeModule>}
109
+ */
110
+ const getBundle = async (entrypoint, bundlePath) => {
111
+ if (!bundlePath) {
112
+ return bundleSource(pathResolve(entrypoint));
113
+ }
114
+ const bundleCache = pathResolve(bundlePath);
115
+ await createBundles([[pathResolve(entrypoint), bundleCache]]);
116
+ const ns = await import(bundleCache);
117
+ return ns.default;
118
+ };
119
+
120
+ const bundles = [];
121
+
122
+ /**
123
+ * Install an entrypoint.
124
+ *
125
+ * @param {string} entrypoint
126
+ * @param {string} [bundlePath]
127
+ * @param {unknown} [opts]
128
+ * @returns {Promise<import('./externalTypes.js').ManifestBundleRef>}
129
+ */
130
+ const install = async (entrypoint, bundlePath, opts) => {
131
+ const bundle = getBundle(entrypoint, bundlePath);
132
+
133
+ // Serialise the installations.
134
+ mutex = E.when(mutex, async () => {
135
+ // console.log('installing', { filePrefix, entrypoint, bundlePath });
136
+ const spec = await getBundleSpec(bundle, getBundler, opts);
137
+ bundles.push({
138
+ entrypoint,
139
+ ...spec,
140
+ });
141
+ return spec;
142
+ });
143
+ // @ts-expect-error xxx mutex type narrowing
144
+ return mutex;
145
+ };
146
+
147
+ // Await a reference then publish to the board.
148
+ const cmds = [];
149
+ /** @param {Promise<import('./externalTypes.js').ManifestBundleRef>} refP */
150
+ const publishRef = async refP => {
151
+ const { fileName, ...ref } = await refP;
152
+ if (fileName) {
153
+ cmds.push(`agd tx swingset install-bundle @${fileName}`);
154
+ }
155
+
156
+ return harden(ref);
157
+ };
158
+
159
+ // Create the eval structure.
160
+ const evalDescriptor = await deeplyFulfilled(
161
+ harden(builder({ publishRef, install })),
162
+ );
163
+ const { sourceSpec, getManifestCall } = evalDescriptor;
164
+ // console.log('created', { filePrefix, sourceSpec, getManifestCall });
165
+
166
+ // Extract the top-level permit.
167
+ const { permits: evalPermits, manifest: customManifest } =
168
+ await mergeEvalPermit(evalDescriptor, defaultPermits);
169
+
170
+ // Get an install
171
+ const manifestBundleRef = await publishRef(install(sourceSpec));
172
+
173
+ // console.log('writing', { filePrefix, manifestBundleRef, sourceSpec });
174
+ const code = `\
175
+ // This is generated by writeCoreEval; please edit!
176
+ /* eslint-disable */
177
+
178
+ const manifestBundleRef = ${stringify(manifestBundleRef)};
179
+ const getManifestCall = harden(${stringify(getManifestCall, true)});
180
+ const customManifest = ${stringify(customManifest, true)};
181
+
182
+ // Make a behavior function and "export" it by way of script completion value.
183
+ // It is constructed by an anonymous invocation to ensure the absence of a global binding
184
+ // for makeCoreProposalBehavior, which may not be necessary but preserves behavior pre-dating
185
+ // https://github.com/Agoric/agoric-sdk/pull/8712 .
186
+ const behavior = (${makeCoreProposalBehavior})({ manifestBundleRef, getManifestCall, customManifest, E });
187
+ behavior;
188
+ `;
189
+
190
+ const trimmed = defangAndTrim(code);
191
+
192
+ const permitFile = `${filePrefix}-permit.json`;
193
+ log(`creating ${permitFile}`);
194
+ await writeFile(permitFile, JSON.stringify(evalPermits, null, 2));
195
+
196
+ const codeFile = `${filePrefix}.js`;
197
+ log(`creating ${codeFile}`);
198
+ await writeFile(codeFile, trimmed);
199
+
200
+ /** @type {CoreEvalPlan} */
201
+ const plan = {
202
+ name: filePrefix,
203
+ script: codeFile,
204
+ permit: permitFile,
205
+ bundles,
206
+ };
207
+
208
+ await writeFile(
209
+ `${filePrefix}-plan.json`,
210
+ `${JSON.stringify(plan, null, 2)}\n`,
211
+ );
212
+
213
+ log(`\
214
+ You can now run a governance submission command like:
215
+ agd tx gov submit-proposal swingset-core-eval ${permitFile} ${codeFile} \\
216
+ --title="Enable <something>" --description="Evaluate ${codeFile}" --deposit=1000000ubld \\
217
+ --gas=auto --gas-adjustment=1.2
218
+ Remember to install bundles before submitting the proposal:
219
+ ${cmds.join('\n ')}
220
+ `);
221
+ return plan;
222
+ };
223
+
224
+ return writeCoreEval;
225
+ };
226
+ /** @deprecated use makeWriteCoreEval */
227
+ export const makeWriteCoreProposal = makeWriteCoreEval;