stripe-experiment-sync 1.0.18 → 1.0.20

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 CHANGED
@@ -202,6 +202,9 @@ Supported objects: `all`, `charge`, `checkout_sessions`, `credit_note`, `custome
202
202
 
203
203
  The sync engine tracks cursors per account and resource, enabling incremental syncing that resumes after interruptions.
204
204
 
205
+ For paged backfills, the engine keeps a separate per-run pagination cursor (`page_cursor`) while the
206
+ incremental cursor continues to track the highest `created` timestamp.
207
+
205
208
  > **Tip:** For large Stripe accounts (>10,000 objects), loop through date ranges day-by-day to avoid timeouts.
206
209
 
207
210
  ## Account Management
@@ -1,12 +1,13 @@
1
1
  import {
2
+ SIGMA_INGESTION_CONFIGS,
2
3
  StripeSync,
3
4
  createStripeWebSocketClient,
4
5
  runMigrations
5
- } from "./chunk-K4JQHI7Y.js";
6
+ } from "./chunk-HHDPFCIA.js";
6
7
  import {
7
8
  install,
8
9
  uninstall
9
- } from "./chunk-M5TTM27L.js";
10
+ } from "./chunk-UPJNFZXA.js";
10
11
 
11
12
  // src/cli/config.ts
12
13
  import dotenv from "dotenv";
@@ -129,22 +130,23 @@ var VALID_SYNC_OBJECTS = [
129
130
  "credit_note",
130
131
  "early_fraud_warning",
131
132
  "refund",
132
- "checkout_sessions",
133
- "subscription_item_change_events_v2_beta",
134
- "exchange_rates_from_usd"
133
+ "checkout_sessions"
135
134
  ];
136
135
  async function backfillCommand(options, entityName) {
137
136
  let stripeSync = null;
138
137
  try {
139
- if (!VALID_SYNC_OBJECTS.includes(entityName)) {
138
+ dotenv2.config();
139
+ const enableSigma = options.enableSigma ?? process.env.ENABLE_SIGMA === "true";
140
+ const sigmaTableNames = enableSigma ? Object.keys(SIGMA_INGESTION_CONFIGS) : [];
141
+ const validEntities = [...VALID_SYNC_OBJECTS, ...sigmaTableNames];
142
+ if (!validEntities.includes(entityName)) {
143
+ const entityList = enableSigma ? `${VALID_SYNC_OBJECTS.join(", ")}, and ${sigmaTableNames.length} sigma tables` : VALID_SYNC_OBJECTS.join(", ");
140
144
  console.error(
141
- chalk3.red(
142
- `Error: Invalid entity name "${entityName}". Valid entities are: ${VALID_SYNC_OBJECTS.join(", ")}`
143
- )
145
+ chalk3.red(`Error: Invalid entity name "${entityName}". Valid entities are: ${entityList}`)
144
146
  );
145
147
  process.exit(1);
146
148
  }
147
- dotenv2.config();
149
+ const isSigmaTable = sigmaTableNames.includes(entityName);
148
150
  let stripeApiKey = options.stripeKey || process.env.STRIPE_API_KEY || process.env.STRIPE_SECRET_KEY || "";
149
151
  let databaseUrl = options.databaseUrl || process.env.DATABASE_URL || "";
150
152
  if (!stripeApiKey || !databaseUrl) {
@@ -197,11 +199,13 @@ async function backfillCommand(options, entityName) {
197
199
  ngrokAuthToken: ""
198
200
  // Not needed for backfill
199
201
  };
200
- console.log(chalk3.blue(`Backfilling ${entityName} from Stripe in 'stripe' schema...`));
202
+ const schemaName = isSigmaTable ? "sigma" : "stripe";
203
+ console.log(chalk3.blue(`Backfilling ${entityName} from Stripe in '${schemaName}' schema...`));
201
204
  console.log(chalk3.gray(`Database: ${config.databaseUrl.replace(/:[^:@]+@/, ":****@")}`));
202
205
  try {
203
206
  await runMigrations({
204
- databaseUrl: config.databaseUrl
207
+ databaseUrl: config.databaseUrl,
208
+ enableSigma
205
209
  });
206
210
  } catch (migrationError) {
207
211
  console.error(chalk3.red("Failed to run migrations:"));
@@ -218,18 +222,49 @@ async function backfillCommand(options, entityName) {
218
222
  stripeSync = new StripeSync({
219
223
  databaseUrl: config.databaseUrl,
220
224
  stripeSecretKey: config.stripeApiKey,
221
- enableSigma: process.env.ENABLE_SIGMA === "true",
225
+ enableSigma,
222
226
  stripeApiVersion: process.env.STRIPE_API_VERSION || "2020-08-27",
223
227
  autoExpandLists: process.env.AUTO_EXPAND_LISTS === "true",
224
228
  backfillRelatedEntities: process.env.BACKFILL_RELATED_ENTITIES !== "false",
225
229
  poolConfig
226
230
  });
227
- const result = await stripeSync.processUntilDone({ object: entityName });
228
- const totalSynced = Object.values(result).reduce(
229
- (sum, syncResult) => sum + (syncResult?.synced || 0),
230
- 0
231
- );
232
- console.log(chalk3.green(`\u2713 Backfill complete: ${totalSynced} ${entityName} objects synced`));
231
+ if (entityName === "all") {
232
+ const backfill = await stripeSync.processUntilDoneParallel({
233
+ object: "all",
234
+ triggeredBy: "cli-backfill",
235
+ maxParallel: 10,
236
+ skipInaccessibleSigmaTables: true
237
+ });
238
+ const objectCount = Object.keys(backfill.totals).length;
239
+ console.log(
240
+ chalk3.green(
241
+ `\u2713 Backfill complete: ${backfill.totalSynced} rows synced across ${objectCount} objects`
242
+ )
243
+ );
244
+ if (backfill.skipped.length > 0) {
245
+ console.log(
246
+ chalk3.yellow(
247
+ `Skipped ${backfill.skipped.length} Sigma tables without access: ${backfill.skipped.join(", ")}`
248
+ )
249
+ );
250
+ }
251
+ if (backfill.errors.length > 0) {
252
+ console.log(chalk3.red(`Backfill finished with ${backfill.errors.length} errors:`));
253
+ for (const err of backfill.errors) {
254
+ console.log(chalk3.red(` - ${err.object}: ${err.message}`));
255
+ }
256
+ }
257
+ } else {
258
+ const result = await stripeSync.processUntilDone({ object: entityName });
259
+ const totalSynced = Object.values(result).reduce(
260
+ (sum, syncResult) => sum + (syncResult?.synced || 0),
261
+ 0
262
+ );
263
+ const tableType = isSigmaTable ? "(sigma)" : "";
264
+ console.log(
265
+ chalk3.green(`\u2713 Backfill complete: ${totalSynced} ${entityName} ${tableType} rows synced`)
266
+ );
267
+ }
233
268
  await stripeSync.close();
234
269
  } catch (error) {
235
270
  if (error instanceof Error) {
@@ -269,11 +304,16 @@ async function migrateCommand(options) {
269
304
  ]);
270
305
  databaseUrl = answers.databaseUrl;
271
306
  }
307
+ const enableSigma = options.enableSigma ?? process.env.ENABLE_SIGMA === "true";
272
308
  console.log(chalk3.blue("Running database migrations in 'stripe' schema..."));
273
309
  console.log(chalk3.gray(`Database: ${databaseUrl.replace(/:[^:@]+@/, ":****@")}`));
310
+ if (enableSigma) {
311
+ console.log(chalk3.blue("Sigma tables enabled"));
312
+ }
274
313
  try {
275
314
  await runMigrations({
276
- databaseUrl
315
+ databaseUrl,
316
+ enableSigma
277
317
  });
278
318
  console.log(chalk3.green("\u2713 Migrations completed successfully"));
279
319
  } catch (migrationError) {
@@ -365,7 +405,8 @@ Mode: ${modeLabel}`));
365
405
  console.log(chalk3.gray(`Database: ${maskedDbUrl}`));
