@voltro/cli 0.40.0 → 0.41.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.
Files changed (100) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/dist/{apiBuild-C8xBEYbL.js → apiBuild-B_iH24qf.js} +2 -2
  3. package/dist/apiBuild-RM5W5YXk.js +2 -0
  4. package/dist/bin.js +1 -1
  5. package/dist/{build-CkhFGnKA.js → build-DUdi6F_Q.js} +150 -150
  6. package/dist/{checkCommand-QbHshOac.js → checkCommand-B2RWrpWi.js} +1 -1
  7. package/dist/{checkCommand-BcXJa2IS.js → checkCommand-DWL2_PPR.js} +2 -2
  8. package/dist/{codegenCommand-DF2OJh3O.js → codegenCommand-DkjoJ30Q.js} +2 -2
  9. package/dist/{codemodRunner-BcOvi4A2.js → codemodRunner-sFuWDETH.js} +520 -460
  10. package/dist/{commands-7Z7-HOE3.js → commands-D0VR1yBB.js} +22 -22
  11. package/dist/{dashboardCommand-CUycH6dR.js → dashboardCommand-Bro7Jwts.js} +5 -5
  12. package/dist/{dataCommand-By78lscK.js → dataCommand-OKC5FscP.js} +183 -172
  13. package/dist/{dbCommand-DSwGv9wS.js → dbCommand-BHRamDsy.js} +441 -414
  14. package/dist/dbCommand-C9iE1pd9.js +2 -0
  15. package/dist/{dev-Dh1NuYx1.js → dev-D4l_YOzI.js} +22 -22
  16. package/dist/{dev-D8JSKlBM.js → dev-DuqBJC7g.js} +1 -1
  17. package/dist/doctorCommand-Bw3V4L1j.js +2 -0
  18. package/dist/{doctorCommand-C-8-Z9D6.js → doctorCommand-TmZTAepc.js} +385 -279
  19. package/dist/{dormancyCommand-A79Odglm.js → dormancyCommand-CUKhRmGG.js} +1 -1
  20. package/dist/{embeddingsCommand-CoiyHfkY.js → embeddingsCommand-Db-iQM3l.js} +1 -1
  21. package/dist/{envCommand-B6d0s-jZ.js → envCommand-DQ_URZq9.js} +12 -12
  22. package/dist/{evolveCommand-BC5a9lxX.js → evolveCommand-CghRPrGO.js} +2 -2
  23. package/dist/index.js +1 -1
  24. package/dist/{infoCommand-ZqSVzJZ4.js → infoCommand-BCs_ZFnl.js} +1 -1
  25. package/dist/{migrate-BnPw2zC8.js → migrate-DLtPv2_D.js} +1 -1
  26. package/dist/{runtimeTrace-BslKJjDY.js → runtimeTrace-jFKvOPBz.js} +1 -1
  27. package/dist/{sdkgen-DQ8uEmmn.js → sdkgen-COQqHB9V.js} +1 -1
  28. package/dist/{serveCommand-Dqb9Ku1-.js → serveCommand-Cba_M2Su.js} +3 -3
  29. package/dist/serveCommand-DRbYK646.js +2 -0
  30. package/dist/serveEntry.js +1 -1
  31. package/dist/{start-dkNYKtgQ.js → start-BjcuFME_.js} +379 -343
  32. package/dist/{start-BA7txHhY.js → start-fifc0xpW.js} +1 -1
  33. package/dist/startEntry.js +1 -1
  34. package/dist/updateCommand-B2alql9k.js +2 -0
  35. package/dist/{updateCommand-eoGpZr3E.js → updateCommand-HZQVBU3T.js} +1 -1
  36. package/dist/webDev-D6QeXw3P.js +2 -0
  37. package/dist/{webDev-bybjZA0o.js → webDev-Dk8lFUzf.js} +642 -525
  38. package/dist/{webhooksCommand-DubZWNOx.js → webhooksCommand-D7ZpH7w0.js} +1 -1
  39. package/package.json +23 -17
  40. package/templates/AGENTS.md +1 -1
  41. package/templates/agent-docs/_index.md +1 -1
  42. package/templates/agent-docs/_manifest.json +1 -1
  43. package/templates/agent-docs/cli.md +6 -0
  44. package/templates/agent-docs/plugins/governance.md +8 -0
  45. package/templates/agent-docs/routing.md +141 -28
  46. package/templates/agent-docs/security.md +24 -0
  47. package/templates/agent-docs/whats-new.md +37 -121
  48. package/templates/apps/api-ai/package.json +7 -7
  49. package/templates/apps/api-auth/package.json +8 -8
  50. package/templates/apps/api-backend/package.json +7 -7
  51. package/templates/apps/api-backend-deactivation/package.json +7 -7
  52. package/templates/apps/api-backend-mail/package.json +8 -8
  53. package/templates/apps/api-backend-mariadb/package.json +9 -9
  54. package/templates/apps/api-backend-sqlite/package.json +8 -8
  55. package/templates/apps/api-backend-storage/package.json +8 -8
  56. package/templates/apps/api-cms/package.json +10 -10
  57. package/templates/apps/api-collab/package.json +8 -8
  58. package/templates/apps/api-data-advanced/package.json +8 -8
  59. package/templates/apps/api-durable/package.json +8 -8
  60. package/templates/apps/api-feature-flags/package.json +9 -9
  61. package/templates/apps/api-governance/package.json +8 -8
  62. package/templates/apps/api-kv/package.json +8 -8
  63. package/templates/apps/api-moderation/package.json +8 -8
  64. package/templates/apps/api-observability/package.json +8 -8
  65. package/templates/apps/api-ratelimit/package.json +8 -8
  66. package/templates/apps/api-rbac/package.json +8 -8
  67. package/templates/apps/api-rest/package.json +7 -7
  68. package/templates/apps/api-saas/package.json +11 -11
  69. package/templates/apps/api-saas-starter/package.json +10 -10
  70. package/templates/apps/api-search/package.json +8 -8
  71. package/templates/apps/api-status/package.json +8 -8
  72. package/templates/apps/api-versioning/package.json +8 -8
  73. package/templates/apps/api-webhooks/package.json +9 -9
  74. package/templates/apps/changelog/package.json +6 -6
  75. package/templates/apps/edge-functions/package.json +2 -2
  76. package/templates/apps/frontend-admin/package.json +8 -8
  77. package/templates/apps/frontend-app/package.json +9 -9
  78. package/templates/apps/frontend-auth/package.json +8 -8
  79. package/templates/apps/frontend-blank/package.json +7 -7
  80. package/templates/apps/frontend-cms/package.json +9 -9
  81. package/templates/apps/frontend-collab/package.json +10 -10
  82. package/templates/apps/frontend-contact/package.json +7 -7
  83. package/templates/apps/frontend-dashboard/package.json +7 -7
  84. package/templates/apps/frontend-docs/package.json +7 -7
  85. package/templates/apps/frontend-i18n/package.json +6 -6
  86. package/templates/apps/frontend-landing/package.json +7 -7
  87. package/templates/apps/frontend-portal/package.json +8 -8
  88. package/templates/apps/frontend-saas/package.json +8 -8
  89. package/templates/apps/frontend-spa/package.json +7 -7
  90. package/templates/apps/frontend-ssr/package.json +7 -7
  91. package/templates/apps/frontend-ssr-api/package.json +8 -8
  92. package/templates/apps/frontend-static-blog/package.json +6 -6
  93. package/templates/apps/frontend-status/package.json +8 -8
  94. package/templates/apps/mobile-app/package.json +4 -4
  95. package/dist/apiBuild-BIyGkym8.js +0 -2
  96. package/dist/dbCommand-DcqEyxju.js +0 -2
  97. package/dist/doctorCommand-FhQ7EVYL.js +0 -2
  98. package/dist/serveCommand-BmvEQCMS.js +0 -2
  99. package/dist/updateCommand-BauSVxPp.js +0 -2
  100. package/dist/webDev-CBbKs4dZ.js +0 -2
