@x12i/catalox 3.0.0 → 3.2.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 (141) hide show
  1. package/README.md +43 -6
  2. package/dist/src/catalox/authorization.js +1 -1
  3. package/dist/src/catalox/authorization.js.map +1 -1
  4. package/dist/src/catalox/backup-data.d.ts +0 -6
  5. package/dist/src/catalox/backup-data.d.ts.map +1 -1
  6. package/dist/src/catalox/backup-data.js +2 -413
  7. package/dist/src/catalox/backup-data.js.map +1 -1
  8. package/dist/src/catalox/catalog-lifecycle.d.ts +29 -0
  9. package/dist/src/catalox/catalog-lifecycle.d.ts.map +1 -0
  10. package/dist/src/catalox/catalog-lifecycle.js +480 -0
  11. package/dist/src/catalox/catalog-lifecycle.js.map +1 -0
  12. package/dist/src/catalox/catalox-bound.d.ts +21 -6
  13. package/dist/src/catalox/catalox-bound.d.ts.map +1 -1
  14. package/dist/src/catalox/catalox-bound.js +30 -9
  15. package/dist/src/catalox/catalox-bound.js.map +1 -1
  16. package/dist/src/catalox/catalox.d.ts +31 -11
  17. package/dist/src/catalox/catalox.d.ts.map +1 -1
  18. package/dist/src/catalox/catalox.js +485 -82
  19. package/dist/src/catalox/catalox.js.map +1 -1
  20. package/dist/src/catalox/context.js +2 -2
  21. package/dist/src/catalox/context.js.map +1 -1
  22. package/dist/src/catalox/create-catalox.d.ts +6 -0
  23. package/dist/src/catalox/create-catalox.d.ts.map +1 -1
  24. package/dist/src/catalox/create-catalox.js +25 -0
  25. package/dist/src/catalox/create-catalox.js.map +1 -1
  26. package/dist/src/catalox/index.d.ts +4 -2
  27. package/dist/src/catalox/index.d.ts.map +1 -1
  28. package/dist/src/catalox/index.js +4 -2
  29. package/dist/src/catalox/index.js.map +1 -1
  30. package/dist/src/catalox/native-catalog-merge.d.ts +12 -0
  31. package/dist/src/catalox/native-catalog-merge.d.ts.map +1 -0
  32. package/dist/src/catalox/native-catalog-merge.js +102 -0
  33. package/dist/src/catalox/native-catalog-merge.js.map +1 -0
  34. package/dist/src/catalox/native-scope.d.ts +28 -0
  35. package/dist/src/catalox/native-scope.d.ts.map +1 -0
  36. package/dist/src/catalox/native-scope.js +184 -0
  37. package/dist/src/catalox/native-scope.js.map +1 -0
  38. package/dist/src/catalox/record-history.d.ts +53 -0
  39. package/dist/src/catalox/record-history.d.ts.map +1 -0
  40. package/dist/src/catalox/record-history.js +158 -0
  41. package/dist/src/catalox/record-history.js.map +1 -0
  42. package/dist/src/catalox/restore-firestore-backup.d.ts +6 -3
  43. package/dist/src/catalox/restore-firestore-backup.d.ts.map +1 -1
  44. package/dist/src/catalox/restore-firestore-backup.js +3 -224
  45. package/dist/src/catalox/restore-firestore-backup.js.map +1 -1
  46. package/dist/src/cli/index.js +159 -55
  47. package/dist/src/cli/index.js.map +1 -1
  48. package/dist/src/contracts/apps.d.ts +2 -0
  49. package/dist/src/contracts/apps.d.ts.map +1 -1
  50. package/dist/src/contracts/backup.d.ts +2 -2
  51. package/dist/src/contracts/backup.d.ts.map +1 -1
  52. package/dist/src/contracts/catalog-lifecycle.d.ts +70 -0
  53. package/dist/src/contracts/catalog-lifecycle.d.ts.map +1 -0
  54. package/dist/src/contracts/catalog-lifecycle.js +2 -0
  55. package/dist/src/contracts/catalog-lifecycle.js.map +1 -0
  56. package/dist/src/contracts/catalogs.d.ts +37 -0
  57. package/dist/src/contracts/catalogs.d.ts.map +1 -1
  58. package/dist/src/contracts/catalogs.js.map +1 -1
  59. package/dist/src/contracts/context.d.ts +5 -1
  60. package/dist/src/contracts/context.d.ts.map +1 -1
  61. package/dist/src/contracts/descriptors.d.ts +6 -0
  62. package/dist/src/contracts/descriptors.d.ts.map +1 -1
  63. package/dist/src/contracts/index.d.ts +6 -3
  64. package/dist/src/contracts/index.d.ts.map +1 -1
  65. package/dist/src/contracts/index.js.map +1 -1
  66. package/dist/src/contracts/items.d.ts +19 -0
  67. package/dist/src/contracts/items.d.ts.map +1 -1
  68. package/dist/src/contracts/record-history.d.ts +66 -0
  69. package/dist/src/contracts/record-history.d.ts.map +1 -0
  70. package/dist/src/contracts/record-history.js +2 -0
  71. package/dist/src/contracts/record-history.js.map +1 -0
  72. package/dist/src/contracts/restore.d.ts +0 -39
  73. package/dist/src/contracts/restore.d.ts.map +1 -1
  74. package/dist/src/firebase/adapter-store.d.ts +1 -0
  75. package/dist/src/firebase/adapter-store.d.ts.map +1 -1
  76. package/dist/src/firebase/adapter-store.js +3 -0
  77. package/dist/src/firebase/adapter-store.js.map +1 -1
  78. package/dist/src/firebase/binding-store.d.ts +2 -0
  79. package/dist/src/firebase/binding-store.d.ts.map +1 -1
  80. package/dist/src/firebase/binding-store.js +10 -0
  81. package/dist/src/firebase/binding-store.js.map +1 -1
  82. package/dist/src/firebase/catalog-data-index-store.d.ts +1 -0
  83. package/dist/src/firebase/catalog-data-index-store.d.ts.map +1 -1
  84. package/dist/src/firebase/catalog-data-index-store.js +3 -0
  85. package/dist/src/firebase/catalog-data-index-store.js.map +1 -1
  86. package/dist/src/firebase/catalog-item-history-store.d.ts +21 -0
  87. package/dist/src/firebase/catalog-item-history-store.d.ts.map +1 -0
  88. package/dist/src/firebase/catalog-item-history-store.js +61 -0
  89. package/dist/src/firebase/catalog-item-history-store.js.map +1 -0
  90. package/dist/src/firebase/catalog-store.d.ts +1 -0
  91. package/dist/src/firebase/catalog-store.d.ts.map +1 -1
  92. package/dist/src/firebase/catalog-store.js +3 -0
  93. package/dist/src/firebase/catalog-store.js.map +1 -1
  94. package/dist/src/firebase/index.d.ts +1 -0
  95. package/dist/src/firebase/index.d.ts.map +1 -1
  96. package/dist/src/firebase/index.js +1 -0
  97. package/dist/src/firebase/index.js.map +1 -1
  98. package/dist/src/firebase/mapping-store.d.ts +1 -0
  99. package/dist/src/firebase/mapping-store.d.ts.map +1 -1
  100. package/dist/src/firebase/mapping-store.js +3 -0
  101. package/dist/src/firebase/mapping-store.js.map +1 -1
  102. package/dist/src/firebase/native-item-store.d.ts +8 -2
  103. package/dist/src/firebase/native-item-store.d.ts.map +1 -1
  104. package/dist/src/firebase/native-item-store.js +22 -6
  105. package/dist/src/firebase/native-item-store.js.map +1 -1
  106. package/dist/src/firebase/reference-store.d.ts +3 -0
  107. package/dist/src/firebase/reference-store.d.ts.map +1 -1
  108. package/dist/src/firebase/reference-store.js +16 -0
  109. package/dist/src/firebase/reference-store.js.map +1 -1
  110. package/dist/src/firebase/renderer-snippet-store.d.ts +3 -0
  111. package/dist/src/firebase/renderer-snippet-store.d.ts.map +1 -1
  112. package/dist/src/firebase/renderer-snippet-store.js +17 -0
  113. package/dist/src/firebase/renderer-snippet-store.js.map +1 -1
  114. package/dist/src/firebase/snapshot-store.d.ts +1 -0
  115. package/dist/src/firebase/snapshot-store.d.ts.map +1 -1
  116. package/dist/src/firebase/snapshot-store.js +8 -0
  117. package/dist/src/firebase/snapshot-store.js.map +1 -1
  118. package/dist/test/integration/backup-data-gcs.live.test.d.ts +2 -0
  119. package/dist/test/integration/backup-data-gcs.live.test.d.ts.map +1 -0
  120. package/dist/test/integration/backup-data-gcs.live.test.js +98 -0
  121. package/dist/test/integration/backup-data-gcs.live.test.js.map +1 -0
  122. package/dist/test/integration/firestore.emulator.test.js +25 -4
  123. package/dist/test/integration/firestore.emulator.test.js.map +1 -1
  124. package/dist/test/integration/record-history.live.test.d.ts +2 -0
  125. package/dist/test/integration/record-history.live.test.d.ts.map +1 -0
  126. package/dist/test/integration/record-history.live.test.js +141 -0
  127. package/dist/test/integration/record-history.live.test.js.map +1 -0
  128. package/dist/test/unit/native-catalog-merge.test.d.ts +2 -0
  129. package/dist/test/unit/native-catalog-merge.test.d.ts.map +1 -0
  130. package/dist/test/unit/native-catalog-merge.test.js +33 -0
  131. package/dist/test/unit/native-catalog-merge.test.js.map +1 -0
  132. package/dist/test/unit/native-scope.test.d.ts +2 -0
  133. package/dist/test/unit/native-scope.test.d.ts.map +1 -0
  134. package/dist/test/unit/native-scope.test.js +29 -0
  135. package/dist/test/unit/native-scope.test.js.map +1 -0
  136. package/dist/test/unit/record-history-path.test.d.ts +2 -0
  137. package/dist/test/unit/record-history-path.test.d.ts.map +1 -0
  138. package/dist/test/unit/record-history-path.test.js +24 -0
  139. package/dist/test/unit/record-history-path.test.js.map +1 -0
  140. package/firestore.indexes.json +39 -0
  141. package/package.json +3 -2