366
406
  try {
367
407
  await runMigrations({
368
- databaseUrl: config.databaseUrl
408
+ databaseUrl: config.databaseUrl,
409
+ enableSigma: config.enableSigma
369
410
  });
370
411
  } catch (migrationError) {
371
412
  console.error(chalk3.red("Failed to run migrations:"));
@@ -473,13 +514,38 @@ Starting server on port ${port}...`));
473
514
  console.log(chalk3.green(`\u2713 Server started on port ${port}`));
474
515
  }
475
516
  if (process.env.SKIP_BACKFILL !== "true") {
476
- console.log(chalk3.blue("\nStarting initial sync of all Stripe data..."));
477
- const syncResult = await stripeSync.processUntilDone();
478
- const totalSynced = Object.values(syncResult).reduce(
479
- (sum, result) => sum + (result?.synced || 0),
480
- 0
517
+ if (!stripeSync) {
518
+ throw new Error("StripeSync not initialized.");
519
+ }
520
+ console.log(chalk3.blue("\nStarting historical backfill (parallel sweep)..."));
521
+ const backfill = await stripeSync.processUntilDoneParallel({
522
+ triggeredBy: "cli-historical-backfill",
523
+ maxParallel: 10,
524
+ skipInaccessibleSigmaTables: true
525
+ });
526
+ const objectCount = Object.keys(backfill.totals).length;
527
+ console.log(
528
+ chalk3.green(
529
+ `\u2713 Historical backfill complete: ${backfill.totalSynced} rows synced across ${objectCount} objects`
530
+ )
481
531
  );
482
- console.log(chalk3.green(`\u2713 Sync complete: ${totalSynced} objects synced`));
532
+ if (backfill.skipped.length > 0) {
533
+ console.log(
534
+ chalk3.yellow(
535
+ `Skipped ${backfill.skipped.length} Sigma tables without access: ${backfill.skipped.join(", ")}`
536
+ )
537
+ );
538
+ }
539
+ if (backfill.errors.length > 0) {
540
+ console.log(
541
+ chalk3.red(
542
+ `Historical backfill finished with ${backfill.errors.length} errors. See logs above.`
543
+ )
544
+ );
545
+ }
546
+ console.log(chalk3.blue("\nStarting incremental backfill..."));
547
+ await stripeSync.processUntilDone();
548
+ console.log(chalk3.green("\u2713 Incremental backfill complete"));
483
549
  } else {
484
550
  console.log(chalk3.yellow("\n\u23ED\uFE0F Skipping initial sync (SKIP_BACKFILL=true)"));
485
551
  }
@@ -553,7 +619,8 @@ async function installCommand(options) {
553
619
  stripeKey,
554
620
  packageVersion: options.packageVersion,
555
621
  workerIntervalSeconds: options.workerInterval,
556
- supabaseManagementUrl
622
+ supabaseManagementUrl,
623
+ enableSigma: options.enableSigma
557
624
  });
558
625
  console.log(chalk3.cyan("\n\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501\u2501"));
559
626
  console.log(chalk3.cyan.bold(" Installation Complete!"));