@x12i/catalox 2.4.0 → 2.6.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.
- package/README.md +43 -4
- package/dist/src/catalox/backup-data.d.ts +2 -4
- package/dist/src/catalox/backup-data.d.ts.map +1 -1
- package/dist/src/catalox/backup-data.js +206 -1
- package/dist/src/catalox/backup-data.js.map +1 -1
- package/dist/src/catalox/catalox.d.ts +17 -0
- package/dist/src/catalox/catalox.d.ts.map +1 -1
- package/dist/src/catalox/catalox.js +64 -6
- package/dist/src/catalox/catalox.js.map +1 -1
- package/dist/src/catalox/firestore-gcs-compare.d.ts +15 -0
- package/dist/src/catalox/firestore-gcs-compare.d.ts.map +1 -0
- package/dist/src/catalox/firestore-gcs-compare.js +221 -0
- package/dist/src/catalox/firestore-gcs-compare.js.map +1 -0
- package/dist/src/catalox/firestore-gcs-transfer.d.ts +24 -0
- package/dist/src/catalox/firestore-gcs-transfer.d.ts.map +1 -0
- package/dist/src/catalox/firestore-gcs-transfer.js +329 -0
- package/dist/src/catalox/firestore-gcs-transfer.js.map +1 -0
- package/dist/src/catalox/index.d.ts +3 -1
- package/dist/src/catalox/index.d.ts.map +1 -1
- package/dist/src/catalox/index.js +3 -1
- package/dist/src/catalox/index.js.map +1 -1
- package/dist/src/cli/index.js +188 -4
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/contracts/backup.d.ts +11 -1
- package/dist/src/contracts/backup.d.ts.map +1 -1
- package/dist/src/contracts/catalogs.d.ts +6 -0
- package/dist/src/contracts/catalogs.d.ts.map +1 -1
- package/dist/src/contracts/catalogs.js +18 -1
- package/dist/src/contracts/catalogs.js.map +1 -1
- package/dist/src/contracts/gcs-firestore-compare.d.ts +64 -0
- package/dist/src/contracts/gcs-firestore-compare.d.ts.map +1 -0
- package/dist/src/contracts/gcs-firestore-compare.js +2 -0
- package/dist/src/contracts/gcs-firestore-compare.js.map +1 -0
- package/dist/src/contracts/gcs-firestore-transfer.d.ts +94 -0
- package/dist/src/contracts/gcs-firestore-transfer.d.ts.map +1 -0
- package/dist/src/contracts/gcs-firestore-transfer.js +2 -0
- package/dist/src/contracts/gcs-firestore-transfer.js.map +1 -0
- package/dist/src/contracts/index.d.ts +3 -0
- package/dist/src/contracts/index.d.ts.map +1 -1
- package/dist/src/contracts/index.js +1 -0
- package/dist/src/contracts/index.js.map +1 -1
- package/dist/src/firebase/firestore-collection-path.d.ts +7 -0
- package/dist/src/firebase/firestore-collection-path.d.ts.map +1 -0
- package/dist/src/firebase/firestore-collection-path.js +24 -0
- package/dist/src/firebase/firestore-collection-path.js.map +1 -0
- package/dist/src/firebase/native-item-store.d.ts +6 -0
- package/dist/src/firebase/native-item-store.d.ts.map +1 -1
- package/dist/src/firebase/native-item-store.js +18 -1
- package/dist/src/firebase/native-item-store.js.map +1 -1
- package/dist/test/unit/compact-catalog-filter.test.d.ts +2 -0
- package/dist/test/unit/compact-catalog-filter.test.d.ts.map +1 -0
- package/dist/test/unit/compact-catalog-filter.test.js +18 -0
- package/dist/test/unit/compact-catalog-filter.test.js.map +1 -0
- package/dist/test/unit/gcs-backup-run-folder.test.d.ts +2 -0
- package/dist/test/unit/gcs-backup-run-folder.test.d.ts.map +1 -0
- package/dist/test/unit/gcs-backup-run-folder.test.js +10 -0
- package/dist/test/unit/gcs-backup-run-folder.test.js.map +1 -0
- package/dist/test/unit/gcs-firestore-compare.test.d.ts +2 -0
- package/dist/test/unit/gcs-firestore-compare.test.d.ts.map +1 -0
- package/dist/test/unit/gcs-firestore-compare.test.js +14 -0
- package/dist/test/unit/gcs-firestore-compare.test.js.map +1 -0
- package/dist/test/unit/gcs-firestore-paths.test.d.ts +2 -0
- package/dist/test/unit/gcs-firestore-paths.test.d.ts.map +1 -0
- package/dist/test/unit/gcs-firestore-paths.test.js +16 -0
- package/dist/test/unit/gcs-firestore-paths.test.js.map +1 -0
- package/package.json +5 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore-gcs-transfer.d.ts","sourceRoot":"","sources":["../../../src/catalox/firestore-gcs-transfer.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,OAAO,EAA0B,MAAM,uBAAuB,CAAC;AAIxE,OAAO,KAAK,EACV,uCAAuC,EACvC,wCAAwC,EACxC,mCAAmC,EACnC,oCAAoC,EAGpC,0CAA0C,EAC1C,2CAA2C,EAC3C,sCAAsC,EACtC,uCAAuC,EACxC,MAAM,wCAAwC,CAAC;AAEhD,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AAEtF,sGAAsG;AACtG,eAAO,MAAM,8BAA8B,2CAA2C,CAAC;AAEvF,KAAK,eAAe,GAAG;IAAE,OAAO,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAE7C,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAI1D;AAED,yEAAyE;AACzE,wBAAgB,mCAAmC,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,CAMlF;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,GAAG,MAAM,CAIT;AAOD,qHAAqH;AACrH,eAAO,MAAM,qBAAqB,mCAA6B,CAAC;AAyEhE,wBAAsB,8BAA8B,CAClD,KAAK,EAAE,mCAAmC,GAAG,eAAe,GAC3D,OAAO,CAAC,oCAAoC,CAAC,CAwB/C;AAED,wBAAsB,kCAAkC,CACtD,KAAK,EAAE,uCAAuC,GAAG,eAAe,GAC/D,OAAO,CAAC,wCAAwC,CAAC,CA0DnD;AAgCD,wBAAsB,iCAAiC,CACrD,KAAK,EAAE,sCAAsC,GAAG,eAAe,GAC9D,OAAO,CAAC,uCAAuC,CAAC,CA6ClD;AAED,wBAAsB,6CAA6C,CACjE,KAAK,EAAE,0CAA0C,GAAG,eAAe,GAClE,OAAO,CAAC,2CAA2C,CAAC,CA2DtD"}
|
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
import { once } from "node:events";
|
|
2
|
+
import { FieldPath, } from "firebase-admin/firestore";
|
|
3
|
+
import { Storage } from "@google-cloud/storage";
|
|
4
|
+
import readline from "node:readline";
|
|
5
|
+
import { Readable } from "node:stream";
|
|
6
|
+
import { deleteAllDocsInFirestoreCollection } from "./backup-data.js";
|
|
7
|
+
import { collectionRefFromSlashPath } from "../firebase/firestore-collection-path.js";
|
|
8
|
+
/** Default manifest object name under `gcsPrefix` for export-all / restore-all / compare-manifest. */
|
|
9
|
+
export const CATALOX_FIRESTORE_GCS_MANIFEST = "catalox-firestore-export-manifest.json";
|
|
10
|
+
export function normalizeGcsPrefix(prefix) {
|
|
11
|
+
const p = (prefix ?? "").trim();
|
|
12
|
+
if (!p)
|
|
13
|
+
return "";
|
|
14
|
+
return p.endsWith("/") ? p : `${p}/`;
|
|
15
|
+
}
|
|
16
|
+
/** Map `apps` or `a/b/c` → safe single-segment base for object names. */
|
|
17
|
+
export function firestoreCollectionPathToObjectBase(collectionPath) {
|
|
18
|
+
return collectionPath
|
|
19
|
+
.split("/")
|
|
20
|
+
.filter(Boolean)
|
|
21
|
+
.join("__")
|
|
22
|
+
.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
23
|
+
}
|
|
24
|
+
export function ndjsonObjectPath(params) {
|
|
25
|
+
const base = firestoreCollectionPathToObjectBase(params.collectionPath);
|
|
26
|
+
const sfx = params.objectNamePostfix != null && params.objectNamePostfix !== "" ? params.objectNamePostfix : "";
|
|
27
|
+
return `${params.gcsPrefix}${base}${sfx}.ndjson`;
|
|
28
|
+
}
|
|
29
|
+
function getBucket(input) {
|
|
30
|
+
const storage = input.storage ?? new Storage();
|
|
31
|
+
return storage.bucket(input.bucket);
|
|
32
|
+
}
|
|
33
|
+
/** @deprecated Use the same implementation as {@link collectionRefFromSlashPath} (re-exported for compatibility). */
|
|
34
|
+
export const collectionRefFromPath = collectionRefFromSlashPath;
|
|
35
|
+
async function* ndjsonLinesForCollection(col) {
|
|
36
|
+
let last;
|
|
37
|
+
while (true) {
|
|
38
|
+
let q = col.orderBy(FieldPath.documentId()).limit(400);
|
|
39
|
+
if (last)
|
|
40
|
+
q = q.startAfter(last);
|
|
41
|
+
const snap = await q.get();
|
|
42
|
+
if (snap.empty)
|
|
43
|
+
break;
|
|
44
|
+
for (const d of snap.docs) {
|
|
45
|
+
yield JSON.stringify({ id: d.id, data: d.data() });
|
|
46
|
+
}
|
|
47
|
+
last = snap.docs[snap.docs.length - 1];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function uploadNdjsonFromCollection(file, col) {
|
|
51
|
+
const ws = file.createWriteStream({
|
|
52
|
+
contentType: "application/x-ndjson",
|
|
53
|
+
resumable: false,
|
|
54
|
+
});
|
|
55
|
+
let count = 0;
|
|
56
|
+
await new Promise((resolve, reject) => {
|
|
57
|
+
ws.on("error", reject);
|
|
58
|
+
ws.on("finish", resolve);
|
|
59
|
+
(async () => {
|
|
60
|
+
try {
|
|
61
|
+
for await (const line of ndjsonLinesForCollection(col)) {
|
|
62
|
+
count += 1;
|
|
63
|
+
const chunk = `${line}\n`;
|
|
64
|
+
if (!ws.write(chunk))
|
|
65
|
+
await once(ws, "drain");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
catch (e) {
|
|
69
|
+
reject(e);
|
|
70
|
+
}
|
|
71
|
+
finally {
|
|
72
|
+
ws.end();
|
|
73
|
+
}
|
|
74
|
+
})().catch(reject);
|
|
75
|
+
});
|
|
76
|
+
return count;
|
|
77
|
+
}
|
|
78
|
+
async function discoverCollectionsForExport(fs, recursive) {
|
|
79
|
+
const roots = await fs.listCollections();
|
|
80
|
+
if (!recursive)
|
|
81
|
+
return roots;
|
|
82
|
+
const out = [];
|
|
83
|
+
const seen = new Set();
|
|
84
|
+
const queue = [...roots];
|
|
85
|
+
while (queue.length) {
|
|
86
|
+
const col = queue.shift();
|
|
87
|
+
if (seen.has(col.path))
|
|
88
|
+
continue;
|
|
89
|
+
seen.add(col.path);
|
|
90
|
+
out.push(col);
|
|
91
|
+
let lastDoc;
|
|
92
|
+
while (true) {
|
|
93
|
+
let q = col.orderBy(FieldPath.documentId()).limit(200);
|
|
94
|
+
if (lastDoc)
|
|
95
|
+
q = q.startAfter(lastDoc);
|
|
96
|
+
const snap = await q.get();
|
|
97
|
+
if (snap.empty)
|
|
98
|
+
break;
|
|
99
|
+
for (const d of snap.docs) {
|
|
100
|
+
const subs = await d.ref.listCollections();
|
|
101
|
+
for (const s of subs) {
|
|
102
|
+
if (!seen.has(s.path))
|
|
103
|
+
queue.push(s);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
lastDoc = snap.docs[snap.docs.length - 1];
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
export async function exportFirestoreCollectionToGcs(input) {
|
|
112
|
+
const issues = [];
|
|
113
|
+
const prefix = normalizeGcsPrefix(input.gcsPrefix);
|
|
114
|
+
try {
|
|
115
|
+
const col = collectionRefFromPath(input.firestore, input.collectionPath);
|
|
116
|
+
const objectPath = ndjsonObjectPath({
|
|
117
|
+
gcsPrefix: prefix,
|
|
118
|
+
collectionPath: input.collectionPath,
|
|
119
|
+
...(input.objectNamePostfix != null && input.objectNamePostfix !== ""
|
|
120
|
+
? { objectNamePostfix: input.objectNamePostfix }
|
|
121
|
+
: {}),
|
|
122
|
+
});
|
|
123
|
+
const bucket = getBucket(input);
|
|
124
|
+
const file = bucket.file(objectPath);
|
|
125
|
+
const count = await uploadNdjsonFromCollection(file, col);
|
|
126
|
+
return { ok: true, bucket: input.bucket, objectPath, documentCount: count, issues };
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
issues.push({
|
|
130
|
+
code: "export_failed",
|
|
131
|
+
message: e instanceof Error ? e.message : String(e),
|
|
132
|
+
detail: { collectionPath: input.collectionPath },
|
|
133
|
+
});
|
|
134
|
+
return { ok: false, bucket: input.bucket, objectPath: "", documentCount: 0, issues };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
export async function exportAllFirestoreCollectionsToGcs(input) {
|
|
138
|
+
const issues = [];
|
|
139
|
+
const prefix = normalizeGcsPrefix(input.gcsPrefix);
|
|
140
|
+
const recursive = Boolean(input.recursive);
|
|
141
|
+
const bucket = getBucket(input);
|
|
142
|
+
const entries = [];
|
|
143
|
+
try {
|
|
144
|
+
const cols = await discoverCollectionsForExport(input.firestore, recursive);
|
|
145
|
+
for (const col of cols) {
|
|
146
|
+
const collectionPath = col.path;
|
|
147
|
+
const objectPath = ndjsonObjectPath({
|
|
148
|
+
gcsPrefix: prefix,
|
|
149
|
+
collectionPath,
|
|
150
|
+
...(input.objectNamePostfix != null && input.objectNamePostfix !== ""
|
|
151
|
+
? { objectNamePostfix: input.objectNamePostfix }
|
|
152
|
+
: {}),
|
|
153
|
+
});
|
|
154
|
+
try {
|
|
155
|
+
const file = bucket.file(objectPath);
|
|
156
|
+
const count = await uploadNdjsonFromCollection(file, col);
|
|
157
|
+
entries.push({ firestorePath: collectionPath, objectPath, documentCount: count });
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
issues.push({
|
|
161
|
+
code: "export_collection_failed",
|
|
162
|
+
message: e instanceof Error ? e.message : String(e),
|
|
163
|
+
detail: { firestorePath: collectionPath },
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
const manifestObjectPath = `${prefix}${CATALOX_FIRESTORE_GCS_MANIFEST}`;
|
|
168
|
+
const manifest = {
|
|
169
|
+
catalog: "catalox-firestore-gcs-export",
|
|
170
|
+
version: 1,
|
|
171
|
+
exportedAt: new Date().toISOString(),
|
|
172
|
+
gcsPrefix: prefix,
|
|
173
|
+
objectNamePostfix: input.objectNamePostfix ?? "",
|
|
174
|
+
entries: entries.map((e) => ({
|
|
175
|
+
firestorePath: e.firestorePath,
|
|
176
|
+
objectPath: e.objectPath,
|
|
177
|
+
documentCount: e.documentCount,
|
|
178
|
+
})),
|
|
179
|
+
};
|
|
180
|
+
await bucket.file(manifestObjectPath).save(JSON.stringify(manifest, null, 2), {
|
|
181
|
+
contentType: "application/json",
|
|
182
|
+
resumable: false,
|
|
183
|
+
});
|
|
184
|
+
const ok = issues.length === 0;
|
|
185
|
+
return { ok, bucket: input.bucket, manifestObjectPath, entries, issues };
|
|
186
|
+
}
|
|
187
|
+
catch (e) {
|
|
188
|
+
issues.push({
|
|
189
|
+
code: "export_all_failed",
|
|
190
|
+
message: e instanceof Error ? e.message : String(e),
|
|
191
|
+
});
|
|
192
|
+
return { ok: false, bucket: input.bucket, manifestObjectPath: `${prefix}${CATALOX_FIRESTORE_GCS_MANIFEST}`, entries, issues };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
async function restoreNdjsonStreamToCollection(fs, col, stream) {
|
|
196
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
197
|
+
let batch = fs.batch();
|
|
198
|
+
let n = 0;
|
|
199
|
+
let inBatch = 0;
|
|
200
|
+
const flush = async () => {
|
|
201
|
+
if (inBatch === 0)
|
|
202
|
+
return;
|
|
203
|
+
await batch.commit();
|
|
204
|
+
batch = fs.batch();
|
|
205
|
+
inBatch = 0;
|
|
206
|
+
};
|
|
207
|
+
for await (const line of rl) {
|
|
208
|
+
const trimmed = line.trim();
|
|
209
|
+
if (!trimmed)
|
|
210
|
+
continue;
|
|
211
|
+
const row = JSON.parse(trimmed);
|
|
212
|
+
if (row.id == null || row.data == null)
|
|
213
|
+
throw new Error("Invalid NDJSON row: expected { id, data }");
|
|
214
|
+
batch.set(col.doc(String(row.id)), row.data, { merge: false });
|
|
215
|
+
n += 1;
|
|
216
|
+
inBatch += 1;
|
|
217
|
+
if (inBatch >= 450)
|
|
218
|
+
await flush();
|
|
219
|
+
}
|
|
220
|
+
await flush();
|
|
221
|
+
return n;
|
|
222
|
+
}
|
|
223
|
+
export async function restoreFirestoreCollectionFromGcs(input) {
|
|
224
|
+
const issues = [];
|
|
225
|
+
try {
|
|
226
|
+
const col = collectionRefFromPath(input.firestore, input.collectionPath);
|
|
227
|
+
if (input.replaceDestinationCollection) {
|
|
228
|
+
await deleteAllDocsInFirestoreCollection(input.firestore, col.path);
|
|
229
|
+
}
|
|
230
|
+
const bucket = getBucket(input);
|
|
231
|
+
const [exists] = await bucket.file(input.objectPath).exists();
|
|
232
|
+
if (!exists) {
|
|
233
|
+
issues.push({ code: "object_not_found", message: `GCS object not found: ${input.objectPath}` });
|
|
234
|
+
return {
|
|
235
|
+
ok: false,
|
|
236
|
+
bucket: input.bucket,
|
|
237
|
+
objectPath: input.objectPath,
|
|
238
|
+
collectionPath: input.collectionPath,
|
|
239
|
+
documentsWritten: 0,
|
|
240
|
+
issues,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
const rs = bucket.file(input.objectPath).createReadStream();
|
|
244
|
+
const written = await restoreNdjsonStreamToCollection(input.firestore, col, rs);
|
|
245
|
+
return {
|
|
246
|
+
ok: true,
|
|
247
|
+
bucket: input.bucket,
|
|
248
|
+
objectPath: input.objectPath,
|
|
249
|
+
collectionPath: input.collectionPath,
|
|
250
|
+
documentsWritten: written,
|
|
251
|
+
issues,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
catch (e) {
|
|
255
|
+
issues.push({
|
|
256
|
+
code: "restore_failed",
|
|
257
|
+
message: e instanceof Error ? e.message : String(e),
|
|
258
|
+
detail: { objectPath: input.objectPath, collectionPath: input.collectionPath },
|
|
259
|
+
});
|
|
260
|
+
return {
|
|
261
|
+
ok: false,
|
|
262
|
+
bucket: input.bucket,
|
|
263
|
+
objectPath: input.objectPath,
|
|
264
|
+
collectionPath: input.collectionPath,
|
|
265
|
+
documentsWritten: 0,
|
|
266
|
+
issues,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
export async function restoreAllFirestoreCollectionsFromGcsManifest(input) {
|
|
271
|
+
const issues = [];
|
|
272
|
+
const prefix = normalizeGcsPrefix(input.gcsPrefix);
|
|
273
|
+
const manifestObjectPath = input.manifestObjectPath ?? `${prefix}${CATALOX_FIRESTORE_GCS_MANIFEST}`;
|
|
274
|
+
const restored = [];
|
|
275
|
+
try {
|
|
276
|
+
const bucket = getBucket(input);
|
|
277
|
+
const [exists] = await bucket.file(manifestObjectPath).exists();
|
|
278
|
+
if (!exists) {
|
|
279
|
+
issues.push({ code: "manifest_not_found", message: `GCS object not found: ${manifestObjectPath}` });
|
|
280
|
+
return { ok: false, bucket: input.bucket, manifestObjectPath, restored, issues };
|
|
281
|
+
}
|
|
282
|
+
const [buf] = await bucket.file(manifestObjectPath).download();
|
|
283
|
+
const manifest = JSON.parse(buf.toString("utf8"));
|
|
284
|
+
if (manifest.catalog !== "catalox-firestore-gcs-export" || manifest.version !== 1 || !Array.isArray(manifest.entries)) {
|
|
285
|
+
throw new Error("Unsupported manifest format (expected catalog catalox-firestore-gcs-export version 1)");
|
|
286
|
+
}
|
|
287
|
+
for (const ent of manifest.entries) {
|
|
288
|
+
try {
|
|
289
|
+
const col = collectionRefFromPath(input.firestore, ent.firestorePath);
|
|
290
|
+
if (input.replaceDestinationCollection) {
|
|
291
|
+
await deleteAllDocsInFirestoreCollection(input.firestore, col.path);
|
|
292
|
+
}
|
|
293
|
+
const [objExists] = await bucket.file(ent.objectPath).exists();
|
|
294
|
+
if (!objExists) {
|
|
295
|
+
issues.push({
|
|
296
|
+
code: "object_not_found",
|
|
297
|
+
message: `Missing NDJSON object: ${ent.objectPath}`,
|
|
298
|
+
detail: { firestorePath: ent.firestorePath },
|
|
299
|
+
});
|
|
300
|
+
continue;
|
|
301
|
+
}
|
|
302
|
+
const rs = bucket.file(ent.objectPath).createReadStream();
|
|
303
|
+
const documentsWritten = await restoreNdjsonStreamToCollection(input.firestore, col, rs);
|
|
304
|
+
restored.push({
|
|
305
|
+
firestorePath: ent.firestorePath,
|
|
306
|
+
objectPath: ent.objectPath,
|
|
307
|
+
documentsWritten,
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
catch (e) {
|
|
311
|
+
issues.push({
|
|
312
|
+
code: "restore_entry_failed",
|
|
313
|
+
message: e instanceof Error ? e.message : String(e),
|
|
314
|
+
detail: { firestorePath: ent.firestorePath, objectPath: ent.objectPath },
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
const ok = issues.length === 0;
|
|
319
|
+
return { ok, bucket: input.bucket, manifestObjectPath, restored, issues };
|
|
320
|
+
}
|
|
321
|
+
catch (e) {
|
|
322
|
+
issues.push({
|
|
323
|
+
code: "restore_all_failed",
|
|
324
|
+
message: e instanceof Error ? e.message : String(e),
|
|
325
|
+
});
|
|
326
|
+
return { ok: false, bucket: input.bucket, manifestObjectPath, restored, issues };
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
//# sourceMappingURL=firestore-gcs-transfer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"firestore-gcs-transfer.js","sourceRoot":"","sources":["../../../src/catalox/firestore-gcs-transfer.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./context.js";
|
|
2
2
|
export * from "./authorization.js";
|
|
3
3
|
export * from "./catalox.js";
|
|
4
|
-
export { runBackupData, formatBackupTimestamp, discoverNativeCatalogIds, BACKUP_METADATA_SOURCE_NAMES, type BackupDataDeps, pruneMongoBackupRuns, pruneFirebaseVersionedBackups, paginatedCopyFirestoreToFirestore, deleteAllDocsInFirestoreCollection, firebaseLatestName, firebaseVersionedName, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, } from "./backup-data.js";
|
|
4
|
+
export { runBackupData, formatBackupTimestamp, discoverNativeCatalogIds, BACKUP_METADATA_SOURCE_NAMES, type BackupDataDeps, pruneMongoBackupRuns, pruneFirebaseVersionedBackups, gcsBackupRunFolder, paginatedCopyFirestoreToFirestore, deleteAllDocsInFirestoreCollection, firebaseLatestName, firebaseVersionedName, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, } from "./backup-data.js";
|
|
5
5
|
export { runRestoreFirestoreBackup, runUndoFirestoreRestore, type RestoreFirestoreDeps } from "./restore-firestore-backup.js";
|
|
6
|
+
export { exportFirestoreCollectionToGcs, exportAllFirestoreCollectionsToGcs, restoreFirestoreCollectionFromGcs, restoreAllFirestoreCollectionsFromGcsManifest, CATALOX_FIRESTORE_GCS_MANIFEST, normalizeGcsPrefix, firestoreCollectionPathToObjectBase, ndjsonObjectPath, collectionRefFromPath, } from "./firestore-gcs-transfer.js";
|
|
7
|
+
export { compareFirestoreCollectionWithGcsNdjson, compareAllFirestoreCollectionsWithGcsManifest, normalizeForCompare, dataFingerprint, } from "./firestore-gcs-compare.js";
|
|
6
8
|
export { reportNativeCatalogLayoutDiagnostics, nativeCatalogFirestorePaths, type NativeCatalogLayoutDiagnosticRow, } from "./native-catalog-layout-diagnostics.js";
|
|
7
9
|
export * from "./identity.js";
|
|
8
10
|
export * from "./json-io.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/catalox/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,KAAK,cAAc,EACnB,oBAAoB,EACpB,6BAA6B,EAC7B,iCAAiC,EACjC,kCAAkC,EAClC,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC9H,OAAO,EACL,oCAAoC,EACpC,2BAA2B,EAC3B,KAAK,gCAAgC,GACtC,MAAM,wCAAwC,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/catalox/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAC5B,KAAK,cAAc,EACnB,oBAAoB,EACpB,6BAA6B,EAC7B,kBAAkB,EAClB,iCAAiC,EACjC,kCAAkC,EAClC,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAAE,KAAK,oBAAoB,EAAE,MAAM,+BAA+B,CAAC;AAC9H,OAAO,EACL,8BAA8B,EAC9B,kCAAkC,EAClC,iCAAiC,EACjC,6CAA6C,EAC7C,8BAA8B,EAC9B,kBAAkB,EAClB,mCAAmC,EACnC,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,uCAAuC,EACvC,6CAA6C,EAC7C,mBAAmB,EACnB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,oCAAoC,EACpC,2BAA2B,EAC3B,KAAK,gCAAgC,GACtC,MAAM,wCAAwC,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export * from "./context.js";
|
|
2
2
|
export * from "./authorization.js";
|
|
3
3
|
export * from "./catalox.js";
|
|
4
|
-
export { runBackupData, formatBackupTimestamp, discoverNativeCatalogIds, BACKUP_METADATA_SOURCE_NAMES, pruneMongoBackupRuns, pruneFirebaseVersionedBackups, paginatedCopyFirestoreToFirestore, deleteAllDocsInFirestoreCollection, firebaseLatestName, firebaseVersionedName, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, } from "./backup-data.js";
|
|
4
|
+
export { runBackupData, formatBackupTimestamp, discoverNativeCatalogIds, BACKUP_METADATA_SOURCE_NAMES, pruneMongoBackupRuns, pruneFirebaseVersionedBackups, gcsBackupRunFolder, paginatedCopyFirestoreToFirestore, deleteAllDocsInFirestoreCollection, firebaseLatestName, firebaseVersionedName, firebaseNativeLogical, firebaseSnapshotLogical, firebaseSnapshotRunLogical, } from "./backup-data.js";
|
|
5
5
|
export { runRestoreFirestoreBackup, runUndoFirestoreRestore } from "./restore-firestore-backup.js";
|
|
6
|
+
export { exportFirestoreCollectionToGcs, exportAllFirestoreCollectionsToGcs, restoreFirestoreCollectionFromGcs, restoreAllFirestoreCollectionsFromGcsManifest, CATALOX_FIRESTORE_GCS_MANIFEST, normalizeGcsPrefix, firestoreCollectionPathToObjectBase, ndjsonObjectPath, collectionRefFromPath, } from "./firestore-gcs-transfer.js";
|
|
7
|
+
export { compareFirestoreCollectionWithGcsNdjson, compareAllFirestoreCollectionsWithGcsManifest, normalizeForCompare, dataFingerprint, } from "./firestore-gcs-compare.js";
|
|
6
8
|
export { reportNativeCatalogLayoutDiagnostics, nativeCatalogFirestorePaths, } from "./native-catalog-layout-diagnostics.js";
|
|
7
9
|
export * from "./identity.js";
|
|
8
10
|
export * from "./json-io.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/catalox/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAE5B,oBAAoB,EACpB,6BAA6B,EAC7B,iCAAiC,EACjC,kCAAkC,EAClC,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAA6B,MAAM,+BAA+B,CAAC;AAC9H,OAAO,EACL,oCAAoC,EACpC,2BAA2B,GAE5B,MAAM,wCAAwC,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/catalox/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,qBAAqB,EACrB,wBAAwB,EACxB,4BAA4B,EAE5B,oBAAoB,EACpB,6BAA6B,EAC7B,kBAAkB,EAClB,iCAAiC,EACjC,kCAAkC,EAClC,kBAAkB,EAClB,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,0BAA0B,GAC3B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,yBAAyB,EAAE,uBAAuB,EAA6B,MAAM,+BAA+B,CAAC;AAC9H,OAAO,EACL,8BAA8B,EAC9B,kCAAkC,EAClC,iCAAiC,EACjC,6CAA6C,EAC7C,8BAA8B,EAC9B,kBAAkB,EAClB,mCAAmC,EACnC,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,uCAAuC,EACvC,6CAA6C,EAC7C,mBAAmB,EACnB,eAAe,GAChB,MAAM,4BAA4B,CAAC;AACpC,OAAO,EACL,oCAAoC,EACpC,2BAA2B,GAE5B,MAAM,wCAAwC,CAAC;AAChD,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC"}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -7,7 +7,7 @@ import { getFirestore } from "firebase-admin/firestore";
|
|
|
7
7
|
import { createRequire } from "node:module";
|
|
8
8
|
import { readFileSync } from "node:fs";
|
|
9
9
|
import { resolve as resolvePath } from "node:path";
|
|
10
|
-
import { ApiCatalogAdapter, AuthorizationService, BindingStore, CatalogStore, Catalox, DefinitionStore, DescriptorStore, FirestoreStore, MappingStore, NativeItemStore, ReferenceStore, SnapshotStore, StoreAppBindingStore, } from "../index.js";
|
|
10
|
+
import { ApiCatalogAdapter, AuthorizationService, BindingStore, CatalogStore, Catalox, DefinitionStore, DescriptorStore, FirestoreStore, MappingStore, NativeItemStore, ReferenceStore, SnapshotStore, StoreAppBindingStore, normalizeGcsPrefix, ndjsonObjectPath, } from "../index.js";
|
|
11
11
|
import { AdapterStore } from "../firebase/adapter-store.js";
|
|
12
12
|
import { AppStore } from "../firebase/app-store.js";
|
|
13
13
|
import { CatalogDataIndexStore } from "../firebase/catalog-data-index-store.js";
|
|
@@ -296,21 +296,37 @@ const firestoreCmd = program
|
|
|
296
296
|
.description("Firestore backup, restore (Firebase mirrors), and native layout migration");
|
|
297
297
|
firestoreCmd
|
|
298
298
|
.command("backup")
|
|
299
|
-
.description("Generic Catalox backup to Mongo (catalox-backups)
|
|
299
|
+
.description("Generic Catalox backup to Mongo (catalox-backups), Firebase (backup-* collections), or GCS (NDJSON via @x12i/helpers/gcs)")
|
|
300
300
|
.requiredOption("--app <appId>", "AppId for Catalox context")
|
|
301
|
-
.requiredOption("--mode <mongo|firebase>", "Backup target")
|
|
301
|
+
.requiredOption("--mode <mongo|firebase|gcs>", "Backup target")
|
|
302
302
|
.option("--mongo-uri <uri>", "Mongo connection string (required when mode=mongo)")
|
|
303
|
+
.option("--bucket <name>", "GCS bucket name (required when mode=gcs)")
|
|
304
|
+
.option("--gcs-prefix <path>", "Optional prefix before timestamp folder (default: catalox-firestore-backups/)", "")
|
|
303
305
|
.option("--label <text>", "Backup label stored on manifest")
|
|
304
306
|
.option("--snapshots", "Include catalogSnapshots data", false)
|
|
305
307
|
.option("--catalog <catalogId...>", "Restrict which native catalogs are copied")
|
|
306
308
|
.option("--god", "God mode", false)
|
|
307
309
|
.action(async (opts) => {
|
|
310
|
+
const m = String(opts.mode).toLowerCase();
|
|
311
|
+
const mode = m === "mongo" ? "mongo" : m === "gcs" ? "gcs" : "firebase";
|
|
312
|
+
if (mode === "gcs" && !(opts.bucket != null && String(opts.bucket).trim())) {
|
|
313
|
+
// eslint-disable-next-line no-console
|
|
314
|
+
console.error("--bucket is required when --mode gcs");
|
|
315
|
+
process.exitCode = 1;
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
308
318
|
const catalox = createCatalox();
|
|
309
319
|
const ctx = baseContext({ app: opts.app, god: opts.god });
|
|
310
|
-
const
|
|
320
|
+
const gcsPrefixOpt = opts.gcsPrefix != null && String(opts.gcsPrefix).trim() ? String(opts.gcsPrefix).trim() : undefined;
|
|
311
321
|
const res = await catalox.backupData(ctx, {
|
|
312
322
|
mode,
|
|
313
323
|
mongoBackupUri: opts.mongoUri,
|
|
324
|
+
...(mode === "gcs"
|
|
325
|
+
? {
|
|
326
|
+
gcsBucket: String(opts.bucket).trim(),
|
|
327
|
+
...(gcsPrefixOpt !== undefined ? { gcsPrefix: gcsPrefixOpt } : {}),
|
|
328
|
+
}
|
|
329
|
+
: {}),
|
|
314
330
|
includeSnapshots: Boolean(opts.snapshots),
|
|
315
331
|
...(opts.catalog?.length ? { catalogIds: opts.catalog } : {}),
|
|
316
332
|
...(opts.label != null && String(opts.label) !== "" ? { backupLabel: String(opts.label) } : {}),
|
|
@@ -430,6 +446,174 @@ firestoreCmd
|
|
|
430
446
|
if (!m.ok)
|
|
431
447
|
process.exitCode = 1;
|
|
432
448
|
});
|
|
449
|
+
firestoreCmd
|
|
450
|
+
.command("export-gcs")
|
|
451
|
+
.description("Export Firestore collection(s) to a GCS bucket as NDJSON + manifest (for --all). Uses Application Default Credentials for GCS.")
|
|
452
|
+
.requiredOption("--app <appId>", "AppId for Catalox context")
|
|
453
|
+
.requiredOption("--bucket <name>", "GCS bucket name")
|
|
454
|
+
.option("--prefix <path>", "Object key prefix inside the bucket", "")
|
|
455
|
+
.option("--postfix <suffix>", "Optional suffix before .ndjson in each object name", "")
|
|
456
|
+
.option("--path <collectionPath>", "Single collection path (e.g. apps or catalogData/myId/items)")
|
|
457
|
+
.option("--all", "Export every root collection; writes catalox-firestore-export-manifest.json", false)
|
|
458
|
+
.option("--recursive", "With --all: include all document subcollections (expensive)", false)
|
|
459
|
+
.option("--god", "God mode", false)
|
|
460
|
+
.action(async (opts) => {
|
|
461
|
+
const hasPath = Boolean(opts.path && String(opts.path).trim());
|
|
462
|
+
const all = Boolean(opts.all);
|
|
463
|
+
if (hasPath === all) {
|
|
464
|
+
// eslint-disable-next-line no-console
|
|
465
|
+
console.error("Specify exactly one of: --path <collectionPath> OR --all");
|
|
466
|
+
process.exitCode = 1;
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
469
|
+
const catalox = createCatalox();
|
|
470
|
+
const ctx = baseContext({ app: opts.app, god: opts.god });
|
|
471
|
+
const bucket = String(opts.bucket);
|
|
472
|
+
const gcsPrefix = String(opts.prefix ?? "");
|
|
473
|
+
const objectNamePostfix = opts.postfix != null ? String(opts.postfix) : undefined;
|
|
474
|
+
if (hasPath) {
|
|
475
|
+
const res = await catalox.exportFirestoreCollectionToGcs(ctx, {
|
|
476
|
+
bucket,
|
|
477
|
+
gcsPrefix,
|
|
478
|
+
...(objectNamePostfix !== undefined && objectNamePostfix !== "" ? { objectNamePostfix } : {}),
|
|
479
|
+
collectionPath: String(opts.path).trim(),
|
|
480
|
+
});
|
|
481
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
482
|
+
if (!res.ok)
|
|
483
|
+
process.exitCode = 1;
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const res = await catalox.exportAllFirestoreCollectionsToGcs(ctx, {
|
|
487
|
+
bucket,
|
|
488
|
+
gcsPrefix,
|
|
489
|
+
...(objectNamePostfix !== undefined && objectNamePostfix !== "" ? { objectNamePostfix } : {}),
|
|
490
|
+
recursive: Boolean(opts.recursive),
|
|
491
|
+
});
|
|
492
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
493
|
+
if (!res.ok)
|
|
494
|
+
process.exitCode = 1;
|
|
495
|
+
});
|
|
496
|
+
firestoreCmd
|
|
497
|
+
.command("import-gcs")
|
|
498
|
+
.description("Restore Firestore from GCS NDJSON produced by export-gcs (single collection or manifest for all). Uses ADC for GCS.")
|
|
499
|
+
.requiredOption("--app <appId>", "AppId for Catalox context")
|
|
500
|
+
.requiredOption("--bucket <name>", "GCS bucket name")
|
|
501
|
+
.option("--prefix <path>", "Object key prefix (must match export)", "")
|
|
502
|
+
.option("--postfix <suffix>", "Suffix used at export time", "")
|
|
503
|
+
.option("--path <collectionPath>", "Target Firestore collection path for single-file restore")
|
|
504
|
+
.option("--object <objectPath>", "Full GCS object path within bucket (overrides prefix/path/postfix inference)")
|
|
505
|
+
.option("--manifest <objectPath>", "Restore all entries from this manifest object path in the bucket")
|
|
506
|
+
.option("--restore-all", "Restore all entries using default manifest name under --prefix (same as export --all)", false)
|
|
507
|
+
.option("--replace", "Delete each destination collection before writing", false)
|
|
508
|
+
.option("--god", "God mode", false)
|
|
509
|
+
.action(async (opts) => {
|
|
510
|
+
const catalox = createCatalox();
|
|
511
|
+
const ctx = baseContext({ app: opts.app, god: opts.god });
|
|
512
|
+
const bucket = String(opts.bucket);
|
|
513
|
+
const gcsPrefix = String(opts.prefix ?? "");
|
|
514
|
+
const postfix = opts.postfix != null ? String(opts.postfix) : undefined;
|
|
515
|
+
const replace = Boolean(opts.replace);
|
|
516
|
+
const manifestPath = opts.manifest != null && String(opts.manifest).trim() ? String(opts.manifest).trim() : "";
|
|
517
|
+
const restoreAll = Boolean(opts.restoreAll);
|
|
518
|
+
if (manifestPath || restoreAll) {
|
|
519
|
+
const res = await catalox.restoreAllFirestoreCollectionsFromGcsManifest(ctx, {
|
|
520
|
+
bucket,
|
|
521
|
+
gcsPrefix,
|
|
522
|
+
...(postfix !== undefined && postfix !== "" ? { objectNamePostfix: postfix } : {}),
|
|
523
|
+
...(manifestPath ? { manifestObjectPath: manifestPath } : {}),
|
|
524
|
+
replaceDestinationCollection: replace,
|
|
525
|
+
});
|
|
526
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
527
|
+
if (!res.ok)
|
|
528
|
+
process.exitCode = 1;
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
const collectionPath = opts.path != null && String(opts.path).trim() ? String(opts.path).trim() : "";
|
|
532
|
+
if (!collectionPath) {
|
|
533
|
+
// eslint-disable-next-line no-console
|
|
534
|
+
console.error("For single-collection restore, pass --path (and optionally --object), or use --manifest / --restore-all");
|
|
535
|
+
process.exitCode = 1;
|
|
536
|
+
return;
|
|
537
|
+
}
|
|
538
|
+
const explicitObject = opts.object != null && String(opts.object).trim() ? String(opts.object).trim() : "";
|
|
539
|
+
const objectPath = explicitObject ||
|
|
540
|
+
ndjsonObjectPath({
|
|
541
|
+
gcsPrefix: normalizeGcsPrefix(gcsPrefix),
|
|
542
|
+
collectionPath,
|
|
543
|
+
...(postfix != null && postfix !== "" ? { objectNamePostfix: postfix } : {}),
|
|
544
|
+
});
|
|
545
|
+
const res = await catalox.restoreFirestoreCollectionFromGcs(ctx, {
|
|
546
|
+
bucket,
|
|
547
|
+
gcsPrefix,
|
|
548
|
+
...(postfix !== undefined && postfix !== "" ? { objectNamePostfix: postfix } : {}),
|
|
549
|
+
collectionPath,
|
|
550
|
+
objectPath,
|
|
551
|
+
replaceDestinationCollection: replace,
|
|
552
|
+
});
|
|
553
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
554
|
+
if (!res.ok)
|
|
555
|
+
process.exitCode = 1;
|
|
556
|
+
});
|
|
557
|
+
firestoreCmd
|
|
558
|
+
.command("compare-gcs")
|
|
559
|
+
.description("Compare live Firestore to NDJSON in GCS: identical, changed, only-in-Firestore, only-in-bucket (see docs/firestore-gcs-export.md)")
|
|
560
|
+
.requiredOption("--app <appId>", "AppId for Catalox context")
|
|
561
|
+
.requiredOption("--bucket <name>", "GCS bucket name")
|
|
562
|
+
.option("--prefix <path>", "Object key prefix (must match export)", "")
|
|
563
|
+
.option("--postfix <suffix>", "Suffix used at export time (single-collection mode)", "")
|
|
564
|
+
.option("--path <collectionPath>", "Firestore collection path for single-object compare")
|
|
565
|
+
.option("--object <objectPath>", "Full GCS object path (overrides prefix/path/postfix inference)")
|
|
566
|
+
.option("--manifest <objectPath>", "Compare all entries from this manifest object path")
|
|
567
|
+
.option("--restore-all", "Compare all entries using default manifest name under --prefix (same as export --all)", false)
|
|
568
|
+
.option("--max-ids <n>", "Max document ids listed per category (counts are always full)", "500")
|
|
569
|
+
.option("--god", "God mode", false)
|
|
570
|
+
.action(async (opts) => {
|
|
571
|
+
const catalox = createCatalox();
|
|
572
|
+
const ctx = baseContext({ app: opts.app, god: opts.god });
|
|
573
|
+
const bucket = String(opts.bucket);
|
|
574
|
+
const gcsPrefix = String(opts.prefix ?? "");
|
|
575
|
+
const postfix = opts.postfix != null ? String(opts.postfix) : undefined;
|
|
576
|
+
const maxIds = Math.max(0, Number.parseInt(String(opts.maxIds ?? "500"), 10) || 0);
|
|
577
|
+
const manifestPath = opts.manifest != null && String(opts.manifest).trim() ? String(opts.manifest).trim() : "";
|
|
578
|
+
const restoreAll = Boolean(opts.restoreAll);
|
|
579
|
+
if (manifestPath || restoreAll) {
|
|
580
|
+
const res = await catalox.compareAllFirestoreCollectionsWithGcsManifest(ctx, {
|
|
581
|
+
bucket,
|
|
582
|
+
gcsPrefix,
|
|
583
|
+
...(manifestPath ? { manifestObjectPath: manifestPath } : {}),
|
|
584
|
+
maxListedIdsPerCategory: maxIds,
|
|
585
|
+
});
|
|
586
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
587
|
+
if (!res.ok)
|
|
588
|
+
process.exitCode = 1;
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
const collectionPath = opts.path != null && String(opts.path).trim() ? String(opts.path).trim() : "";
|
|
592
|
+
if (!collectionPath) {
|
|
593
|
+
// eslint-disable-next-line no-console
|
|
594
|
+
console.error("Pass --path for single-collection compare, or --manifest / --restore-all for manifest-driven compare");
|
|
595
|
+
process.exitCode = 1;
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const explicitObject = opts.object != null && String(opts.object).trim() ? String(opts.object).trim() : "";
|
|
599
|
+
const objectPath = explicitObject ||
|
|
600
|
+
ndjsonObjectPath({
|
|
601
|
+
gcsPrefix: normalizeGcsPrefix(gcsPrefix),
|
|
602
|
+
collectionPath,
|
|
603
|
+
...(postfix != null && postfix !== "" ? { objectNamePostfix: postfix } : {}),
|
|
604
|
+
});
|
|
605
|
+
const res = await catalox.compareFirestoreCollectionWithGcsNdjson(ctx, {
|
|
606
|
+
bucket,
|
|
607
|
+
gcsPrefix,
|
|
608
|
+
...(postfix != null && postfix !== "" ? { objectNamePostfix: postfix } : {}),
|
|
609
|
+
collectionPath,
|
|
610
|
+
objectPath,
|
|
611
|
+
maxListedIdsPerCategory: maxIds,
|
|
612
|
+
});
|
|
613
|
+
await writeOrStdout(JSON.stringify(res, null, 2));
|
|
614
|
+
if (!res.ok)
|
|
615
|
+
process.exitCode = 1;
|
|
616
|
+
});
|
|
433
617
|
program.parseAsync(process.argv).catch((err) => {
|
|
434
618
|
// eslint-disable-next-line no-console
|
|
435
619
|
console.error(err instanceof Error ? err.message : err);
|