stripe-experiment-sync 1.0.1 → 1.0.3

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.
@@ -0,0 +1,73 @@
1
+ // package.json
2
+ var package_default = {
3
+ name: "stripe-experiment-sync",
4
+ version: "1.0.3",
5
+ private: false,
6
+ description: "Stripe Sync Engine to sync Stripe data to Postgres",
7
+ type: "module",
8
+ main: "./dist/index.cjs",
9
+ bin: "./dist/cli/index.cjs",
10
+ exports: {
11
+ ".": {
12
+ types: "./dist/index.d.ts",
13
+ import: "./dist/index.js",
14
+ require: "./dist/index.cjs"
15
+ },
16
+ "./supabase": {
17
+ types: "./dist/supabase/index.d.ts",
18
+ import: "./dist/supabase/index.js",
19
+ require: "./dist/supabase/index.cjs"
20
+ }
21
+ },
22
+ scripts: {
23
+ clean: "rimraf dist",
24
+ prebuild: "npm run clean",
25
+ build: "tsup src/index.ts src/supabase/index.ts --format esm,cjs --dts --shims && cp -r src/database/migrations dist/migrations",
26
+ lint: "eslint src --ext .ts",
27
+ test: "vitest"
28
+ },
29
+ files: [
30
+ "dist"
31
+ ],
32
+ dependencies: {
33
+ pg: "^8.16.3",
34
+ "pg-node-migrations": "0.0.8",
35
+ "supabase-management-js": "^0.1.6",
36
+ ws: "^8.18.0",
37
+ yesql: "^7.0.0"
38
+ },
39
+ peerDependencies: {
40
+ stripe: "> 11"
41
+ },
42
+ devDependencies: {
43
+ "@types/node": "^24.10.1",
44
+ "@types/pg": "^8.15.5",
45
+ "@types/ws": "^8.5.13",
46
+ "@types/yesql": "^4.1.4",
47
+ "@vitest/ui": "^4.0.9",
48
+ vitest: "^3.2.4"
49
+ },
50
+ repository: {
51
+ type: "git",
52
+ url: "https://github.com/tx-stripe/stripe-sync-engine.git"
53
+ },
54
+ homepage: "https://github.com/tx-stripe/stripe-sync-engine#readme",
55
+ bugs: {
56
+ url: "https://github.com/tx-stripe/stripe-sync-engine/issues"
57
+ },
58
+ keywords: [
59
+ "stripe",
60
+ "postgres",
61
+ "sync",
62
+ "webhooks",
63
+ "supabase",
64
+ "billing",
65
+ "database",
66
+ "typescript"
67
+ ],
68
+ author: "Supabase <https://supabase.com/>"
69
+ };
70
+
71
+ export {
72
+ package_default
73
+ };
package/dist/index.cjs CHANGED
@@ -45,25 +45,28 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
45
45
  // package.json