@@ -1,66 +1,13 @@
1
- import { BACKUP_METADATA_SOURCE_NAMES, deleteAllDocsInFirestoreCollection, discoverNativeCatalogIds, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, firebaseVersionedName, formatBackupTimestamp, paginatedCopyFirestoreToFirestore, firebaseLatestName, } from "./backup-data.js";
1
+ import { BACKUP_METADATA_SOURCE_NAMES, deleteAllDocsInFirestoreCollection, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, paginatedCopyFirestoreToFirestore, } from "./backup-data.js";
2
2
  import { NativeItemStore } from "../firebase/native-item-store.js";
3
3
  import { DefinitionStore } from "../firebase/definition-store.js";
4
4
  import { CatalogDataIndexStore } from "../firebase/catalog-data-index-store.js";
5
- import { legacyNativeItemsCollectionRef, resolveNativeItemsLayout, nativeItemsCollectionId, } from "../firebase/catalog-data-paths.js";
6
- import { fixNativeCatalogDataMetadata } from "../migrations/migrate-native-catalog-layout.js";
5
+ import { legacyNativeItemsCollectionRef, nativeItemsCollectionId, } from "../firebase/catalog-data-paths.js";
7
6
  export const RESTORE_FIRESTORE_BACKUP_SESSION_COLLECTION = "backup-restoreSessions";
