openzoo 0.51.4 → 0.51.5

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.
Files changed (50) hide show
  1. package/bin/openzoo.js +0 -37
  2. package/lib/config.js +34 -0
  3. package/lib/pay.js +60 -4
  4. package/package.json +4 -7
  5. package/transmute/README.md +0 -385
  6. package/transmute/bin/openzoo-transmute.js +0 -7
  7. package/transmute/docs/OPENZOO_CLI_PATCH.md +0 -139
  8. package/transmute/docs/VERCEL_TO_SOLANA.md +0 -381
  9. package/transmute/lib/build.js +0 -381
  10. package/transmute/lib/cli.js +0 -293
  11. package/transmute/lib/compile/bytecode.js +0 -591
  12. package/transmute/lib/compile/hostids.js +0 -11
  13. package/transmute/lib/compile/index.js +0 -159
  14. package/transmute/lib/compile/ir.js +0 -1634
  15. package/transmute/lib/compile/parse.js +0 -753
  16. package/transmute/lib/compile/rust.js +0 -781
  17. package/transmute/lib/deploy.js +0 -357
  18. package/transmute/lib/eligibility.js +0 -211
  19. package/transmute/lib/gateway.js +0 -710
  20. package/transmute/lib/hub.js +0 -290
  21. package/transmute/lib/solana.js +0 -387
  22. package/transmute/lib/vercel.js +0 -296
  23. package/transmute/lib/wallet.js +0 -41
  24. package/transmute/lib/wire.js +0 -208
  25. package/transmute/prebuilt/zoo_vm.v0.so +0 -0
  26. package/transmute/runtime/zoo-host/Cargo.lock +0 -588
  27. package/transmute/runtime/zoo-host/Cargo.toml +0 -30
  28. package/transmute/runtime/zoo-host/examples/vmrun.rs +0 -43
  29. package/transmute/runtime/zoo-host/src/assets.rs +0 -214
  30. package/transmute/runtime/zoo-host/src/ctx.rs +0 -350
  31. package/transmute/runtime/zoo-host/src/fmt.rs +0 -188
  32. package/transmute/runtime/zoo-host/src/helpers.rs +0 -245
  33. package/transmute/runtime/zoo-host/src/json.rs +0 -263
  34. package/transmute/runtime/zoo-host/src/kv.rs +0 -206
  35. package/transmute/runtime/zoo-host/src/lib.rs +0 -137
  36. package/transmute/runtime/zoo-host/src/site.rs +0 -94
  37. package/transmute/runtime/zoo-host/src/val.rs +0 -1050
  38. package/transmute/runtime/zoo-host/src/vm.rs +0 -902
  39. package/transmute/runtime/zoo-host/src/wire.rs +0 -239
  40. package/transmute/runtime/zoo-vm/Cargo.lock +0 -596
  41. package/transmute/runtime/zoo-vm/Cargo.toml +0 -23
  42. package/transmute/runtime/zoo-vm/src/lib.rs +0 -92
  43. package/transmute/site/.env.production +0 -2
  44. package/transmute/site/api/echo.js +0 -10
  45. package/transmute/site/api/hello.js +0 -12
  46. package/transmute/site/api/hits.js +0 -13
  47. package/transmute/site/api/time.js +0 -5
  48. package/transmute/site/package.json +0 -6
  49. package/transmute/site/public/app.js +0 -16
  50. package/transmute/site/public/index.html +0 -96