@@ -1,25 +1,25 @@
1
1
  import { t as e } from "./cliError-BmdYnghb.js";
2
- import { c as t, i as n, o as r } from "./dev-Dh1NuYx1.js";
2
+ import { c as t, i as n, o as r } from "./dev-D4l_YOzI.js";
3
3
  import { n as i, t as a } from "./cliArgs-D4p8n7EE.js";
4
4
  import { r as o } from "./dialectDriver-czCHYpeH.js";
5
5
  import { t as s } from "./dataProfile-dW-PsfLB.js";
6
6
  import { o as c, t as l } from "./inspectFetch-EMuhTG_9.js";
7
- import { r as u } from "./dbCommand-DSwGv9wS.js";
7
+ import { r as u } from "./dbCommand-BHRamDsy.js";
8
8
  import { createLogger as d } from "@voltro/logger";
9
9
  import { Effect as f, Stream as p } from "effect";
10
10
  import { SqlClient as m } from "@effect/sql";
11
11
  import { declaredSnapshot as h, fingerprintSchema as g, introspectSchema as _ } from "@voltro/database/sql";
12
12
  import { connectionIdentity as v, normaliseTarget as y, sameDatabase as b, streamTable as x } from "@voltro/database";
13
- import { STORAGE_REFS_TABLE as S, resolveStorageProvider as C } from "@voltro/plugin-storage";
14
- import { assessLiveImport as ee, backupArtifactName as w, backupCommand as te, classificationFromSnapshot as ne, decryptStream as T, encryptStream as re, packBundle as E, peekBundle as D, previewMasking as ie, restoreCommand as O, runExport as k, runImport as A, runNativeStep as j, storageAssetSink as M, storageAssetSource as ae, storageBlobSink as oe, storageBlobSource as se, unpackBundle as ce, unpackBundleToDir as N } from "@voltro/data-transfer";
13
+ import { STORAGE_REFS_TABLE as ee, resolveStorageProvider as S } from "@voltro/plugin-storage";
14
+ import { assessLiveImport as te, backupArtifactName as C, backupCommand as ne, classificationFromSnapshot as re, decryptStream as w, encryptStream as ie, packBundle as T, peekBundle as E, previewMasking as ae, restoreCommand as D, runExport as O, runImport as k, runNativeStep as A, storageAssetSink as j, storageAssetSource as oe, storageBlobSink as se, storageBlobSource as ce, unpackBundle as le, unpackBundleToDir as M } from "@voltro/data-transfer";
15
15
  //#region src/backupStamp.ts