8
7
  const RESTORE_MANIFEST_COLLECTION = RESTORE_FIRESTORE_BACKUP_SESSION_COLLECTION;
9
- function sourceBackupCollectionId(source, logical) {
10
- if (source.kind === "latest")
11
- return firebaseLatestName(logical);
12
- return firebaseVersionedName(source.versionTimestamp, logical);
13
- }
14
8
  function preRestoreCollectionId(restoreSessionId, logical) {
15
9
  return `${restoreSessionId}__preRestore-${logical}`;
16
10
  }
17
- /**
18
- * Discover snapshot backup mirrors by scanning top-level collection ids.
19
- * Parses `catalogSnapshotsRun--{catalogId}--{runId}` with the last `--` as delimiter (catalogId / runId must not contain `--`).
20
- */
21
- async function listSnapshotRestoreWork(fs, source, includeSnapshots) {
22
- if (!includeSnapshots)
23
- return { snapshotCatalogIds: [], snapshotRuns: [] };
24
- const cols = await fs.listCollections();
25
- const itemPrefix = source.kind === "latest" ? "backup-catalogSnapshots--" : `${source.versionTimestamp}__backup-catalogSnapshots--`;
26
- const runPrefix = source.kind === "latest"
27
- ? "backup-catalogSnapshotsRun--"
28
- : `${source.versionTimestamp}__backup-catalogSnapshotsRun--`;
29
- const snapshotCatalogIds = new Set();
30
- const snapshotRuns = [];
31
- for (const c of cols) {
32
- const id = c.id;
33
- if (!id.startsWith(itemPrefix) || id.includes("catalogSnapshotsRun"))
34
- continue;
35
- const catalogId = id.slice(itemPrefix.length);
36
- if (!catalogId)
37
- continue;
38
- const probe = await fs.collection(id).limit(1).get();
39
- if (!probe.empty)
40
- snapshotCatalogIds.add(catalogId);
41
- }
42
- const runSeen = new Set();
43
- for (const c of cols) {
44
- const id = c.id;
45
- if (!id.startsWith(runPrefix))
46
- continue;
47
- const rest = id.slice(runPrefix.length);
48
- const delim = rest.lastIndexOf("--");
49
- if (delim === -1)
50
- continue;
51
- const catalogId = rest.slice(0, delim);
52
- const runId = rest.slice(delim + 2);
53
- const probe = await fs.collection(id).limit(1).get();
54
- if (probe.empty)
55
- continue;
56
- const rk = `${catalogId}\0${runId}`;
57
- if (runSeen.has(rk))
58
- continue;
59
- runSeen.add(rk);
60
- snapshotRuns.push({ catalogId, runId });
61
- }
62
- return { snapshotCatalogIds: [...snapshotCatalogIds], snapshotRuns };
63
- }
64
11
  async function writeManifest(fs, manifest) {
65
12
  await fs.collection(RESTORE_MANIFEST_COLLECTION).doc(manifest.restoreSessionId).set(manifest, { merge: true });
66
13
  }
@@ -70,175 +17,7 @@ async function readManifest(fs, restoreSessionId) {
70
17
  return null;
71
18
  return snap.data();
72
19
  }