@@ -1,293 +0,0 @@
1
- // The openzoo-transmute command line.
2
- //
3
- // The openzoo package can mount these subcommands in its own bin without
4
- // duplicating anything:
5
- //
6
- // case 'build': case 'deploy': case 'serve':
7
- // await (await import('openzoo-transmute/lib/cli.js')).run(process.argv.slice(2));
8
- //
9
- // `run(argv)` resolves to the exit code (0 = ok) and also sets
10
- // `process.exitCode` when non-zero; it never calls `process.exit` itself so a
11
- // `serve` keeps the event loop (and the http server) alive.
12
- import fs from 'node:fs';
13
- import path from 'node:path';
14
- import { PublicKey } from '@solana/web3.js';
15
- import { readDeployment } from './vercel.js';
16
- import { build } from './build.js';
17
- import { deploy, deployRuntime, resolveOutDir, clusterLabel } from './deploy.js';
18
- import { startGateway, DEFAULT_PORT } from './gateway.js';
19
- import { startHub, DEFAULT_HUB_PORT } from './hub.js';
20
- import { connect, getProgramInfo, getSiteInfo, readManifest } from './solana.js';
21
- import { loadWallet, rpcUrl } from './wallet.js';
22
- import { MANIFEST_PATH } from './wire.js';
23
-
24
- export const USAGE = `openzoo-transmute — Vercel app → Solana program + asset accounts
25
-
26
- usage:
27
- openzoo-transmute build [dir] [--target shared|program] [--out .zoo-out] [--name <crate>] [--arch v0|v3] [--cluster <c>] [--skip-cargo]
28
- --target shared (default): bytecode for the shared zoo-vm runtime — a site is data accounts only (≈0.05–0.1 SOL)
29
- --target program: your own Pinocchio program per site (≈1 SOL+)
30
- openzoo-transmute deploy [dir|outDir] [--cluster mainnet|devnet|localnet|<url>] [--keypair <path>] [--yes] [--runtime <zoo-vm id>]
31
- [--program <id>] [--concurrency 4] [--skip-assets] [--force] [--headroom 1.5]
32
- openzoo-transmute serve <siteId|programId> [--runtime <zoo-vm id>] [--cluster <c>] [--port ${DEFAULT_PORT}] [--keypair <path>] [--host 127.0.0.1] [--quiet]
33
- openzoo-transmute runtime deploy [--cluster <c>] [--keypair <path>] [--yes] [--program-keypair zoo-vm-keypair.json] [--so <path>]
34
- deploy (or upgrade) the shared zoo-vm runtime once per cluster
35
- openzoo-transmute runtime status <zoo-vm id> [--cluster <c>]
36
- openzoo-transmute hub [--cluster mainnet] [--port 8080] [--host 0.0.0.0] [--public-url <https://…>]
37
- hosted explorer for EVERY program on the cluster (/s/<programId>), read-only
38
- openzoo-transmute inspect [dir] print the Vercel model + eligibility report
39
- openzoo-transmute status <programId> [--cluster <c>]
40
- openzoo-transmute help
41
-
42
- clusters: mainnet (default, needs --yes to deploy), devnet, testnet, localnet, or an RPC URL.
43
- env: OPENZOO_CLUSTER, OPENZOO_RPC (mainnet RPC), OPENZOO_KEYPAIR / OPENZOO_WALLET (signer), OPENZOO_VM_PROGRAM (shared runtime id).
44
- `;
45
-
46
- /** `--k v`, `--k=v`, `--flag`, `--no-flag`; everything else is positional. */
47
- export function parseArgs(argv) {
48
- const flags = {};
49
- const positionals = [];
50
- const boolFlags = new Set(['yes', 'skip-cargo', 'skip-assets', 'force', 'quiet', 'help', 'json', 'version']);
51
- for (let i = 0; i < argv.length; i++) {
52
- const a = argv[i];
53
- if (a === '--') { positionals.push(...argv.slice(i + 1)); break; }
54
- if (a.startsWith('--')) {
55
- const eq = a.indexOf('=');
56
- let key = eq >= 0 ? a.slice(2, eq) : a.slice(2);
57
- let val;
58
- if (eq >= 0) val = a.slice(eq + 1);
59
- else if (key.startsWith('no-')) { key = key.slice(3); val = false; }
60
- else if (boolFlags.has(key) || i + 1 >= argv.length || argv[i + 1].startsWith('--')) val = true;
61
- else val = argv[++i];
62
- flags[key] = val;
63
- flags[key.replace(/-([a-z])/g, (_, c) => c.toUpperCase())] = val;
64
- } else if (a === '-h') flags.help = true;
65
- else if (a === '-y') flags.yes = true;
66
- else positionals.push(a);
67
- }
68
- return { cmd: positionals[0] || 'help', positionals: positionals.slice(1), flags };
69
- }
70
-
71
- function fmtBytes(n) { return n == null ? '?' : n.toLocaleString() + ' B'; }
72
-
73
- export function inspectText(deployment, report = null) {
74
- const lines = [];
75
- lines.push(`${deployment.root}`);
76
- lines.push(`source: ${deployment.source}${deployment.framework ? ` · framework: ${deployment.framework}` : ''} · static dir: ${deployment.staticDir ? path.relative(deployment.root, deployment.staticDir) || '.' : '-'}`);
77
- for (const n of deployment.notes) lines.push(`note: ${n}`);
78
- lines.push('');
79
- lines.push(`functions (${deployment.functions.length}):`);
80
- const inel = new Map((report?.ineligible || []).map((i) => [i.name, i]));
81
- const elig = new Set((report?.eligible || []).map((e) => (typeof e === 'string' ? e : e.name)));
82
- for (const f of deployment.functions) {
83
- const mark = report ? (inel.has(f.name) ? '✗' : elig.has(f.name) ? '✓' : '?') : ' ';
84
- const meth = f.methods ? f.methods.join(',') : 'any';
85
- lines.push(` ${mark} ${f.routePath.padEnd(32)} ${f.style.padEnd(12)} ${f.runtime.padEnd(11)} ${String(f.maxDuration + 's').padEnd(5)} ${String(f.memory + 'MB').padEnd(7)} ${meth}${f.params.length ? ` params=${f.params.join(',')}` : ''}${f.middleware ? ' middleware' : ''}${f.prerender ? ' ISR' : ''}`);
86
- lines.push(` ${f.sourceFile ? path.relative(deployment.root, f.sourceFile) : '(no source)'}${Object.keys(f.environment || {}).length ? ` env=${Object.keys(f.environment).join(',')}` : ''}`);
87
- const r = inel.get(f.name);
88
- if (r) lines.push(` ineligible: ${r.reason}${r.line ? ` (line ${r.line})` : ''}`);
89
- }
90
- if (deployment.crons.length) { lines.push(''); lines.push(`crons (${deployment.crons.length}) — not transmuted, Solana has no scheduler:`); for (const c of deployment.crons) lines.push(` ${c.schedule || '?'} ${c.path || ''}`); }
91
- lines.push('');
92
- const total = deployment.staticFiles.reduce((n, f) => n + f.size, 0);
93
- lines.push(`static files (${deployment.staticFiles.length}, ${fmtBytes(total)}):`);
94
- for (const f of deployment.staticFiles.slice(0, 60)) lines.push(` ${f.path.padEnd(48)} ${f.contentType.padEnd(32)} ${fmtBytes(f.size)}`);
95
- if (deployment.staticFiles.length > 60) lines.push(` … ${deployment.staticFiles.length - 60} more`);
96
- if (report) {
97
- lines.push('');
98
- lines.push(`eligibility: ${report.eligible.length} eligible, ${report.ineligible.length} ineligible, ${report.warnings.length} warning(s)`);
99
- for (const w of report.warnings) lines.push(` ! ${typeof w === 'string' ? w : w.message || JSON.stringify(w)}`);
100
- }
101
- const routes = deployment.config?.routes || [];
102
- if (routes.length) {
103
- lines.push('');
104
- lines.push(`routes (${routes.length}):`);
105
- for (const r of routes) lines.push(' ' + (r.handle ? `[handle: ${r.handle}]` : `${r.src} → ${r.dest || (r.status ? `status ${r.status}` : '(headers)')}${r.continue ? ' (continue)' : ''}`));
106
- }
107
- return lines.join('\n');
108
- }
109
-
110
- async function tryTransmute(deployment) {
111
- try {
112
- const mod = await import('./compile/index.js');
113
- if (typeof mod.transmute !== 'function') return null;
114
- const r = await mod.transmute(deployment, { name: 'inspect', dryRun: true });
115
- return r?.report || null;
116
- } catch (e) {
117
- if (e?.code === 'ERR_MODULE_NOT_FOUND') return null;
118
- return { eligible: [], ineligible: [], warnings: [`compiler failed: ${e?.message || e}`] };
119
- }
120
- }
121
-
122
- export const DEFAULT_TARGET = 'shared';
123
-
124
- /** `--runtime` is the zoo-vm program id (shared) — or, for `--target program`, a zoo-host checkout path. */
125
- function runtimeFlag(f) {
126
- const v = f.runtime;
127
- if (typeof v !== 'string') return { runtime: process.env.OPENZOO_VM_PROGRAM || null, runtimePath: f.runtimePath || undefined };
128
- if (fs.existsSync(v) && fs.existsSync(path.join(v, 'Cargo.toml'))) return { runtime: process.env.OPENZOO_VM_PROGRAM || null, runtimePath: v };
129
- new PublicKey(v);
130
- return { runtime: v, runtimePath: f.runtimePath || undefined };
131
- }
132
-
133
- async function cmdBuild(p, f, log) {
134
- const target = f.target || process.env.OPENZOO_TARGET || DEFAULT_TARGET;
135
- if (!['shared', 'program'].includes(target)) throw new Error(`--target must be shared or program (got ${target})`);
136
- const { runtime, runtimePath } = runtimeFlag(f);
137
- const r = await build(p[0] || '.', { out: f.out, name: f.name, arch: f.arch, cluster: f.cluster, target, runtime, runtimePath, skipCargo: !!f.skipCargo, log });
138
- if (f.json) log(JSON.stringify({ outDir: r.outDir, target: r.target || 'program', soPath: r.soPath, codePath: r.codePath || null, codeSize: r.codeSize || null, arch: r.arch, report: r.report, costEstimate: { sol: r.costEstimate.sol, totalSol: r.costEstimate.totalSol, source: r.costEstimate.source } }, null, 2));
139
- return r.report.ineligible.length && !r.report.eligible.length && r.manifest.routes.length === 0 && r.deployment.functions.length ? 2 : 0;
140
- }
141
-
142
- async function cmdDeploy(p, f, log) {
143
- const { runtime } = runtimeFlag(f);
144
- const r = await deploy({ outDir: p[0] || '.', cluster: f.cluster, keypair: f.keypair, programId: f.program, runtime, yes: !!f.yes, concurrency: f.concurrency ? Number(f.concurrency) : undefined, skipAssets: !!f.skipAssets, force: !!f.force, headroom: f.headroom, log });
145
- if (f.json) log(JSON.stringify(r, null, 2));
146
- return 0;
147
- }
148
-
149
- async function cmdServe(p, f, log) {
150
- let programId = p[0];
151
- let { runtime } = runtimeFlag(f);
152
- if (!programId) {
153
- // Fall back to the last deploy in ./ or ./.zoo-out.
154
- try {
155
- const d = JSON.parse(fs.readFileSync(path.join(resolveOutDir('.'), '.zoo', 'deploy.json'), 'utf8'));
156
- programId = d.target === 'shared' ? d.site : d.programId;
157
- if (d.target === 'shared' && !runtime) runtime = d.runtime;
158
- } catch { /* none */ }
159
- if (!programId) throw new Error('usage: serve <siteId|programId> [--runtime <zoo-vm id>] (no .zoo/deploy.json found to infer it from)');
160
- }
161
- new PublicKey(programId); // validate
162
- // Shared runtime: the positional is the site id, the program is zoo-vm.
163
- let site = null;
164
- if (runtime) { site = programId; programId = runtime; }
165
- let keypair = null, walletPath = null;
166
- if (f.keypair !== false) {
167
- try { const w = loadWallet({ keypair: typeof f.keypair === 'string' ? f.keypair : undefined }); keypair = w.keypair; walletPath = w.path; }
168
- catch (e) { if (typeof f.keypair === 'string') throw e; log(`no wallet found (${String(e.message).split(';')[0]}); mutating requests will answer 402`); }
169
- }
170
- const port = f.port != null ? Number(f.port) : DEFAULT_PORT;
171
- const host = f.host || '127.0.0.1';
172
- if (keypair && !/^(127\.0\.0\.1|localhost|::1|\[::1\])$/.test(host)) log(`warning: binding ${host} with a signer: anyone who can reach this gateway can send transactions paid by ${keypair.publicKey.toBase58()}; use --no-keypair unless that is intended`);
173
- const gw = await startGateway({ programId, site, cluster: f.cluster, port, host, keypair, log, quiet: !!f.quiet });
174
- const m = gw.state.manifest;
175
- log(`openzoo-transmute gateway → ${gw.url}/ (explorer ${gw.url}/.zoo/, manifest ${gw.url}${MANIFEST_PATH})`);
176
- log(`${site ? `site ${site} on runtime ${programId}` : `program ${programId}`} on ${gw.state.cluster} · ${m.routes.length} function(s), ${m.static ? m.static.length : '?'} asset(s) · signer ${keypair ? keypair.publicKey.toBase58() + (walletPath ? ` (${walletPath})` : '') : 'none (reads only)'}`);
177
- for (const r of m.routes) log(` ${(r.methods && r.methods.length ? r.methods.join('|') : 'ANY').padEnd(16)} ${r.routePath}`);
178
- const stop = () => gw.close().then(() => process.exit(0));
179
- process.once('SIGINT', stop);
180
- process.once('SIGTERM', stop);
181
- return 0;
182
- }
183
-
184
- async function cmdInspect(p, f, log) {
185
- const deployment = readDeployment(p[0] || '.');
186
- const report = await tryTransmute(deployment);
187
- if (f.json) log(JSON.stringify({ ...deployment, report }, null, 2));
188
- else {
189
- log(inspectText(deployment, report));
190
- if (!report) log('\n(compiler not available: eligibility not checked)');
191
- }
192
- return 0;
193
- }
194
-
195
- async function cmdStatus(p, f, log) {
196
- if (!p[0]) throw new Error('usage: status <siteId|programId> [--runtime <zoo-vm id>] [--cluster <c>]');
197
- const { runtime } = runtimeFlag(f);
198
- const rpc = rpcUrl(f.cluster);
199
- const connection = connect(rpc);
200
- if (runtime) {
201
- const site = new PublicKey(p[0]);
202
- const [info, manifest] = await Promise.all([getSiteInfo(connection, new PublicKey(runtime), site), readManifest(connection, new PublicKey(runtime), site).catch(() => null)]);
203
- const out = { site: site.toBase58(), runtime, cluster: clusterLabel(f.cluster), rpc: rpc.replace(/\?.*$/, ''), exists: info.exists, authority: info.authority ? info.authority.toBase58() : null, account: info.pda.toBase58(), manifest: manifest ? { name: manifest.name, routes: manifest.routes?.length ?? 0, static: manifest.static?.length ?? 0, deployedAt: manifest.deployedAt } : null };
204
- if (f.json) { log(JSON.stringify(out, null, 2)); return info.exists ? 0 : 1; }
205
- log(`site ${out.site} on runtime ${runtime} (${out.cluster})`);
206
- if (!info.exists) { log('status NOT DEPLOYED'); return 1; }
207
- log(`authority ${out.authority}`);
208
- log(`account ${out.account}`);
209
- if (manifest) { log(`manifest ${manifest.name || ''} · ${out.manifest.routes} function(s), ${out.manifest.static} asset(s) · deployed ${manifest.deployedAt || '?'}`); for (const r of manifest.routes || []) log(` ${(r.methods && r.methods.length ? r.methods.join('|') : 'ANY').padEnd(16)} ${r.routePath}`); }
210
- else log(`manifest none at ${MANIFEST_PATH}`);
211
- return 0;
212
- }
213
- const programId = new PublicKey(p[0]);
214
- const [info, slot, manifest] = await Promise.all([getProgramInfo(connection, programId), connection.getSlot('confirmed'), readManifest(connection, programId).catch(() => null)]);
215
- const out = {
216
- programId: programId.toBase58(), cluster: clusterLabel(f.cluster), rpc: rpc.replace(/\?.*$/, ''), slot,
217
- exists: info.exists, executable: info.executable ?? null, authority: info.authority ? info.authority.toBase58() : null,
218
- deploySlot: info.slot, maxDataLen: info.maxDataLen, programData: info.programData.toBase58(),
219
- manifest: manifest ? { name: manifest.name, framework: manifest.framework, routes: manifest.routes?.length ?? 0, static: manifest.static?.length ?? 0, deployedAt: manifest.deployedAt, arch: manifest.arch } : null,
220
- };
221
- if (f.json) { log(JSON.stringify(out, null, 2)); return info.exists ? 0 : 1; }
222
- log(`program ${out.programId} on ${out.cluster} (${out.rpc}) @ slot ${slot}`);
223
- if (!info.exists) { log('status NOT DEPLOYED'); return 1; }
224
- log(`status deployed at slot ${out.deploySlot}${out.executable === false ? ' (not executable!)' : ''}`);
225
- log(`authority ${out.authority || 'none (immutable)'}`);
226
- log(`programData ${out.programData} (max ${out.maxDataLen?.toLocaleString()} B)`);
227
- if (manifest) {
228
- log(`manifest ${manifest.name || ''} ${manifest.framework || ''} · ${out.manifest.routes} function(s), ${out.manifest.static} asset(s) · deployed ${manifest.deployedAt || '?'}${manifest.arch ? ` (${manifest.arch})` : ''}`);
229
- for (const r of manifest.routes || []) log(` ${(r.methods && r.methods.length ? r.methods.join('|') : 'ANY').padEnd(16)} ${r.routePath}`);
230
- } else log(`manifest none at ${MANIFEST_PATH}`);
231
- return 0;
232
- }
233
-
234
- /**
235
- * Run the CLI. Returns the exit code; prints errors to stderr.
236
- * @param {string[]} argv arguments after the program name
237
- * @param {{log?:Function, error?:Function}} io
238
- */
239
- async function cmdHub(p, f, log) {
240
- // The hosted explorer: every program on the cluster from one public host,
241
- // read-only by default (a public signer would be a drain). --keypair opts in.
242
- const cluster = f.cluster || process.env.OPENZOO_CLUSTER || 'mainnet';
243
- // A signer makes the demo real (visitors can POST). It is bounded: a per-IP
244
- // rate limit and a daily SOL budget (OPENZOO_HUB_WRITE_BUDGET_SOL), so a
245
- // public hub can sign without being drained. Keypair from --keypair or the
246
- // OPENZOO_HUB_KEYPAIR secret (JSON byte array).
247
- let keypair = null;
248
- if (typeof f.keypair === 'string') keypair = loadWallet({ keypair: f.keypair }).keypair;
249
- else if (process.env.OPENZOO_HUB_KEYPAIR) { const { Keypair } = await import('@solana/web3.js'); keypair = Keypair.fromSecretKey(Uint8Array.from(JSON.parse(process.env.OPENZOO_HUB_KEYPAIR))); }
250
- if (keypair) log(`hub signs writes with ${keypair.publicKey.toBase58()} (budget ${process.env.OPENZOO_HUB_WRITE_BUDGET_SOL || '0.05'} SOL/day, ${process.env.OPENZOO_HUB_WRITES_PER_MIN || '3'} writes/min/ip)`);
251
- const port = f.port != null ? Number(f.port) : Number(process.env.PORT || DEFAULT_HUB_PORT);
252
- const h = await startHub({ cluster, port, host: f.host || '0.0.0.0', keypair, log, quiet: !!f.quiet, publicUrl: f.publicUrl || process.env.OPENZOO_HUB_URL || null, maxSites: f.maxSites ? Number(f.maxSites) : undefined });
253
- log(`openzoo hub → ${h.url}/.hub (cluster ${cluster}; sites at ${h.url}/s/<programId>)`);
254
- const stop = () => h.close().then(() => process.exit(0));
255
- process.once('SIGINT', stop);
256
- process.once('SIGTERM', stop);
257
- return 0;
258
- }
259
-
260
- async function cmdRuntime(p, f, log) {
261
- const sub = p[0];
262
- if (sub === 'deploy') {
263
- const r = await deployRuntime({ cluster: f.cluster, keypair: f.keypair, yes: !!f.yes, programKeypair: f.programKeypair, so: f.so, headroom: f.headroom, log });
264
- if (f.json) log(JSON.stringify(r, null, 2));
265
- return 0;
266
- }
267
- if (sub === 'status') {
268
- if (!p[1]) throw new Error('usage: runtime status <zoo-vm id> [--cluster <c>]');
269
- return cmdStatus([p[1]], { ...f, runtime: undefined }, log);
270
- }
271
- throw new Error('usage: runtime deploy|status');
272
- }
273
-
274
- export async function run(argv = process.argv.slice(2), io = {}) {
275
- const log = io.log ?? console.log;
276
- const error = io.error ?? console.error;
277
- const { cmd, positionals, flags } = parseArgs(argv);
278
- if (flags.version) { log(JSON.parse(fs.readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version); return 0; }
279
- if (flags.help || cmd === 'help' || cmd === '--help') { log(USAGE); return 0; }
280
- const commands = { build: cmdBuild, deploy: cmdDeploy, serve: cmdServe, inspect: cmdInspect, status: cmdStatus, hub: cmdHub, runtime: cmdRuntime };
281
- const fn = commands[cmd];
282
- if (!fn) { error(`unknown command: ${cmd}\n`); error(USAGE); process.exitCode = 1; return 1; }
283
- try {
284
- const code = (await fn(positionals, flags, log)) || 0;
285
- if (code) process.exitCode = code;
286
- return code;
287
- } catch (e) {
288
- error(`error: ${e?.message || e}`);
289
- if (process.env.OPENZOO_DEBUG && e?.stack) error(e.stack);
290
- process.exitCode = 1;
291
- return 1;
292
- }
293
- }