@fazetitans/fscopy 1.2.0 → 1.2.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fazetitans/fscopy",
3
- "version": "1.2.0",
3
+ "version": "1.2.1",
4
4
  "description": "Fast CLI tool to copy Firestore collections between Firebase projects with filtering, parallel transfers, and subcollection support",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.ts CHANGED
@@ -6,6 +6,7 @@ process.env.METADATA_SERVER_DETECTION = 'none';
6
6
  import yargs from 'yargs';
7
7
  import { hideBin } from 'yargs/helpers';
8
8
 
9
+ import pkg from '../package.json';
9
10
  import type { Config, CliArgs } from './types.js';
10
11
  import { Output, parseSize } from './utils/output.js';
11
12
  import { ensureCredentials } from './utils/credentials.js';
@@ -24,6 +25,7 @@ import { runTransfer } from './orchestrator.js';
24
25
 
25
26
  const argv = yargs(hideBin(process.argv))
26
27
  .scriptName('fscopy')
28
+ .version(pkg.version)
27
29
  .usage('$0 [options]')
28
30
  .option('init', {
29
31
  type: 'string',
@@ -78,7 +78,7 @@ async function handleSuccessOutput(
78
78
  if (config.json) {
79
79
  output.json(JSON.parse(formatJsonOutput(true, config, stats, duration, undefined, verifyResult)));
80
80
  } else {
81
- printSummary(stats, duration.toFixed(2), argv.log, config.dryRun);
81
+ printSummary(stats, duration.toFixed(2), argv.log, config.dryRun, config.verifyIntegrity);
82
82
  }
83
83
 
84
84
  if (config.webhook) {
@@ -137,12 +137,13 @@ export async function runTransfer(config: Config, argv: CliArgs, output: Output)
137
137
  }
138
138
 
139
139
  const currentStats = config.resume ? stats : createEmptyStats();
140
- const { progressBar } = await setupProgressTracking(sourceDb, config, currentStats, output);
141
140
 
142
141
  if (config.clear) {
143
142
  await clearDestinationCollections(destDb, config, currentStats, output);
144
143
  }
145
144
 
145
+ const { progressBar } = await setupProgressTracking(sourceDb, config, currentStats, output);
146
+
146
147
  const rateLimiter = config.rateLimit > 0 ? new RateLimiter(config.rateLimit) : null;
147
148
  if (rateLimiter) {
148
149
  output.info(`⏱️ Rate limiting enabled: ${config.rateLimit} docs/s\n`);
@@ -159,7 +159,8 @@ export function printSummary(
159
159
  stats: Stats,
160
160
  duration: string,
161
161
  logFile?: string,
162
- dryRun?: boolean
162
+ dryRun?: boolean,
163
+ verifyIntegrity?: boolean
163
164
  ): void {
164
165
  console.log('\n' + '='.repeat(60));
165
166
  console.log('📊 TRANSFER SUMMARY');
@@ -172,8 +173,12 @@ export function printSummary(
172
173
  if (stats.conflicts > 0) {
173
174
  console.log(`Conflicts detected: ${stats.conflicts}`);
174
175
  }
175
- if (stats.integrityErrors > 0) {
176
- console.log(`Integrity errors: ${stats.integrityErrors}`);
176
+ if (verifyIntegrity) {
177
+ if (stats.integrityErrors > 0) {
178
+ console.log(`Integrity errors: ${stats.integrityErrors}`);
179
+ } else {
180
+ console.log(`Integrity verified: ✓ ${stats.documentsTransferred} documents`);
181
+ }
177
182
  }
178
183
  console.log(`Errors: ${stats.errors}`);
179
184
  console.log(`Duration: ${duration}s`);
@@ -31,6 +31,11 @@ async function countWithSubcollections(
31
31
  depth: number,
32
32
  progress?: CountProgress
33
33
  ): Promise<number> {
34
+ // Apply limit at root level only
35
+ if (depth === 0 && config.limit > 0) {
36
+ query = query.limit(config.limit);
37
+ }
38
+
34
39
  const snapshot = await query.select().get();
35
40
  let count = snapshot.size;
36
41
 
@@ -80,11 +85,17 @@ async function countSubcollectionsForDoc(
80
85
  async function countWithoutSubcollections(
81
86
  query: Query,
82
87
  collectionPath: string,
88
+ config: Config,
83
89
  depth: number,
84
90
  progress?: CountProgress
85
91
  ): Promise<number> {
86
92
  const countSnapshot = await query.count().get();
87
- const count = countSnapshot.data().count;
93
+ let count = countSnapshot.data().count;
94
+
95
+ // Apply limit at root level only
96
+ if (depth === 0 && config.limit > 0) {
97
+ count = Math.min(count, config.limit);
98
+ }
88
99
 
89
100
  if (depth === 0 && progress?.onCollection) {
90
101
  progress.onCollection(collectionPath, count);
@@ -106,5 +117,5 @@ export async function countDocuments(
106
117
  return countWithSubcollections(sourceDb, query, collectionPath, config, depth, progress);
107
118
  }
108
119
 
109
- return countWithoutSubcollections(query, collectionPath, depth, progress);
120
+ return countWithoutSubcollections(query, collectionPath, config, depth, progress);
110
121
  }