46
46
  var package_default = {
47
47
  name: "stripe-experiment-sync",
48
- version: "1.0.1",
48
+ version: "1.0.3",
49
49
  private: false,
50
50
  description: "Stripe Sync Engine to sync Stripe data to Postgres",
51
51
  type: "module",
52
52
  main: "./dist/index.cjs",
53
+ bin: "./dist/cli/index.cjs",
53
54
  exports: {
54
- import: {
55
+ ".": {
55
56
  types: "./dist/index.d.ts",
56
- import: "./dist/index.js"
57
- },
58
- require: {
59
- types: "./dist/index.d.cts",
57
+ import: "./dist/index.js",
60
58
  require: "./dist/index.cjs"
59
+ },
60
+ "./supabase": {
61
+ types: "./dist/supabase/index.d.ts",
62
+ import: "./dist/supabase/index.js",
63
+ require: "./dist/supabase/index.cjs"
61
64
  }
62
65
  },
63
66
  scripts: {
64
67
  clean: "rimraf dist",
65
68
  prebuild: "npm run clean",
66
- build: "tsup src/index.ts --format esm,cjs --dts --shims && cp -r src/database/migrations dist/migrations",
69
+ build: "tsup src/index.ts src/supabase/index.ts --format esm,cjs --dts --shims && cp -r src/database/migrations dist/migrations",
67
70
  lint: "eslint src --ext .ts",
68
71
  test: "vitest"
69
72
  },
@@ -73,6 +76,7 @@ var package_default = {
73
76
  dependencies: {
74
77
  pg: "^8.16.3",
75
78
  "pg-node-migrations": "0.0.8",
79
+ "supabase-management-js": "^0.1.6",
76
80
  ws: "^8.18.0",
77
81
  yesql: "^7.0.0"
78
82
  },
@@ -442,12 +446,20 @@ var PostgresClient = class {
442
446
  */
443
447
  async cancelStaleRuns(accountId) {
444
448
  await this.query(
445
- `UPDATE "${this.config.schema}"."_sync_run" r
449
+ `UPDATE "${this.config.schema}"."_sync_obj_run" o
446
450
  SET status = 'error',
447
451
  error_message = 'Auto-cancelled: stale (no update in 5 min)',
448
452
  completed_at = now()
453
+ WHERE o."_account_id" = $1
454
+ AND o.status = 'running'
455
+ AND o.updated_at < now() - interval '5 minutes'`,
456
+ [accountId]
457
+ );
458
+ await this.query(
459
+ `UPDATE "${this.config.schema}"."_sync_run" r
460
+ SET closed_at = now()
449
461
  WHERE r."_account_id" = $1
450
- AND r.status = 'running'
462
+ AND r.closed_at IS NULL
451
463
  AND EXISTS (
452
464
  SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
453
465
  WHERE o."_account_id" = r."_account_id"
@@ -457,7 +469,7 @@ var PostgresClient = class {
457
469
  SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
458
470
  WHERE o."_account_id" = r."_account_id"
459
471
  AND o.run_started_at = r.started_at
460
- AND o.updated_at >= now() - interval '5 minutes'
472
+ AND o.status IN ('pending', 'running')
461
473
  )`,
462
474
  [accountId]
463
475
  );
@@ -473,7 +485,7 @@ var PostgresClient = class {
473
485
  await this.cancelStaleRuns(accountId);
474
486
  const existing = await this.query(
475
487
  `SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
476
- WHERE "_account_id" = $1 AND status = 'running'`,
488
+ WHERE "_account_id" = $1 AND closed_at IS NULL`,
477
489
  [accountId]
478
490
  );
479
491
  if (existing.rows.length > 0) {
@@ -502,7 +514,7 @@ var PostgresClient = class {
502
514
  async getActiveSyncRun(accountId) {
503
515
  const result = await this.query(
504
516
  `SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
505
- WHERE "_account_id" = $1 AND status = 'running'`,
517
+ WHERE "_account_id" = $1 AND closed_at IS NULL`,
506
518
  [accountId]
507
519
  );
508
520
  if (result.rows.length === 0) return null;
@@ -510,11 +522,12 @@ var PostgresClient = class {
510
522
  return { accountId: row._account_id, runStartedAt: row.started_at };
511
523
  }
512
524
  /**
513
- * Get full sync run details.
525
+ * Get sync run config (for concurrency control).
526
+ * Status is derived from sync_dashboard view.
514
527
  */
515
528
  async getSyncRun(accountId, runStartedAt) {
516
529
  const result = await this.query(
517
- `SELECT "_account_id", started_at, status, max_concurrent
530
+ `SELECT "_account_id", started_at, max_concurrent, closed_at
518
531
  FROM "${this.config.schema}"."_sync_run"
519
532
  WHERE "_account_id" = $1 AND started_at = $2`,
520
533
  [accountId, runStartedAt]
@@ -524,32 +537,22 @@ var PostgresClient = class {
524
537
  return {
525
538
  accountId: row._account_id,
526
539
  runStartedAt: row.started_at,
527
- status: row.status,
528
- maxConcurrent: row.max_concurrent
540
+ maxConcurrent: row.max_concurrent,
541
+ closedAt: row.closed_at
529
542
  };
530
543
  }
531
544
  /**
532
- * Mark a sync run as complete.
545
+ * Close a sync run (mark as done).
546
+ * Status (complete/error) is derived from object run states.
533
547
  */
534
- async completeSyncRun(accountId, runStartedAt) {
548
+ async closeSyncRun(accountId, runStartedAt) {
535
549
  await this.query(
536
550
  `UPDATE "${this.config.schema}"."_sync_run"
537
- SET status = 'complete', completed_at = now()
538
- WHERE "_account_id" = $1 AND started_at = $2`,
551
+ SET closed_at = now()
552
+ WHERE "_account_id" = $1 AND started_at = $2 AND closed_at IS NULL`,
539
553
  [accountId, runStartedAt]
540
554
  );
541
555
  }
542
- /**
543
- * Mark a sync run as failed.
544
- */
545
- async failSyncRun(accountId, runStartedAt, errorMessage) {
546
- await this.query(
547
- `UPDATE "${this.config.schema}"."_sync_run"
548
- SET status = 'error', error_message = $3, completed_at = now()
549
- WHERE "_account_id" = $1 AND started_at = $2`,
550
- [accountId, runStartedAt, errorMessage]
551
- );
552
- }
553
556
  /**
554
557
  * Create object run entries for a sync run.
555
558
  * All objects start as 'pending'.
@@ -673,6 +676,7 @@ var PostgresClient = class {
673
676
  }
674
677
  /**
675
678
  * Mark an object sync as complete.
679
+ * Auto-closes the run when all objects are done.
676
680
  */
677
681
  async completeObjectSync(accountId, runStartedAt, object) {
678
682
  await this.query(
@@ -681,9 +685,14 @@ var PostgresClient = class {
681
685
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
682
686
  [accountId, runStartedAt, object]
683
687
  );
688
+ const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
689
+ if (allDone) {
690
+ await this.closeSyncRun(accountId, runStartedAt);
691
+ }
684
692
  }
685
693
  /**
686
694
  * Mark an object sync as failed.
695
+ * Auto-closes the run when all objects are done.
687
696
  */
688
697
  async failObjectSync(accountId, runStartedAt, object, errorMessage) {
689
698
  await this.query(
@@ -692,6 +701,21 @@ var PostgresClient = class {
692
701
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
693
702
  [accountId, runStartedAt, object, errorMessage]
694
703
  );
704
+ const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
705
+ if (allDone) {
706
+ await this.closeSyncRun(accountId, runStartedAt);
707
+ }
708
+ }
709
+ /**
710
+ * Check if any object in a run has errored.
711
+ */
712
+ async hasAnyObjectErrors(accountId, runStartedAt) {
713
+ const result = await this.query(
714
+ `SELECT COUNT(*) as count FROM "${this.config.schema}"."_sync_obj_run"
715
+ WHERE "_account_id" = $1 AND run_started_at = $2 AND status = 'error'`,
716
+ [accountId, runStartedAt]
717
+ );
718
+ return parseInt(result.rows[0].count) > 0;
695
719
  }
696
720
  /**
697
721
  * Count running objects in a run.
@@ -733,6 +757,13 @@ var PostgresClient = class {
733
757
  );
734
758
  return parseInt(result.rows[0].count) === 0;
735
759
  }
760
+ /**
761
+ * Closes the database connection pool and cleans up resources.
762
+ * Call this when you're done using the PostgresClient instance.
763
+ */
764
+ async close() {
765
+ await this.pool.end();
766
+ }
736
767
  };
737
768
 
738
769
  // src/schemas/managed_webhook.ts
@@ -1287,8 +1318,8 @@ var StripeSync = class {
1287
1318
  // Depends on invoice
1288
1319
  listFn: (p) => this.stripe.creditNotes.list(p),
1289
1320
  upsertFn: (items, id, bf) => this.upsertCreditNotes(items, id, bf),
1290
- supportsCreatedFilter: false
1291
- // credit_notes don't support created filter
1321
+ supportsCreatedFilter: true
1322
+ // credit_notes support created filter
1292
1323
  },
1293
1324
  dispute: {
1294
1325
  order: 14,
@@ -1941,14 +1972,10 @@ var StripeSync = class {
1941
1972
  }
1942
1973
  }
1943
1974
  }
1944
- await this.postgresClient.completeSyncRun(accountId, runStartedAt);
1975
+ await this.postgresClient.closeSyncRun(accountId, runStartedAt);
1945
1976
  return results;
1946
1977
  } catch (error) {
1947
- await this.postgresClient.failSyncRun(
1948
- accountId,
1949
- runStartedAt,
1950
- error instanceof Error ? error.message : "Unknown error"
1951
- );
1978
+ await this.postgresClient.closeSyncRun(accountId, runStartedAt);
1952
1979
  throw error;
1953
1980
  }
1954
1981
  }
@@ -2479,12 +2506,13 @@ var StripeSync = class {
2479
2506
  await this.postgresClient.tryStartObjectSync(accountId, runStartedAt, resourceName);
2480
2507
  try {
2481
2508
  const result = await fn(cursor, runStartedAt);
2482
- await this.postgresClient.completeSyncRun(accountId, runStartedAt);
2509
+ await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
2483
2510
  return result;
2484
2511
  } catch (error) {
2485
- await this.postgresClient.failSyncRun(
2512
+ await this.postgresClient.failObjectSync(
2486
2513
  accountId,
2487
2514
  runStartedAt,
2515
+ resourceName,
2488
2516
  error instanceof Error ? error.message : "Unknown error"
2489
2517
  );
2490
2518
  throw error;
@@ -3232,6 +3260,13 @@ var StripeSync = class {
3232
3260
  }
3233
3261
  return entities;
3234
3262
  }
3263
+ /**
3264
+ * Closes the database connection pool and cleans up resources.
3265
+ * Call this when you're done using the StripeSync instance.
3266
+ */
3267
+ async close() {
3268
+ await this.postgresClient.pool.end();
3269
+ }
3235
3270
  };
3236
3271
  function chunkArray(array, chunkSize) {
3237
3272
  const result = [];
package/dist/index.d.cts CHANGED
@@ -104,22 +104,20 @@ declare class PostgresClient {
104
104
  runStartedAt: Date;
105
105
  } | null>;
106
106
  /**
107
- * Get full sync run details.
107
+ * Get sync run config (for concurrency control).
108
+ * Status is derived from sync_dashboard view.
108
109
  */
109
110
  getSyncRun(accountId: string, runStartedAt: Date): Promise<{
110
111
  accountId: string;
111
112
  runStartedAt: Date;
112
- status: string;
113
113
  maxConcurrent: number;
114
+ closedAt: Date | null;
114
115
  } | null>;
115
116
  /**
116
- * Mark a sync run as complete.
117
- */
118
- completeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
119
- /**
120
- * Mark a sync run as failed.
117
+ * Close a sync run (mark as done).
118
+ * Status (complete/error) is derived from object run states.
121
119
  */
122
- failSyncRun(accountId: string, runStartedAt: Date, errorMessage: string): Promise<void>;
120
+ closeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
123
121
  /**
124
122
  * Create object run entries for a sync run.
125
123
  * All objects start as 'pending'.
@@ -168,12 +166,18 @@ declare class PostgresClient {
168
166
  deleteSyncRuns(accountId: string): Promise<void>;
169
167
  /**
170
168
  * Mark an object sync as complete.
169
+ * Auto-closes the run when all objects are done.
171
170
  */
172
171
  completeObjectSync(accountId: string, runStartedAt: Date, object: string): Promise<void>;
173
172
  /**
174
173
  * Mark an object sync as failed.
174
+ * Auto-closes the run when all objects are done.
175
175
  */
176
176
  failObjectSync(accountId: string, runStartedAt: Date, object: string, errorMessage: string): Promise<void>;
177
+ /**
178
+ * Check if any object in a run has errored.
179
+ */
180
+ hasAnyObjectErrors(accountId: string, runStartedAt: Date): Promise<boolean>;
177
181
  /**
178
182
  * Count running objects in a run.
179
183
  */
@@ -187,6 +191,11 @@ declare class PostgresClient {
187
191
  * Check if all objects in a run are complete (or error).
188
192
  */
189
193
  areAllObjectsComplete(accountId: string, runStartedAt: Date): Promise<boolean>;
194
+ /**
195
+ * Closes the database connection pool and cleans up resources.
196
+ * Call this when you're done using the PostgresClient instance.
197
+ */
198
+ close(): Promise<void>;
190
199
  }
191
200
 
192
201
  /**
@@ -567,6 +576,11 @@ declare class StripeSync {
567
576
  */
568
577
  private expandEntity;
569
578
  private fetchMissingEntities;
579
+ /**
580
+ * Closes the database connection pool and cleans up resources.
581
+ * Call this when you're done using the StripeSync instance.
582
+ */
583
+ close(): Promise<void>;
570
584
  }
571
585
 
572
586
  type MigrationConfig = {
package/dist/index.d.ts CHANGED
@@ -104,22 +104,20 @@ declare class PostgresClient {
104
104
  runStartedAt: Date;
105
105
  } | null>;
106
106
  /**
107
- * Get full sync run details.
107
+ * Get sync run config (for concurrency control).
108
+ * Status is derived from sync_dashboard view.
108
109
  */
109
110
  getSyncRun(accountId: string, runStartedAt: Date): Promise<{
110
111
  accountId: string;
111
112
  runStartedAt: Date;
112
- status: string;
113
113
  maxConcurrent: number;
114
+ closedAt: Date | null;
114
115
  } | null>;
115
116
  /**
116
- * Mark a sync run as complete.
117
- */
118
- completeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
119
- /**
120
- * Mark a sync run as failed.
117
+ * Close a sync run (mark as done).
118
+ * Status (complete/error) is derived from object run states.
121
119
  */
122
- failSyncRun(accountId: string, runStartedAt: Date, errorMessage: string): Promise<void>;
120
+ closeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
123
121
  /**
124
122
  * Create object run entries for a sync run.
125
123
  * All objects start as 'pending'.
@@ -168,12 +166,18 @@ declare class PostgresClient {
168
166
  deleteSyncRuns(accountId: string): Promise<void>;
169
167
  /**
170
168
  * Mark an object sync as complete.
169
+ * Auto-closes the run when all objects are done.
171
170
  */
172
171
  completeObjectSync(accountId: string, runStartedAt: Date, object: string): Promise<void>;
173
172
  /**
174
173
  * Mark an object sync as failed.
174
+ * Auto-closes the run when all objects are done.
175
175
  */
176
176
  failObjectSync(accountId: string, runStartedAt: Date, object: string, errorMessage: string): Promise<void>;
177
+ /**
178
+ * Check if any object in a run has errored.
179
+ */
180
+ hasAnyObjectErrors(accountId: string, runStartedAt: Date): Promise<boolean>;
177
181
  /**
178
182
  * Count running objects in a run.
179
183
  */
@@ -187,6 +191,11 @@ declare class PostgresClient {
187
191
  * Check if all objects in a run are complete (or error).
188
192
  */
189
193
  areAllObjectsComplete(accountId: string, runStartedAt: Date): Promise<boolean>;
194
+ /**
195
+ * Closes the database connection pool and cleans up resources.
196
+ * Call this when you're done using the PostgresClient instance.
197
+ */
198
+ close(): Promise<void>;
190
199
  }
191
200
 
192
201
  /**
@@ -567,6 +576,11 @@ declare class StripeSync {
567
576
  */
568
577
  private expandEntity;
569
578
  private fetchMissingEntities;
579
+ /**
580
+ * Closes the database connection pool and cleans up resources.
581
+ * Call this when you're done using the StripeSync instance.
582
+ */
583
+ close(): Promise<void>;
570
584
  }
571
585
 
572
586
  type MigrationConfig = {