73
- export async function runRestoreFirestoreBackup(deps, input) {
74
- const issues = [];
75
- const counts = {};
76
- const nativeItemSourceLayoutByCatalogId = {};
77
- if (input.source.kind === "versioned" && !input.source.versionTimestamp?.trim()) {
78
- return {
79
- ok: false,
80
- restoreSessionId: "",
81
- counts: {},
82
- issues: [{ code: "missing_version_timestamp", message: "versioned restore requires versionTimestamp" }],
83
- nativeItemSourceLayoutByCatalogId: {},
84
- };
85
- }
86
- const fs = deps.firestoreStore.firestore;
87
- const restoreSessionId = (input.restoreSessionId?.trim() && input.restoreSessionId) || formatBackupTimestamp();
88
- const includeSnapshots = Boolean(input.includeSnapshots);
89
- const allCatalogs = await deps.catalogs.listAll();
90
- const nativeCatalogIds = await discoverNativeCatalogIds(fs, allCatalogs, {
91
- bindings: deps.bindings,
92
- ...(input.catalogIds != null && input.catalogIds.length ? { catalogIds: input.catalogIds } : {}),
93
- ...(input.appId != null && input.appId !== "" ? { appId: input.appId } : {}),
94
- });
95
- const probeLogical = BACKUP_METADATA_SOURCE_NAMES[0];
96
- const probeId = sourceBackupCollectionId(input.source, probeLogical);
97
- const probeSnap = await fs.collection(probeId).limit(1).get();
98
- if (probeSnap.empty) {
99
- return {
100
- ok: false,
101
- restoreSessionId,
102
- counts,
103
- issues: [
104
- {
105
- code: "backup_source_empty",
106
- message: `No documents in backup collection ${probeId}; nothing to restore from this source`,
107
- detail: { probeId },
108
- },
109
- ],
110
- nativeItemSourceLayoutByCatalogId: {},
111
- };
112
- }
113
- const { snapshotCatalogIds, snapshotRuns } = await listSnapshotRestoreWork(fs, input.source, includeSnapshots);
114
- try {
115
- for (const name of BACKUP_METADATA_SOURCE_NAMES) {
116
- const destPre = preRestoreCollectionId(restoreSessionId, name);
117
- await deleteAllDocsInFirestoreCollection(fs, destPre);
118
- await paginatedCopyFirestoreToFirestore(fs, name, destPre, counts, `pre:${destPre}`);
119
- }
120
- for (const catalogId of nativeCatalogIds) {
121
- const layout = await resolveNativeItemsLayout(fs, catalogId);
122
- nativeItemSourceLayoutByCatalogId[String(catalogId)] = layout;
123
- const logical = firebaseNativeLogical(String(catalogId));
124
- const destPre = preRestoreCollectionId(restoreSessionId, logical);
125
- await deleteAllDocsInFirestoreCollection(fs, destPre);
126
- const livePath = layout === "legacy"
127
- ? legacyNativeItemsCollectionRef(fs, catalogId).path
128
- : fs.collection(nativeItemsCollectionId(String(catalogId))).path;
129
- await paginatedCopyFirestoreToFirestore(fs, livePath, destPre, counts, `pre:${destPre}`);
130
- }
131
- if (includeSnapshots) {
132
- for (const catalogId of snapshotCatalogIds) {
133
- const logical = firebaseSnapshotLogical(catalogId);
134
- const destPre = preRestoreCollectionId(restoreSessionId, logical);
135
- await deleteAllDocsInFirestoreCollection(fs, destPre);
136
- const liveItems = fs.collection("catalogSnapshots").doc(catalogId).collection("items").path;
137
- await paginatedCopyFirestoreToFirestore(fs, liveItems, destPre, counts, `pre:${destPre}`);
138
- }
139
- for (const { catalogId, runId } of snapshotRuns) {
140
- const logical = firebaseSnapshotRunLogical(catalogId, runId);
141
- const destPre = preRestoreCollectionId(restoreSessionId, logical);
142
- await deleteAllDocsInFirestoreCollection(fs, destPre);
143
- const livePath = fs.collection("catalogSnapshots").doc(catalogId).collection("runs").doc(runId).collection("items")
144
- .path;
145
- await paginatedCopyFirestoreToFirestore(fs, livePath, destPre, counts, `pre:${destPre}`);
146
- }
147
- }
148
- const manifest = {
149
- restoreSessionId,
150
- createdAt: new Date().toISOString(),
151
- source: input.source,
152
- includeSnapshots,
153
- phase: "preRestoreCaptured",
154
- nativeCatalogIds: nativeCatalogIds.map(String),
155
- nativeItemSourceLayoutByCatalogId: { ...nativeItemSourceLayoutByCatalogId },
156
- metadataSourceNames: BACKUP_METADATA_SOURCE_NAMES,
157
- snapshotCatalogIds,
158
- snapshotRuns,
159
- };
160
- await writeManifest(fs, manifest);
161
- for (const name of BACKUP_METADATA_SOURCE_NAMES) {
162
- const src = sourceBackupCollectionId(input.source, name);
163
- await deleteAllDocsInFirestoreCollection(fs, name);
164
- await paginatedCopyFirestoreToFirestore(fs, src, name, counts, `restore:${name}`);
165
- }
166
- for (const catalogId of nativeCatalogIds) {
167
- const cid = String(catalogId);
168
- const flatPath = nativeItemsCollectionId(cid);
169
- await deleteAllDocsInFirestoreCollection(fs, flatPath);
170
- const src = sourceBackupCollectionId(input.source, firebaseNativeLogical(cid));
171
- await paginatedCopyFirestoreToFirestore(fs, src, flatPath, counts, `restore:nativeFlat:${cid}`);
172
- const legacyPath = legacyNativeItemsCollectionRef(fs, catalogId).path;
173
- await deleteAllDocsInFirestoreCollection(fs, legacyPath);
174
- }
175
- const nowIso = new Date().toISOString();
176
- if (nativeCatalogIds.length > 0) {
177
- await fixNativeCatalogDataMetadata({
178
- definitions: deps.definitions,
179
- catalogDataIndex: deps.catalogDataIndex,
180
- nativeItems: deps.nativeItems,
181
- }, nativeCatalogIds, nowIso);
182
- }
183
- if (includeSnapshots) {
184
- for (const catalogId of snapshotCatalogIds) {
185
- const dest = fs.collection("catalogSnapshots").doc(catalogId).collection("items").path;
186
- const src = sourceBackupCollectionId(input.source, firebaseSnapshotLogical(catalogId));
187
- await deleteAllDocsInFirestoreCollection(fs, dest);
188
- await paginatedCopyFirestoreToFirestore(fs, src, dest, counts, `restore:snap:${catalogId}`);
189
- }
190
- for (const { catalogId, runId } of snapshotRuns) {
191
- const dest = fs
192
- .collection("catalogSnapshots")
193
- .doc(catalogId)
194
- .collection("runs")
195
- .doc(runId)
196
- .collection("items").path;
197
- const src = sourceBackupCollectionId(input.source, firebaseSnapshotRunLogical(catalogId, runId));
198
- await deleteAllDocsInFirestoreCollection(fs, dest);
199
- await paginatedCopyFirestoreToFirestore(fs, src, dest, counts, `restore:snaprun:${catalogId}:${runId}`);
200
- }
201
- }
202
- await writeManifest(fs, { ...manifest, phase: "restored" });
203
- deps.nativeItems.invalidateLayoutCache();
204
- return {
205
- ok: true,
206
- restoreSessionId,
207
- counts,
208
- issues,
209
- nativeItemSourceLayoutByCatalogId,
210
- };
211
- }
212
- catch (e) {
213
- const msg = e instanceof Error ? e.message : String(e);
214
- issues.push({ code: "restore_failed", message: msg });
215
- try {
216
- await writeManifest(fs, {
217
- restoreSessionId,
218
- createdAt: new Date().toISOString(),
219
- source: input.source,
220
- includeSnapshots,
221
- phase: "failed",
222
- nativeCatalogIds: nativeCatalogIds.map(String),
223
- nativeItemSourceLayoutByCatalogId: { ...nativeItemSourceLayoutByCatalogId },
224
- metadataSourceNames: BACKUP_METADATA_SOURCE_NAMES,
225
- snapshotCatalogIds,
226
- snapshotRuns,
227
- });
228
- }
229
- catch {
230
- // ignore manifest write errors during failure handling
231
- }
232
- deps.nativeItems.invalidateLayoutCache();
233
- return {
234
- ok: false,
235
- restoreSessionId,
236
- counts,
237
- issues,
238
- nativeItemSourceLayoutByCatalogId,
239
- };
240
- }
241
- }
20
+ // Firestore mirror restore (backup-* / {ts}__backup-*) removed; backups are storage-only (GCS).
242
21
  export async function runUndoFirestoreRestore(deps, input) {
243
22
  const issues = [];
244
23
  const counts = {};
@@ -1 +1 @@
1
- {"version":3,"file":"restore-firestore-backup.js","sourceRoot":"","sources":["../../../src/catalox/restore-firestore-backup.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"restore-firestore-backup.js","sourceRoot":"","sources":["../../../src/catalox/restore-firestore-backup.ts"],"names":[],"mappings":"AAQA,OAAO,EACL,4BAA4B,EAC5B,kCAAkC,EAClC,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,EAC1B,iCAAiC,GAClC,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,MAAM,iCAAiC,CAAC;AAClE,OAAO,EAAE,qBAAqB,EAAE,MAAM,yCAAyC,CAAC;AAChF,OAAO,EACL,8BAA8B,EAC9B,uBAAuB,GACxB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,CAAC,MAAM,2CAA2C,GAAG,wBAAwB,CAAC;AAEpF,MAAM,2BAA2B,GAAG,2CAA2C,CAAC;AAQhF,SAAS,sBAAsB,CAAC,gBAAwB,EAAE,OAAe;IACvE,OAAO,GAAG,gBAAgB,gBAAgB,OAAO,EAAE,CAAC;AACtD,CAAC;AAgBD,KAAK,UAAU,aAAa,CAAC,EAAa,EAAE,QAA+C;IACzF,MAAM,EAAE,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC,GAAG,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;AACjH,CAAC;AAED,KAAK,UAAU,YAAY,CACzB,EAAa,EACb,gBAAwB;IAExB,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC,GAAG,EAAE,CAAC;IAC1F,IAAI,CAAC,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IAC9B,OAAO,IAAI,CAAC,IAAI,EAA2C,CAAC;AAC9D,CAAC;AAED,gGAAgG;AAEhG,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAA0B,EAC1B,KAAgC;IAEhC,MAAM,MAAM,GAAgC,EAAE,CAAC;IAC/C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,EAAE,GAAG,IAAI,CAAC,cAAc,CAAC,SAAS,CAAC;IACzC,MAAM,EAAE,GAAG,KAAK,CAAC,gBAAgB,CAAC,IAAI,EAAE,CAAC;IACzC,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,8BAA8B,EAAE,CAAC,EAAE,CAAC;IAC/G,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;IAC5C,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM;YACN,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,oBAAoB,EAAE,OAAO,EAAE,0BAA0B,2BAA2B,IAAI,EAAE,EAAE,EAAE,CAAC;SACjH,CAAC;IACJ,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChC,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,yCAAyC,EAAE,CAAC,EAAE,CAAC;IACzH,CAAC;IACD,IAAI,QAAQ,CAAC,KAAK,KAAK,UAAU,EAAE,CAAC;QAClC,OAAO;YACL,EAAE,EAAE,KAAK;YACT,MAAM;YACN,MAAM,EAAE;gBACN;oBACE,IAAI,EAAE,eAAe;oBACrB,OAAO,EAAE,4CAA4C,QAAQ,CAAC,KAAK,GAAG;iBACvE;aACF;SACF,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,IAAI,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAC9B,KAAK,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;gBACzD,MAAM,OAAO,GAAG,0BAA0B,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;gBAC7D,MAAM,GAAG,GAAG,sBAAsB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAChD,MAAM,IAAI,GAAG,EAAE;qBACZ,UAAU,CAAC,kBAAkB,CAAC;qBAC9B,GAAG,CAAC,SAAS,CAAC;qBACd,UAAU,CAAC,MAAM,CAAC;qBAClB,GAAG,CAAC,KAAK,CAAC;qBACV,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;gBAC5B,MAAM,kCAAkC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBACnD,MAAM,iCAAiC,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,gBAAgB,SAAS,IAAI,KAAK,EAAE,CAAC,CAAC;YACvG,CAAC;YACD,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,kBAAkB,EAAE,CAAC;gBACpD,MAAM,OAAO,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;gBACnD,MAAM,GAAG,GAAG,sBAAsB,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;gBAChD,MAAM,IAAI,GAAG,EAAE,CAAC,UAAU,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC;gBACvF,MAAM,kCAAkC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;gBACnD,MAAM,iCAAiC,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,aAAa,SAAS,EAAE,CAAC,CAAC;YAC3F,CAAC;QACH,CAAC;QAED,KAAK,MAAM,SAAS,IAAI,QAAQ,CAAC,gBAAgB,EAAE,CAAC;YAClD,MAAM,MAAM,GAAG,QAAQ,CAAC,iCAAiC,CAAC,SAAS,CAAC,IAAI,MAAM,CAAC;YAC/E,MAAM,GAAG,GAAG,SAAsB,CAAC;YACnC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,SAAS,CAAC,CAAC;YACpD,MAAM,UAAU,GAAG,8BAA8B,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC;YAChE,MAAM,GAAG,GAAG,sBAAsB,CAAC,EAAE,EAAE,qBAAqB,CAAC,SAAS,CAAC,CAAC,CAAC;YACzE,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBACxB,MAAM,kCAAkC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACvD,MAAM,kCAAkC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBACzD,MAAM,iCAAiC,CAAC,EAAE,EAAE,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,eAAe,SAAS,EAAE,CAAC,CAAC;YACnG,CAAC;iBAAM,CAAC;gBACN,MAAM,kCAAkC,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;gBACvD,MAAM,kCAAkC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBACzD,MAAM,iCAAiC,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,eAAe,SAAS,EAAE,CAAC,CAAC;YACjG,CAAC;QACH,CAAC;QAED,KAAK,MAAM,IAAI,IAAI,QAAQ,CAAC,mBAAmB,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,sBAAsB,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC7C,MAAM,kCAAkC,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YACnD,MAAM,iCAAiC,CAAC,EAAE,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,aAAa,CAAC,EAAE,EAAE,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC1D,IAAI,CAAC,WAAW,CAAC,qBAAqB,EAAE,CAAC;QAEzC,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACtC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,GAAG,GAAG,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC;QACnD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;IACvC,CAAC;AACH,CAAC"}
@@ -49,7 +49,7 @@ function baseContext(opts) {
49
49
  return {
50
50
  appId,
51
51
  ...(storeId ? { storeId } : {}),
52
- ...(opts.god ? { isGodMode: true } : {}),
52
+ ...(opts.god ? { superAdmin: true } : {}),
53
53
  ...(userId ? { userId, actor: { type: "user", id: userId } } : {}),
54
54
  };
55
55
  }
@@ -267,25 +267,21 @@ storeCmd
267
267
  });
268
268
  const firestoreCmd = program
269
269
  .command("firestore")
270
- .description("Firestore backup, restore (Firebase mirrors), and native layout migration");
270
+ .description("Firestore backup (GCS), restore-from-GCS, and native layout migration");
271
271
  firestoreCmd
272
272
  .command("backup")
273
- .description("Generic Catalox backup to Mongo (catalox-backups), Firebase (backup-* collections), or GCS (NDJSON via @x12i/helpers/gcs)")
273
+ .description("Catalox backup to GCS only (NDJSON + catalox-backup-manifest.json)")
274
274
  .requiredOption("--app <appId>", "AppId for Catalox context")
275
- .requiredOption("--mode <mongo|firebase|gcs>", "Backup target")
276
- .option("--mongo-uri <uri>", "Mongo connection string (required when mode=mongo)")
277
- .option("--bucket <name>", "GCS bucket name (required when mode=gcs)")
275
+ .requiredOption("--bucket <name>", "GCS bucket name")
278
276
  .option("--gcs-prefix <path>", "Optional prefix before timestamp folder (default: catalox-firestore-backups/)", "")
279
277
  .option("--label <text>", "Backup label stored on manifest")
280
278
  .option("--snapshots", "Include catalogSnapshots data", false)
281
279
  .option("--catalog <catalogId...>", "Restrict which native catalogs are copied")
282
280
  .option("--god", "God mode", false)
283
281
  .action(async (opts) => {
284
- const m = String(opts.mode).toLowerCase();
285
- const mode = m === "mongo" ? "mongo" : m === "gcs" ? "gcs" : "firebase";
286
- if (mode === "gcs" && !(opts.bucket != null && String(opts.bucket).trim())) {
282
+ if (!(opts.bucket != null && String(opts.bucket).trim())) {
287
283
  // eslint-disable-next-line no-console
288
- console.error("--bucket is required when --mode gcs");
284
+ console.error("--bucket is required");
289
285
  process.exitCode = 1;
290
286
  return;
291
287
  }
@@ -293,14 +289,9 @@ firestoreCmd
293
289
  const ctx = baseContext({ app: opts.app, god: opts.god });
294
290
  const gcsPrefixOpt = opts.gcsPrefix != null && String(opts.gcsPrefix).trim() ? String(opts.gcsPrefix).trim() : undefined;
295
291
  const res = await catalox.backupData(ctx, {
296
- mode,
297
- mongoBackupUri: opts.mongoUri,
298
- ...(mode === "gcs"
299
- ? {
300
- gcsBucket: String(opts.bucket).trim(),
301
- ...(gcsPrefixOpt !== undefined ? { gcsPrefix: gcsPrefixOpt } : {}),
302
- }
303
- : {}),
292
+ mode: "gcs",
293
+ gcsBucket: String(opts.bucket).trim(),
294
+ ...(gcsPrefixOpt !== undefined ? { gcsPrefix: gcsPrefixOpt } : {}),
304
295
  includeSnapshots: Boolean(opts.snapshots),
305
296
  ...(opts.catalog?.length ? { catalogIds: opts.catalog } : {}),
306
297
  ...(opts.label != null && String(opts.label) !== "" ? { backupLabel: String(opts.label) } : {}),
@@ -309,42 +300,11 @@ firestoreCmd
309
300
  if (!res.ok)
310
301
  process.exitCode = 1;
311
302
  });
312
- firestoreCmd
313
- .command("restore-backup")
314
- .description("Restore live Firestore from backup-* (same DB). Captures pre-restore copies to {session}__preRestore-* for undo.")
315
- .requiredOption("--app <appId>", "AppId for Catalox context")
316
- .option("--from <latest|versioned>", "Backup source", "latest")
317
- .option("--version-ts <token>", "When --from versioned: timestamp token matching backup collection prefix")
318
- .option("--snapshots", "Also restore catalogSnapshots from backup mirrors", false)
319
- .option("--catalog <catalogId...>", "Restrict which native catalogs are restored")
320
- .option("--god", "God mode", false)
321
- .action(async (opts) => {
322
- const catalox = createCatalox();
323
- const ctx = baseContext({ app: opts.app, god: opts.god });
324
- const from = String(opts.from).toLowerCase();
325
- const source = from === "versioned"
326
- ? { kind: "versioned", versionTimestamp: String(opts.versionTs ?? "") }
327
- : { kind: "latest" };
328
- if (from === "versioned" && !String(opts.versionTs ?? "").trim()) {
329
- // eslint-disable-next-line no-console
330
- console.error("--version-ts is required when --from versioned");
331
- process.exitCode = 1;
332
- return;
333
- }
334
- const res = await catalox.restoreFirestoreBackup(ctx, {
335
- source,
336
- includeSnapshots: Boolean(opts.snapshots),
337
- ...(opts.catalog?.length ? { catalogIds: opts.catalog } : {}),
338
- });
339
- await writeOrStdout(JSON.stringify(res, null, 2));
340
- if (!res.ok)
341
- process.exitCode = 1;
342
- });
343
303
  firestoreCmd
344
304
  .command("undo-restore-backup")
345
- .description("Revert a prior restore-backup or restore-backup-from-gcs using backup-restoreSessions/{sessionId} and preRestore collections")
305
+ .description("Revert a prior restore-backup-from-gcs using backup-restoreSessions/{sessionId} and preRestore collections")
346
306
  .requiredOption("--app <appId>", "AppId for Catalox context")
347
- .requiredOption("--session <restoreSessionId>", "restoreSessionId returned by restore-backup")
307
+ .requiredOption("--session <restoreSessionId>", "restoreSessionId returned by restore-backup-from-gcs")
348
308
  .option("--god", "God mode", false)
349
309
  .action(async (opts) => {
350
310
  const catalox = createCatalox();
@@ -358,7 +318,7 @@ firestoreCmd
358
318
  });
359
319
  firestoreCmd
360
320
  .command("restore-backup-from-gcs")
361
- .description("Restore live Firestore from one backupData GCS run (NDJSON under --run-folder). Same undo semantics as restore-backup.")
321
+ .description("Restore live Firestore from one backupData GCS run (NDJSON under --run-folder). Uses pre-restore sidecars so undo works.")
362
322
  .requiredOption("--app <appId>", "AppId for Catalox context")
363
323
  .requiredOption("--bucket <name>", "GCS bucket name")
364
324
  .requiredOption("--run-folder <path>", "Run folder within bucket (e.g. catalox-firestore-backups/2026_04_18T12_00_00Z)")
@@ -457,9 +417,11 @@ firestoreCmd
457
417
  });
458
418
  firestoreCmd
459
419
  .command("migrate-native-catalog-data")
460
- .description("Backup (Firebase) then copy legacy catalogData/{catalogId}/items → flat catalogData-{catalogId}-items (stops OLD layout)")
420
+ .description("Optional pre-migrate backup to GCS, then copy legacy catalogData/{catalogId}/items → flat catalogData-{catalogId}-items")
461
421
  .requiredOption("--app <appId>", "AppId for Catalox context")
462
- .option("--skip-backup", "Skip Firebase backupData before migrate", false)
422
+ .option("--skip-backup", "Skip pre-migrate GCS backup", false)
423
+ .option("--backup-bucket <name>", "GCS bucket for pre-migrate backup (required unless --skip-backup)")
424
+ .option("--backup-prefix <path>", "Optional gcsPrefix for pre-migrate backupData")
463
425
  .option("--backup-label <text>", "Label for pre-migrate backup", "pre-native-layout-migration")
464
426
  .option("--snapshots", "Include snapshots in pre-migrate backup", false)
465
427
  .option("--dry-run", "Count/copy simulation only for migrate", false)
@@ -474,8 +436,18 @@ firestoreCmd
474
436
  const catalox = createCatalox();
475
437
  const ctx = baseContext({ app: opts.app, god: opts.god });
476
438
  if (!opts.skipBackup) {
439
+ if (!(opts.backupBucket != null && String(opts.backupBucket).trim())) {
440
+ // eslint-disable-next-line no-console
441
+ console.error("--backup-bucket is required unless --skip-backup");
442
+ process.exitCode = 1;
443
+ return;
444
+ }
477
445
  const b = await catalox.backupData(ctx, {
478
- mode: "firebase",
446
+ mode: "gcs",
447
+ gcsBucket: String(opts.backupBucket).trim(),
448
+ ...(opts.backupPrefix != null && String(opts.backupPrefix).trim() !== ""
449
+ ? { gcsPrefix: String(opts.backupPrefix).trim() }
450
+ : {}),
479
451
  backupLabel: String(opts.backupLabel != null ? opts.backupLabel : "pre-native-layout-migration"),
480
452
  includeSnapshots: Boolean(opts.snapshots),
481
453
  });
@@ -669,6 +641,138 @@ firestoreCmd
669
641
  if (!res.ok)
670
642
  process.exitCode = 1;
671
643
  });
644
+ const historyCmd = program.command("history").description("Native item history (Firestore index + GCS payloads)");
645
+ historyCmd
646
+ .command("list")
647
+ .description("List catalogItemHistory rows for a catalog (newest first)")
648
+ .requiredOption("--app <appId>", "AppId for authz")
649
+ .requiredOption("--catalog <catalogId>", "Catalog id")
650
+ .option("--item <itemId>", "Filter by logical item id")
651
+ .option("--op <op>", "Filter by op (update|delete|restore|catalog_delete_bulk|catalog_rename)")
652
+ .option("--since <iso>", "Client-side filter: ts >= since")
653
+ .option("--until <iso>", "Client-side filter: ts <= until")
654
+ .option("--limit <n>", "Page size", "50")
655
+ .option("--cursor <eventId>", "startAfterEventId for pagination")
656
+ .option("--god", "God mode", false)
657
+ .action(async (opts) => {
658
+ const catalox = createCatalox();
659
+ const ctx = baseContext({ app: opts.app, god: opts.god });
660
+ const limit = Math.max(1, Math.min(500, parseInt(String(opts.limit ?? "50"), 10) || 50));
661
+ const res = await catalox.listCatalogItemHistory(ctx, String(opts.catalog), {
662
+ ...(opts.item ? { itemId: String(opts.item) } : {}),
663
+ ...(opts.op ? { op: String(opts.op) } : {}),
664
+ ...(opts.since ? { since: String(opts.since) } : {}),
665
+ ...(opts.until ? { until: String(opts.until) } : {}),
666
+ limit,
667
+ ...(opts.cursor ? { startAfterEventId: String(opts.cursor) } : {}),
668
+ });
669
+ await writeOrStdout(JSON.stringify(res, null, 2));
670
+ });
671
+ historyCmd
672
+ .command("show")
673
+ .description("Load index row + GCS payload for one eventId")
674
+ .requiredOption("--app <appId>", "AppId for authz")
675
+ .argument("<eventId>", "catalogItemHistory document id")
676
+ .option("--god", "God mode", false)
677
+ .action(async (eventId, opts) => {
678
+ const catalox = createCatalox();
679
+ const ctx = baseContext({ app: opts.app, god: opts.god });
680
+ const res = await catalox.getCatalogItemHistoryEvent(ctx, String(eventId));
681
+ await writeOrStdout(JSON.stringify(res, null, 2));
682
+ if (!res)
683
+ process.exitCode = 1;
684
+ });
685
+ historyCmd
686
+ .command("restore")
687
+ .description("Restore a native row from a history event (before or after snapshot)")
688
+ .requiredOption("--app <appId>", "AppId for authz")
689
+ .argument("<eventId>", "catalogItemHistory document id")
690
+ .option("--mode <before|after>", "Which snapshot to apply", "before")
691
+ .option("--god", "God mode", false)
692
+ .action(async (eventId, opts) => {
693
+ const catalox = createCatalox();
694
+ const ctx = baseContext({ app: opts.app, god: opts.god });
695
+ const mode = String(opts.mode ?? "before").toLowerCase() === "after" ? "after" : "before";
696
+ const res = await catalox.restoreCatalogItemFromHistory(ctx, String(eventId), { mode });
697
+ await writeOrStdout(JSON.stringify(res, null, 2));
698
+ });
699
+ historyCmd
700
+ .command("replay")
701
+ .description("Replay history up to --as-of and diff-apply to live native items")
702
+ .requiredOption("--app <appId>", "AppId for authz")
703
+ .requiredOption("--catalog <catalogId>", "Catalog id")
704
+ .requiredOption("--as-of <iso>", "Inclusive upper bound on event ts")
705
+ .option("--god", "God mode", false)
706
+ .action(async (opts) => {
707
+ const catalox = createCatalox();
708
+ const ctx = baseContext({ app: opts.app, god: opts.god });
709
+ const res = await catalox.replayCatalogToPointInTime(ctx, String(opts.catalog), { asOf: String(opts.asOf) });
710
+ await writeOrStdout(JSON.stringify(res, null, 2));
711
+ });
712
+ const catalogCmd = program.command("catalog").description("Catalog lifecycle (delete / restore / hard rename)");
713
+ catalogCmd
714
+ .command("delete")
715
+ .description("Snapshot catalog to GCS, write delete manifest, then hard-delete Firestore rows (requires record history bucket)")
716
+ .requiredOption("--app <appId>", "AppId for authz")
717
+ .requiredOption("--catalog <catalogId>", "Catalog id")
718
+ .option("--confirm", "Must pass --confirm to run", false)
719
+ .option("--backup-bucket <name>", "Optional: run backupData mode=gcs to this bucket before delete")
720
+ .option("--backup-prefix <path>", "Optional gcsPrefix for pre-delete backupData")
721
+ .option("--god", "God mode", false)
722
+ .action(async (opts) => {
723
+ if (!opts.confirm) {
724
+ // eslint-disable-next-line no-console
725
+ console.error("Refusing to delete without --confirm");
726
+ process.exitCode = 1;
727
+ return;
728
+ }
729
+ const catalox = createCatalox();
730
+ const ctx = baseContext({ app: opts.app, god: opts.god });
731
+ const res = await catalox.deleteCatalog(ctx, String(opts.catalog), {
732
+ confirm: true,
733
+ ...(opts.backupBucket ? { gcsBackupBucket: String(opts.backupBucket).trim() } : {}),
734
+ ...(opts.backupPrefix ? { gcsBackupPrefix: String(opts.backupPrefix).trim() } : {}),
735
+ });
736
+ await writeOrStdout(JSON.stringify(res, null, 2));
737
+ if (!res.ok)
738
+ process.exitCode = 1;
739
+ });
740
+ catalogCmd
741
+ .command("restore")
742
+ .description("Restore a catalog from a delete manifest path (requires superAdmin context / --god)")
743
+ .requiredOption("--app <appId>", "AppId (superAdmin)")
744
+ .requiredOption("--manifest <relativePath>", "GCS object path relative to record-history prefix, ending in manifest.json")
745
+ .option("--god", "God mode (superAdmin)", true)
746
+ .action(async (opts) => {
747
+ const catalox = createCatalox();
748
+ const ctx = baseContext({ app: opts.app, god: true });
749
+ const res = await catalox.restoreDeletedCatalog(ctx, {
750
+ gcsManifestRelativePath: String(opts.manifest).trim(),
751
+ });
752
+ await writeOrStdout(JSON.stringify(res, null, 2));
753
+ if (!res.ok)
754
+ process.exitCode = 1;
755
+ });
756
+ catalogCmd
757
+ .command("rename")
758
+ .description("Hard rename catalog id (copy + rewrite + delete source; requires record history bucket)")
759
+ .requiredOption("--app <appId>", "AppId for authz")
760
+ .requiredOption("--from <catalogId>", "Source catalog id")
761
+ .requiredOption("--to <catalogId>", "Target catalog id (must not exist)")
762
+ .option("--backup-bucket <name>", "Optional: backupData gcs bucket before rename")
763
+ .option("--backup-prefix <path>", "Optional gcsPrefix for pre-rename backup")
764
+ .option("--god", "God mode", false)
765
+ .action(async (opts) => {
766
+ const catalox = createCatalox();
767
+ const ctx = baseContext({ app: opts.app, god: opts.god });
768
+ const res = await catalox.renameCatalog(ctx, String(opts.from), String(opts.to), {
769
+ ...(opts.backupBucket ? { gcsBackupBucket: String(opts.backupBucket).trim() } : {}),
770
+ ...(opts.backupPrefix ? { gcsBackupPrefix: String(opts.backupPrefix).trim() } : {}),
771
+ });
772
+ await writeOrStdout(JSON.stringify(res, null, 2));
773
+ if (!res.ok)
774
+ process.exitCode = 1;
775
+ });
672
776
  program.parseAsync(process.argv).catch((err) => {
673
777
  // eslint-disable-next-line no-console
674
778
  console.error(err instanceof Error ? err.message : err);