16
- var P = "voltro-backup-stamp.json", le = (e) => ({
16
+ var N = "voltro-backup-stamp.json", ue = (e) => ({
17
17
  stampVersion: 1,
18
18
  dialect: e.dialect,
19
19
  schemaFingerprint: e.schemaFingerprint,
20
20
  voltroVersion: e.voltroVersion,
21
21
  createdAt: e.createdAt
22
- }), F = (e) => {
22
+ }), P = (e) => {
23
23
  let t;
24
24
  try {
25
25
  t = JSON.parse(e);
@@ -37,10 +37,10 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
37
37
  voltroVersion: n.voltroVersion,
38
38
  createdAt: n.createdAt
39
39
  };
40
- }, ue = (e) => {
40
+ }, de = (e) => {
41
41
  let { stamp: t, currentDialect: n, currentFingerprint: r } = e;
42
42
  if (t === null) return {
43
- warn: `no ${P} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
43
+ warn: `no ${N} beside the dump — an older/handmade backup. Cannot verify dialect or schema version; make sure this dump is a ${n} dump.`,
44
44
  info: []
45
45
  };
46
46
  let i = [`backup produced by @voltro/cli ${t.voltroVersion} at ${t.createdAt}`, `schema fingerprint: ${t.schemaFingerprint ?? "<none recorded>"}`];
@@ -51,20 +51,20 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
51
51
  refuse: `dialect mismatch — backup is a ${t.dialect} dump, but DB_DIALECT is ${n}. A cross-dialect restore is never valid.`,
52
52
  info: i
53
53
  };
54
- }, I = (e) => {
54
+ }, F = (e) => {
55
55
  try {
56
56
  let t = new URL(e), n = t.pathname.replace(/^\//, "");
57
57
  return `${t.hostname.toLowerCase()}:${t.port || "(default)"}/${n}`;
58
58
  } catch {
59
59
  return e.trim();
60
60
  }
61
- }, de = (e) => {
61
+ }, fe = (e) => {
62
62
  let t = e.flagUrl ?? e.envUrl;
63
63
  if (t === void 0 || t.trim() === "") return {
64
64
  ok: !1,
65
65
  error: "no drill target — pass `--drill-url <url>` or set `DRILL_DB_URL`. The drill restores into a THROWAWAY database (never the live one), so it needs its own connection."
66
66
  };
67
- let n = I(t);
67
+ let n = F(t);
68
68
  return e.liveKeys.some((e) => e === n) ? {
69
69
  ok: !1,
70
70
  error: `drill target (${n}) is the LIVE database — a restore drill must target a throwaway DB, never production. It would --clean and overwrite it.`
@@ -72,7 +72,7 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
72
72
  ok: !0,
73
73
  url: t
74
74
  };
75
- }, fe = (e) => {
75
+ }, pe = (e) => {
76
76
  let { stampFingerprint: t, restoredFingerprint: n, restoredTableCount: r } = e;
77
77
  return r === 0 ? {
78
78
  pass: !1,
@@ -87,24 +87,24 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
87
87
  pass: !0,
88
88
  lines: [`PASS — restored ${r} table(s); schema fingerprint matches the backup stamp (${n.slice(0, 12)}).`]
89
89
  };
90
- }, L = d({ scope: "voltro:data" }), pe = async () => {
90
+ }, I = d({ scope: "voltro:data" }), me = async () => {
91
91
  try {
92
92
  let { createRequire: e } = await import("node:module"), { join: t } = await import("node:path"), { readFileSync: n } = await import("node:fs"), r = e(t(process.cwd(), "package.json")).resolve("@voltro/cli/package.json");
93
93
  return JSON.parse(n(r, "utf8")).version ?? "unknown";
94
94
  } catch {
95
95
  return "unknown";
96
96
  }
97
- }, R = async (e) => {
97
+ }, L = async (e) => {
98
98
  try {
99
- return g(await K(e));
99
+ return g(await G(e));
100
100
  } catch {
101
101
  return null;
102
102
  }
103
- }, z = (e) => {
103
+ }, R = (e) => {
104
104
  if (e.event !== "done") return;
105
105
  let t = e.total === void 0 ? "" : ` / ${e.total}`;
106
- L.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
107
- }, B = async (e) => {
106
+ I.info(`${e.phase} [${e.index + 1}/${e.tableCount}] ${e.table}`, { rows: `${e.rowsDone}${t}` });
107
+ }, z = async (e) => {
108
108
  let t = (e) => e?.meta?.databaseId;
109
109
  if (e) {
110
110
  let n = await l({
@@ -124,26 +124,27 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
124
124
  };
125
125
  }
126
126
  return null;
127
- }, V = async (e) => {
128
- let t = e.includes("--allow-live"), n = t ? null : await B(H(e, "--api-url")), i = v({
129
- dialect: W(),
127
+ }, B = async (e) => {
128
+ let t = e.includes("--allow-live"), n = t ? null : await z(V(e, "--api-url")), i = v({
129
+ dialect: U(),
130
130
  ...r()
131
131
  }), a = y({
132
- dialect: W(),
132
+ dialect: U(),
133
133
  ...r()
134
- }), { refuse: o, message: s } = ee({
134
+ }), { refuse: o, message: s } = te({
135
135
  liveInstance: n?.label ?? null,
136
136
  allowLive: t,
137
137
  sameTarget: b(i, n?.databaseId),
138
138
  ...a === void 0 ? {} : { targetLabel: `${a.host}:${a.port}/${a.database}` }
139
139
  });
140
- return !o || (L.error(s ?? "refusing: live instance detected"), !1);
141
- }, H = i, me = [
140
+ return !o || (I.error(s ?? "refusing: live instance detected"), !1);
141
+ }, V = i, he = [
142
142
  "--api-url",
143
143
  "--bundle-key",
144
144
  "--compression",
145
145
  "--consistency",
146
146
  "--drill-url",
147
+ "--exclude",
147
148
  "--mode",
148
149
  "--on-conflict",
149
150
  "--passphrase",
@@ -152,56 +153,65 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
152
153
  "--target",
153
154
  "--tenant",
154
155
  "--token"
155
- ], U = (e) => a(e, me), W = () => {
156
+ ], H = (e) => a(e, he), U = () => {
156
157
  let t = (process.env.DB_DIALECT ?? "postgres").toLowerCase();
157
158
  if (t === "memory") throw new e("voltro data: requires a real dialect, not DB_DIALECT=memory.");
158
159
  return t;
159
- }, G = async (e, t) => {
160
+ }, W = async (e, t) => {
160
161
  let n = (await o(e)).makeSqlLayer(t);
161
162
  return f.runPromise(m.SqlClient.pipe(f.flatMap(_), f.provide(n)));
162
- }, K = (e) => G(e, r()), he = () => {
163
+ }, G = (e) => W(e, r()), ge = () => {
163
164
  let e = r(), t = [];
164
- return e.url && t.push(I(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
165
- }, q = async () => {
165
+ return e.url && t.push(F(e.url)), (e.host || e.database) && t.push(`${(e.host ?? "localhost").toLowerCase()}:${e.port ?? "(default)"}/${e.database ?? ""}`), t;
166
+ }, K = async () => {
166
167
  let r = process.cwd(), i = await t(r);
167
168
  if (!i) throw new e("voltro data: no app.config.ts found in the current directory.");
168
- let a = await n(i, void 0), o = W();
169
+ let a = await n(i, void 0), o = U();
169
170
  return {
170
171
  store: a,
171
- snapshot: await K(o),
172
+ snapshot: await G(o),
172
173
  dialect: o
173
174
  };
174
- }, J = (e) => x(e, {
175
- table: S,
175
+ }, q = (e) => x(e, {
176
+ table: ee,
176
177
  chunkSize: 500
177
178
  }).pipe(p.map((e) => ({
178
179
  key: String(e.key),
179
180
  contentType: String(e.contentType ?? "application/octet-stream"),
180
181
  size: Number(e.size ?? 0)
181
- }))), Y = (e) => !!e && e.endsWith(".vbundle"), X = (e) => H(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, ge = (e) => e.includes("--encrypt") || H(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, _e = async (e, t) => {
182
+ }))), J = (e) => !!e && e.endsWith(".vbundle"), Y = (e) => V(e, "--passphrase") ?? process.env.VOLTRO_BUNDLE_KEY, _e = (e) => e.includes("--encrypt") || V(e, "--passphrase") !== void 0 || process.env.VOLTRO_BUNDLE_KEY !== void 0, ve = async (e, t) => {
182
183
  let { createWriteStream: n } = await import("node:fs"), { pipeline: r } = await import("node:stream/promises"), { Readable: i } = await import("node:stream");
183
184
  await r(i.from(e), n(t));
184
- }, Z = (e) => ({ async *[Symbol.asyncIterator]() {
185
+ }, X = (e) => ({ async *[Symbol.asyncIterator]() {
185
186
  let { createReadStream: t } = await import("node:fs");
186
187
  for await (let n of t(e)) yield n instanceof Uint8Array ? n : new Uint8Array(n);
187
- } }), ve = (e) => {
188
- let t = H(e, "--tenant");
189
- if (t) return {
188
+ } }), Z = (e) => (e ?? "").split(",").map((e) => e.trim()).filter(Boolean), ye = (t, n) => {
189
+ let r = V(t, "--tenant"), i = V(t, "--tables"), a = V(t, "--exclude");
190
+ if (a !== void 0) {
191
+ if (i !== void 0) throw new e("voltro data export: --exclude and --tables are two ways to say the same thing; use one.");
192
+ if (r !== void 0) throw new e("voltro data export: --exclude does not apply to --tenant, whose table set is derived from the tenant closure.");
193
+ let t = Z(a), o = new Set(n), s = t.filter((e) => !o.has(e));
194
+ if (s.length > 0) throw new e(`voltro data export: --exclude names ${s.length} table(s) that do not exist: ${s.join(", ")}. An exclusion that excludes nothing would leave the run looking like it worked.`);
195
+ let c = new Set(t);
196
+ return {
197
+ kind: "tables",
198
+ tables: n.filter((e) => !c.has(e))
199
+ };
200
+ }
201
+ return r ? {
190
202
  kind: "tenant",
191
- tenantId: t
192
- };
193
- let n = H(e, "--tables");
194
- return n ? {
203
+ tenantId: r
204
+ } : i ? {
195
205
  kind: "tables",
196
- tables: n.split(",").map((e) => e.trim()).filter(Boolean)
206
+ tables: Z(i)
197
207
  } : { kind: "all" };
198
- }, ye = async () => {
208
+ }, be = async () => {
199
209
  let e = await u(process.cwd());
200
- return ne(h(e));
201
- }, be = "voltro/tenant", xe = async () => {
202
- let e = (await u(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === be)).map((e) => e.tableName);
210
+ return re(h(e));
211
+ }, xe = "voltro/tenant", Se = async () => {
212
+ let e = (await u(process.cwd())).filter((e) => (e.appliedMixins ?? []).some((e) => e.id === xe)).map((e) => e.tableName);
203
213
  return e.length > 0 ? e : void 0;
204
- }, Q = (e) => {
214
+ }, Ce = (e) => {
205
215
  for (let t of e.tables) if (t.samples.length !== 0) {
206
216
  console.log(`\n ${t.table}`);
207
217
  for (let e of t.samples) console.log(` ${e.column} [${e.action}] ${JSON.stringify(e.before)} → ${JSON.stringify(e.after)}`);
@@ -214,20 +224,21 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
214
224
  console.log("\n ✗ unclassified (would BLOCK a real export — add .sensitive()/.safe() or a policy override):");
215
225
  for (let t of e.unclassified) console.log(` ${t}`);
216
226
  } else console.log("\n ✓ every exported column is classified — safe to run.");
217
- }, Se = async (e) => {
218
- let t = H(e, "--target") === "api", n = H(e, "--bundle-key"), r = U(e);
219
- if (!r && !(t && n)) return L.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--profile <name>] [--tenant <id>] [--tables a,b] [--bundle-key <storage-key>] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot] [--dry-run]"), 1;
227
+ }, we = async (e) => {
228
+ let t = V(e, "--target") === "api", n = V(e, "--bundle-key"), r = H(e);
229
+ if (!r && !(t && n)) return I.error("usage: voltro data export <outDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--profile <name>] [--tenant <id>] [--tables a,b] [--exclude a,b] [--bundle-key <storage-key>] [--assets] [--compression zstd|gzip|none] [--consistency live|snapshot] [--dry-run]"), 1;
220
230
  if (t) {
221
- let t = H(e, "--api-url");
222
- if (!t) return L.error("--target api requires --api-url <url> (the running instance)"), 1;
223
- let i = H(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
224
- if (!i) return L.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
225
- let a = H(e, "--tables"), o = {
226
- ...H(e, "--profile") ? { profile: H(e, "--profile") } : {},
227
- ...H(e, "--tenant") ? { tenant: H(e, "--tenant") } : {},
231
+ let t = V(e, "--api-url");
232
+ if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
233
+ let i = V(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
234
+ if (!i) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
235
+ if (V(e, "--exclude") !== void 0) return I.error("--exclude is a direct-target flag: it expands against the live table list, which --target api does not expose. Use --tables with the explicit set."), 1;
236
+ let a = V(e, "--tables"), o = {
237
+ ...V(e, "--profile") ? { profile: V(e, "--profile") } : {},
238
+ ...V(e, "--tenant") ? { tenant: V(e, "--tenant") } : {},
228
239
  ...a ? { tables: a.split(",").map((e) => e.trim()).filter(Boolean) } : {},
229
- ...H(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
230
- ...H(e, "--compression") ? { compression: H(e, "--compression") } : {},
240
+ ...V(e, "--consistency") === "snapshot" ? { consistency: "snapshot" } : {},
241
+ ...V(e, "--compression") ? { compression: V(e, "--compression") } : {},
231
242
  ...e.includes("--assets") ? { assets: !0 } : {},
232
243
  ...n ? { bundleKey: n } : {}
233
244
  }, s = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/export`, {
@@ -238,26 +249,26 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
238
249
  },
239
250
  body: JSON.stringify(o)
240
251
  });
241
- if (!s.ok) return L.error(`api export failed: HTTP ${s.status} — ${await s.text()}`), 1;
242
- if (n) return L.info("api export complete (pushed to storage)", {
252
+ if (!s.ok) return I.error(`api export failed: HTTP ${s.status} — ${await s.text()}`), 1;
253
+ if (n) return I.info("api export complete (pushed to storage)", {
243
254
  via: t,
244
255
  ...await s.json()
245
256
  }), 0;
246
257
  let { resolve: c } = await import("node:path"), l = new Uint8Array(await s.arrayBuffer());
247
- return await N((async function* () {
258
+ return await M((async function* () {
248
259
  yield l;
249
- })(), c(process.cwd(), r)), L.info("api export complete (downloaded from the running instance)", {
260
+ })(), c(process.cwd(), r)), I.info("api export complete (downloaded from the running instance)", {
250
261
  outDir: r,
251
262
  tables: s.headers.get("x-export-tables") ?? void 0,
252
263
  rows: s.headers.get("x-export-rows") ?? void 0,
253
264
  masked: s.headers.get("x-export-masked") ?? void 0
254
265
  }), 0;
255
266
  }
256
- if (!r) return L.error("a <outDir> is required for a direct export"), 1;
257
- let i = H(e, "--profile"), a = i ? await s(i) : {}, { store: o, snapshot: c, dialect: l } = await q(), u = e.includes("--assets") || a.assets === !0, d = u ? C({}) : void 0, p = H(e, "--compression") ?? a.compression, m = H(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", h = a.masking, g = a.subset, _ = a.scope ?? ve(e), v = h ? await ye() : void 0, y = _.kind === "tenant" ? await xe() : void 0, b = y ? { tenantTables: y } : {};
267
+ if (!r) return I.error("a <outDir> is required for a direct export"), 1;
268
+ let i = V(e, "--profile"), a = i ? await s(i) : {}, { store: o, snapshot: c, dialect: l } = await K(), u = e.includes("--assets") || a.assets === !0, d = u ? S({}) : void 0, p = V(e, "--compression") ?? a.compression, m = V(e, "--consistency") === "snapshot" ? "snapshot" : a.consistency ?? "live", h = a.masking, g = a.subset, _ = a.scope ?? ye(e, c.tables.map((e) => e.name)), v = h ? await be() : void 0, y = _.kind === "tenant" ? await Se() : void 0, b = y ? { tenantTables: y } : {};
258
269
  if (e.includes("--dry-run")) {
259
- if (!h) return L.error("--dry-run previews masking, but the profile sets no masking policy"), 1;
260
- let e = await f.runPromise(ie({
270
+ if (!h) return I.error("--dry-run previews masking, but the profile sets no masking policy"), 1;
271
+ let e = await f.runPromise(ae({
261
272
  store: o,
262
273
  snapshot: c,
263
274
  masking: h,
@@ -267,12 +278,12 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
267
278
  ...b
268
279
  }
269
280
  }));
270
- return Q(e), +(e.unclassified.length > 0);
281
+ return Ce(e), +(e.unclassified.length > 0);
271
282
  }
272
- if (Y(r)) {
283
+ if (J(r)) {
273
284
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: i, join: a } = await import("node:path"), s = await n.mkdtemp(a(t.tmpdir(), "voltro-export-"));
274
285
  try {
275
- let t = await f.runPromise(k({
286
+ let t = await f.runPromise(O({
276
287
  store: o,
277
288
  snapshot: c,
278
289
  dialect: l,
@@ -285,17 +296,17 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
285
296
  ...p ? { compression: p } : {},
286
297
  ...h ? { masking: h } : {},
287
298
  ...v ? { classification: v } : {},
288
- onProgress: z
289
- })), n = E({
299
+ onProgress: R
300
+ })), n = T({
290
301
  dir: s,
291
- ...d ? { blobs: se(d, () => J(o)) } : {}
292
- }), a = ge(e);
302
+ ...d ? { blobs: ce(d, () => q(o)) } : {}
303
+ }), a = _e(e);
293
304
  if (a) {
294
- let t = X(e);
295
- if (!t) return L.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
296
- n = re(n, t);
305
+ let t = Y(e);
306
+ if (!t) return I.error("--encrypt requires --passphrase <p> or VOLTRO_BUNDLE_KEY (a dedicated key, NOT the transfer secret)"), 1;
307
+ n = ie(n, t);
297
308
  }
298
- return await _e(n, i(process.cwd(), r)), L.info("export complete (single file)", {
309
+ return await ve(n, i(process.cwd(), r)), I.info("export complete (single file)", {
299
310
  file: r,
300
311
  encrypted: a,
301
312
  assets: u,
@@ -309,7 +320,7 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
309
320
  });
310
321
  }
311
322
  }
312
- let x = await f.runPromise(k({
323
+ let x = await f.runPromise(O({
313
324
  store: o,
314
325
  snapshot: c,
315
326
  dialect: l,
@@ -322,10 +333,10 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
322
333
  ...p ? { compression: p } : {},
323
334
  ...h ? { masking: h } : {},
324
335
  ...v ? { classification: v } : {},
325
- ...d ? { assets: ae(d, () => J(o)) } : {},
326
- onProgress: z
336
+ ...d ? { assets: oe(d, () => q(o)) } : {},
337
+ onProgress: R
327
338
  }));
328
- return L.info("export complete", {
339
+ return I.info("export complete", {
329
340
  outDir: r,
330
341
  tables: x.tables.length,
331
342
  rows: x.tables.reduce((e, t) => e + t.rowCount, 0),
@@ -333,15 +344,15 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
333
344
  compression: x.compression,
334
345
  ...x.masking ? { maskedColumns: x.masking.transformed.length } : {}
335
346
  }), 0;
336
- }, Ce = async (e) => {
337
- let t = H(e, "--target") === "api", n = H(e, "--bundle-key"), i = U(e);
338
- if (!i && !(t && n)) return L.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--bundle-key <storage-key>] [--mode upsert|append|replace] [--on-conflict skip|fail] [--atomic] [--assets] [--no-verify] [--force] [--allow-live] (--force: import despite schema drift AND cross-dialect warnings)"), 1;
339
- let a = H(e, "--mode") ?? "upsert", o = H(e, "--on-conflict") ?? "skip";
347
+ }, Q = async (e) => {
348
+ let t = V(e, "--target") === "api", n = V(e, "--bundle-key"), i = H(e);
349
+ if (!i && !(t && n)) return I.error("usage: voltro data import <bundleDir> [--target direct|api] [--api-url <url>] [--token <secret>] [--bundle-key <storage-key>] [--mode upsert|append|replace] [--on-conflict skip|fail] [--atomic] [--assets] [--no-verify] [--force] [--allow-live] (--force: import despite schema drift AND cross-dialect warnings)"), 1;
350
+ let a = V(e, "--mode") ?? "upsert", o = V(e, "--on-conflict") ?? "skip";
340
351
  if (t) {
341
- let t = H(e, "--api-url");
342
- if (!t) return L.error("--target api requires --api-url <url> (the running instance)"), 1;
343
- let r = H(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
344
- if (!r) return L.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
352
+ let t = V(e, "--api-url");
353
+ if (!t) return I.error("--target api requires --api-url <url> (the running instance)"), 1;
354
+ let r = V(e, "--token") ?? process.env.VOLTRO_DATA_TRANSFER_SECRET;
355
+ if (!r) return I.error("--target api requires --token <secret> (or VOLTRO_DATA_TRANSFER_SECRET) matching the instance secret"), 1;
345
356
  let s = {
346
357
  authorization: `Bearer ${r}`,
347
358
  "x-import-mode": a,
@@ -350,16 +361,16 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
350
361
  ...e.includes("--force") ? { "x-import-force": "1" } : {}
351
362
  }, { resolve: c } = await import("node:path"), l;
352
363
  if (n) s["content-type"] = "application/json", l = JSON.stringify({ bundleKey: n });
353
- else if (Y(i)) {
354
- let t = Z(c(process.cwd(), i)), n = X(e);
355
- n && (t = T(t, n));
364
+ else if (J(i)) {
365
+ let t = X(c(process.cwd(), i)), n = Y(e);
366
+ n && (t = w(t, n));
356
367
  let r = [];
357
368
  for await (let e of t) r.push(Buffer.from(e));
358
369
  s["content-type"] = "application/octet-stream", l = Buffer.concat(r);
359
370
  } else {
360
- await (await import("node:fs/promises")).access(c(process.cwd(), i, "assets", "index.ndjson")).then(() => !0, () => !1) && L.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API.");
371
+ await (await import("node:fs/promises")).access(c(process.cwd(), i, "assets", "index.ndjson")).then(() => !0, () => !1) && I.warn("this directory bundle has assets; --target api uploads DATA ONLY. Pack a single-file `.vbundle` (voltro data export <name>.vbundle --assets) to transfer assets over the API.");
361
372
  let e = [];
362
- for await (let t of E({ dir: c(process.cwd(), i) })) e.push(Buffer.from(t));
373
+ for await (let t of T({ dir: c(process.cwd(), i) })) e.push(Buffer.from(t));
363
374
  s["content-type"] = "application/octet-stream", l = Buffer.concat(e);
364
375
  }
365
376
  let u = await fetch(`${t.replace(/\/+$/, "")}/_voltro/admin/import`, {
@@ -367,39 +378,39 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
367
378
  body: l,
368
379
  headers: s
369
380
  });
370
- return u.ok ? (L.info("api import complete (imported by the running instance)", {
381
+ return u.ok ? (I.info("api import complete (imported by the running instance)", {
371
382
  via: t,
372
383
  ...await u.json()
373
- }), 0) : (L.error(`api import failed: HTTP ${u.status} — ${await u.text()}`), 1);
384
+ }), 0) : (I.error(`api import failed: HTTP ${u.status} — ${await u.text()}`), 1);
374
385
  }
375
- if (!i) return L.error("a <bundleDir> is required for a direct import"), 1;
376
- if (!await V(e)) return 1;
377
- let { store: s, snapshot: c } = await q(), l = e.includes("--force"), u = (e) => L.warn(e), d = e.includes("--assets") ? C({}) : void 0, p = W() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
378
- if (Y(i)) {
386
+ if (!i) return I.error("a <bundleDir> is required for a direct import"), 1;
387
+ if (!await B(e)) return 1;
388
+ let { store: s, snapshot: c } = await K(), l = e.includes("--force"), u = (e) => I.warn(e), d = e.includes("--assets") ? S({}) : void 0, p = U() === "postgres" ? (await import("@voltro/sql-postgres")).makePgCopySession(r()) : void 0;
389
+ if (J(i)) {
379
390
  let t = await import("node:os"), n = await import("node:fs/promises"), { resolve: r, join: m } = await import("node:path"), h = await n.mkdtemp(m(t.tmpdir(), "voltro-import-"));
380
391
  try {
381
- let t = Z(r(process.cwd(), i)), n = X(e);
382
- n && (t = T(t, n)), await ce(t, {
392
+ let t = X(r(process.cwd(), i)), n = Y(e);
393
+ n && (t = w(t, n)), await le(t, {
383
394
  dir: h,
384
- blobs: oe(d ?? C({}))
395
+ blobs: se(d ?? S({}))
385
396
  });
386
- let m = await f.runPromise(A({
397
+ let m = await f.runPromise(k({
387
398
  store: s,
388
399
  bundleDir: h,
389
400
  mode: a,
390
401
  onConflict: o,
391
402
  atomic: e.includes("--atomic"),
392
403
  verify: !e.includes("--no-verify"),
393
- targetDialect: W(),
404
+ targetDialect: U(),
394
405
  allowIncompatible: l,
395
406
  targetSnapshot: c,
396
407
  force: l,
397
408
  onWarn: u,
398
- onProgress: z,
409
+ onProgress: R,
399
410
  assetsAlreadyRestored: !0,
400
411
  ...p ? { copyLoader: p } : {}
401
412
  }));
402
- return L.info("import complete (single file)", {
413
+ return I.info("import complete (single file)", {
403
414
  file: i,
404
415
  tables: m.tables.length,
405
416
  rows: m.tables.reduce((e, t) => e + t.rowCount, 0)
@@ -411,23 +422,23 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
411
422
  });
412
423
  }
413
424
  }
414
- let m = await f.runPromise(A({
425
+ let m = await f.runPromise(k({
415
426
  store: s,
416
427
  bundleDir: i,
417
428
  mode: a,
418
429
  onConflict: o,
419
430
  atomic: e.includes("--atomic"),
420
431
  verify: !e.includes("--no-verify"),
421
- targetDialect: W(),
432
+ targetDialect: U(),
422
433
  allowIncompatible: l,
423
434
  targetSnapshot: c,
424
435
  force: l,
425
436
  onWarn: u,
426
- onProgress: z,
427
- ...d ? { assets: M(d) } : {},
437
+ onProgress: R,
438
+ ...d ? { assets: j(d) } : {},
428
439
  ...p ? { copyLoader: p } : {}
429
440
  })).finally(() => p?.close());
430
- return L.info("import complete", {
441
+ return I.info("import complete", {
431
442
  bundleDir: i,
432
443
  tables: m.tables.length,
433
444
  rows: m.tables.reduce((e, t) => e + t.rowCount, 0),
@@ -443,98 +454,98 @@ var P = "voltro-backup-stamp.json", le = (e) => ({
443
454
  ...e.password ? { password: e.password } : {},
444
455
  ...e.database ? { database: e.database } : {}
445
456
  };
446
- }, we = async (e) => {
447
- let t = U(e);
448
- if (!t) return L.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
449
- let n = W(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
457
+ }, Te = async (e) => {
458
+ let t = H(e);
459
+ if (!t) return I.error("usage: voltro data backup <outDir> (native pg_dump/mysqldump/… + consistent artifact)"), 1;
460
+ let n = U(), { mkdir: r, writeFile: i } = await import("node:fs/promises"), { join: a } = await import("node:path");
450
461
  await r(t, { recursive: !0 });
451
- let o = a(t, w(n));
452
- await f.runPromise(j(te(n, $(), o)));
453
- let s = le({
462
+ let o = a(t, C(n));
463
+ await f.runPromise(A(ne(n, $(), o)));
464
+ let s = ue({
454
465
  dialect: n,
455
- schemaFingerprint: await R(n),
456
- voltroVersion: await pe(),
466
+ schemaFingerprint: await L(n),
467
+ voltroVersion: await me(),
457
468
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
458
469
  });
459
- return await i(a(t, P), `${JSON.stringify(s, null, 2)}\n`, "utf8"), L.info("native backup complete", {
470
+ return await i(a(t, N), `${JSON.stringify(s, null, 2)}\n`, "utf8"), I.info("native backup complete", {
460
471
  dialect: n,
461
472
  artifact: o,
462
- stamp: P,
473
+ stamp: N,
463
474
  schemaFingerprint: s.schemaFingerprint ?? "<none>",
464
475
  assets: "NOT included — use `voltro data export --assets` for rows + blobs"
465
476
  }), 0;
466
- }, Te = async (e, t) => {
467
- let n = W(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, w(n)), o = de({
468
- flagUrl: H(t, "--drill-url"),
477
+ }, Ee = async (e, t) => {
478
+ let n = U(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(e, C(n)), o = fe({
479
+ flagUrl: V(t, "--drill-url"),
469
480
  envUrl: process.env.DRILL_DB_URL,
470
- liveKeys: he()
481
+ liveKeys: ge()
471
482
  });
472
- if (!o.ok) return L.error(`restore --drill: ${o.error}`), 1;
473
- let s = await i(r(e, P), "utf8").then(F, () => null);
474
- if (s && s.dialect !== n) return L.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
475
- L.info("restore drill: restoring into throwaway DB", {
483
+ if (!o.ok) return I.error(`restore --drill: ${o.error}`), 1;
484
+ let s = await i(r(e, N), "utf8").then(P, () => null);
485
+ if (s && s.dialect !== n) return I.error(`restore --drill: backup is a ${s.dialect} dump but DB_DIALECT is ${n} — cross-dialect restore is never valid.`), 1;
486
+ I.info("restore drill: restoring into throwaway DB", {
476
487
  dialect: n,
477
- target: I(o.url)
478
- }), await f.runPromise(j(O(n, { url: o.url }, a)));
488
+ target: F(o.url)
489
+ }), await f.runPromise(A(D(n, { url: o.url }, a)));
479
490
  let c = null, l = 0;
480
491
  try {
481
- let e = await G(n, { url: o.url });
492
+ let e = await W(n, { url: o.url });
482
493
  c = g(e), l = e.tables.length;
483
494
  } catch (e) {
484
- return L.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
495
+ return I.error(`restore --drill: could not introspect the restored DB — ${String(e)}`), 1;
485
496
  }
486
- let u = fe({
497
+ let u = pe({
487
498
  stampFingerprint: s?.schemaFingerprint ?? null,
488
499
  restoredFingerprint: c,
489
500
  restoredTableCount: l
490
501
  });
491
- for (let e of u.lines) u.pass ? L.info(`restore drill: ${e}`) : L.error(`restore drill: ${e}`);
502
+ for (let e of u.lines) u.pass ? I.info(`restore drill: ${e}`) : I.error(`restore drill: ${e}`);
492
503
  return +!u.pass;
493
- }, Ee = async (e) => {
494
- let t = U(e);
495
- if (!t) return L.error("usage: voltro data restore <backupDir> [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mysql/…)"), 1;
496
- if (e.includes("--drill")) return Te(t, e);
497
- if (!await V(e)) return 1;
498
- let n = W(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, w(n)), o = ue({
499
- stamp: await i(r(t, P), "utf8").then(F, () => null),
504
+ }, De = async (e) => {
505
+ let t = H(e);
506
+ if (!t) return I.error("usage: voltro data restore <backupDir> [--allow-live] [--api-url <url>] [--force] [--drill [--drill-url <url>]] (native pg_restore/mysql/…)"), 1;
507
+ if (e.includes("--drill")) return Ee(t, e);
508
+ if (!await B(e)) return 1;
509
+ let n = U(), { join: r } = await import("node:path"), { readFile: i } = await import("node:fs/promises"), a = r(t, C(n)), o = de({
510
+ stamp: await i(r(t, N), "utf8").then(P, () => null),
500
511
  currentDialect: n,
501
- currentFingerprint: await R(n)
512
+ currentFingerprint: await L(n)
502
513
  });
503
- for (let e of o.info) L.info(`backup stamp: ${e}`);
504
- if (o.warn && L.warn(o.warn), o.refuse) {
505
- if (!e.includes("--force")) return L.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
506
- L.warn(`restore proceeding despite: ${o.refuse} (--force)`);
514
+ for (let e of o.info) I.info(`backup stamp: ${e}`);
515
+ if (o.warn && I.warn(o.warn), o.refuse) {
516
+ if (!e.includes("--force")) return I.error(`restore refused: ${o.refuse} (pass --force to override)`), 1;
517
+ I.warn(`restore proceeding despite: ${o.refuse} (--force)`);
507
518
  }
508
- return await f.runPromise(j(O(n, $(), a))), L.info("native restore complete", {
519
+ return await f.runPromise(A(D(n, $(), a))), I.info("native restore complete", {
509
520
  dialect: n,
510
521
  artifact: a
511
522
  }), 0;
512
- }, De = async (e) => {
513
- let t = U(e);
514
- if (!t) return L.error("usage: voltro data inspect <file.vbundle> [--json] [--passphrase <p>]"), 1;
515
- let { resolve: n } = await import("node:path"), r = n(process.cwd(), t), i = X(e), a = () => {
516
- let e = Z(r);
517
- return i ? T(e, i) : e;
523
+ }, Oe = async (e) => {
524
+ let t = H(e);
525
+ if (!t) return I.error("usage: voltro data inspect <file.vbundle> [--json] [--passphrase <p>]"), 1;
526
+ let { resolve: n } = await import("node:path"), r = n(process.cwd(), t), i = Y(e), a = () => {
527
+ let e = X(r);
528
+ return i ? w(e, i) : e;
518
529
  };
519
530
  if (e.includes("--json")) {
520
- let e = (await D(a(), ["manifest.json"])).get("manifest.json");
521
- return e ? (console.log(e.toString("utf8")), 0) : (L.error("no manifest.json found in the bundle"), 1);
531
+ let e = (await E(a(), ["manifest.json"])).get("manifest.json");
532
+ return e ? (console.log(e.toString("utf8")), 0) : (I.error("no manifest.json found in the bundle"), 1);
522
533
  }
523
- let o = (await D(a(), ["README.md"])).get("README.md");
534
+ let o = (await E(a(), ["README.md"])).get("README.md");
524
535
  if (o) return console.log(o.toString("utf8")), 0;
525
- let s = (await D(a(), ["manifest.json"])).get("manifest.json");
526
- return s ? (console.log(s.toString("utf8")), 0) : (L.error("bundle has no README.md or manifest.json"), 1);
527
- }, Oe = async (e) => {
528
- let t = U(e), n = U(e.filter((e) => e !== t));
529
- if (!t || !n) return L.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
530
- let { resolve: r } = await import("node:path"), i = Z(r(process.cwd(), t)), a = X(e);
531
- return a && (i = T(i, a)), await N(i, r(process.cwd(), n)), L.info("unpack complete", {
536
+ let s = (await E(a(), ["manifest.json"])).get("manifest.json");
537
+ return s ? (console.log(s.toString("utf8")), 0) : (I.error("bundle has no README.md or manifest.json"), 1);
538
+ }, ke = async (e) => {
539
+ let t = H(e), n = H(e.filter((e) => e !== t));
540
+ if (!t || !n) return I.error("usage: voltro data unpack <file.vbundle> <dir> [--passphrase <p>]"), 1;
541
+ let { resolve: r } = await import("node:path"), i = X(r(process.cwd(), t)), a = Y(e);
542
+ return a && (i = w(i, a)), await M(i, r(process.cwd(), n)), I.info("unpack complete", {
532
543
  file: t,
533
544
  dir: n
534
545
  }), 0;
535
- }, ke = async (e) => {
546
+ }, Ae = async (e) => {
536
547
  let [t, ...n] = e;
537
- return t === "export" ? Se(n) : t === "import" ? Ce(n) : t === "unpack" ? Oe(n) : t === "inspect" ? De(n) : t === "backup" ? we(n) : t === "restore" ? Ee(n) : (L.error("usage: voltro data <export|import|unpack|inspect|backup|restore> … (logical: export/import; native: backup/restore)"), t ? 2 : 1);
548
+ return t === "export" ? we(n) : t === "import" ? Q(n) : t === "unpack" ? ke(n) : t === "inspect" ? Oe(n) : t === "backup" ? Te(n) : t === "restore" ? De(n) : (I.error("usage: voltro data <export|import|unpack|inspect|backup|restore> … (logical: export/import; native: backup/restore)"), t ? 2 : 1);
538
549
  };
539
550
  //#endregion
540
- export { ke as runDataCommand };
551
+ export { Ae as runDataCommand };