stripe-experiment-sync 1.0.17 → 1.0.19

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/dist/index.cjs CHANGED
@@ -46,7 +46,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
46
46
  // package.json
47
47
  var package_default = {
48
48
  name: "stripe-experiment-sync",
49
- version: "1.0.17",
49
+ version: "1.0.19",
50
50
  private: false,
51
51
  description: "Stripe Sync Engine to sync Stripe data to Postgres",
52
52
  type: "module",
@@ -523,7 +523,8 @@ var PostgresClient = class {
523
523
  `UPDATE "${this.config.schema}"."_sync_obj_runs" o
524
524
  SET status = 'error',
525
525
  error_message = 'Auto-cancelled: stale (no update in 5 min)',
526
- completed_at = now()
526
+ completed_at = now(),
527
+ page_cursor = NULL
527
528
  WHERE o."_account_id" = $1
528
529
  AND o.status = 'running'
529
530
  AND o.updated_at < now() - interval '5 minutes'`,
@@ -630,15 +631,17 @@ var PostgresClient = class {
630
631
  /**
631
632
  * Create object run entries for a sync run.
632
633
  * All objects start as 'pending'.
634
+ *
635
+ * @param resourceNames - Database resource names (e.g. 'products', 'customers', NOT 'product', 'customer')
633
636
  */
634
- async createObjectRuns(accountId, runStartedAt, objects) {
635
- if (objects.length === 0) return;
636
- const values = objects.map((_, i) => `($1, $2, $${i + 3})`).join(", ");
637
+ async createObjectRuns(accountId, runStartedAt, resourceNames) {
638
+ if (resourceNames.length === 0) return;
639
+ const values = resourceNames.map((_, i) => `($1, $2, $${i + 3})`).join(", ");
637
640
  await this.query(
638
641
  `INSERT INTO "${this.config.schema}"."_sync_obj_runs" ("_account_id", run_started_at, object)
639
642
  VALUES ${values}
640
643
  ON CONFLICT ("_account_id", run_started_at, object) DO NOTHING`,
641
- [accountId, runStartedAt, ...objects]
644
+ [accountId, runStartedAt, ...resourceNames]
642
645
  );
643
646
  }
644
647
  /**
@@ -667,7 +670,7 @@ var PostgresClient = class {
667
670
  */
668
671
  async getObjectRun(accountId, runStartedAt, object) {
669
672
  const result = await this.query(
670
- `SELECT object, status, processed_count, cursor
673
+ `SELECT object, status, processed_count, cursor, page_cursor
671
674
  FROM "${this.config.schema}"."_sync_obj_runs"
672
675
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
673
676
  [accountId, runStartedAt, object]
@@ -678,7 +681,8 @@ var PostgresClient = class {
678
681
  object: row.object,
679
682
  status: row.status,
680
683
  processedCount: row.processed_count,
681
- cursor: row.cursor
684
+ cursor: row.cursor,
685
+ pageCursor: row.page_cursor
682
686
  };
683
687
  }
684
688
  /**
@@ -693,6 +697,23 @@ var PostgresClient = class {
693
697
  [accountId, runStartedAt, object, count]
694
698
  );
695
699
  }
700
+ /**
701
+ * Update the pagination page_cursor used for backfills using Stripe list calls.
702
+ */
703
+ async updateObjectPageCursor(accountId, runStartedAt, object, pageCursor) {
704
+ await this.query(
705
+ `UPDATE "${this.config.schema}"."_sync_obj_runs"
706
+ SET page_cursor = $4, updated_at = now()
707
+ WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
708
+ [accountId, runStartedAt, object, pageCursor]
709
+ );
710
+ }
711
+ /**
712
+ * Clear the pagination page_cursor for an object sync.
713
+ */
714
+ async clearObjectPageCursor(accountId, runStartedAt, object) {
715
+ await this.updateObjectPageCursor(accountId, runStartedAt, object, null);
716
+ }
696
717
  /**
697
718
  * Update the cursor for an object sync.
698
719
  * Only updates if the new cursor is higher than the existing one (cursors should never decrease).
@@ -725,9 +746,10 @@ var PostgresClient = class {
725
746
  }
726
747
  /**
727
748
  * Get the highest cursor from previous syncs for an object type.
728
- * This considers completed, error, AND running runs to ensure recovery syncs
729
- * don't re-process data that was already synced before a crash.
730
- * A 'running' status with a cursor means the process was killed mid-sync.
749
+ * Uses only completed object runs.
750
+ * - During the initial backfill we page through history, but we also update the cursor as we go.
751
+ * If we crash mid-backfill and reuse that cursor, we can accidentally switch into incremental mode
752
+ * too early and only ever fetch the newest page (breaking the historical backfill).
731
753
  *
732
754
  * Handles two cursor formats:
733
755
  * - Numeric: compared as bigint for correct ordering
@@ -742,11 +764,31 @@ var PostgresClient = class {
742
764
  FROM "${this.config.schema}"."_sync_obj_runs" o
743
765
  WHERE o."_account_id" = $1
744
766
  AND o.object = $2
745
- AND o.cursor IS NOT NULL`,
767
+ AND o.cursor IS NOT NULL
768
+ AND o.status = 'complete'`,
746
769
  [accountId, object]
747
770
  );
748
771
  return result.rows[0]?.cursor ?? null;
749
772
  }
773
+ /**
774
+ * Get the highest cursor from previous syncs for an object type, excluding the current run.
775
+ */
776
+ async getLastCursorBeforeRun(accountId, object, runStartedAt) {
777
+ const result = await this.query(
778
+ `SELECT CASE
779
+ WHEN BOOL_OR(o.cursor !~ '^\\d+$') THEN MAX(o.cursor COLLATE "C")
780
+ ELSE MAX(CASE WHEN o.cursor ~ '^\\d+$' THEN o.cursor::bigint END)::text
781
+ END as cursor
782
+ FROM "${this.config.schema}"."_sync_obj_runs" o
783
+ WHERE o."_account_id" = $1
784
+ AND o.object = $2
785
+ AND o.cursor IS NOT NULL
786
+ AND o.status = 'complete'
787
+ AND o.run_started_at < $3`,
788
+ [accountId, object, runStartedAt]
789
+ );
790
+ return result.rows[0]?.cursor ?? null;
791
+ }
750
792
  /**
751
793
  * Delete all sync runs and object runs for an account.
752
794
  * Useful for testing or resetting sync state.
@@ -767,7 +809,7 @@ var PostgresClient = class {
767
809
  async completeObjectSync(accountId, runStartedAt, object) {
768
810
  await this.query(
769
811
  `UPDATE "${this.config.schema}"."_sync_obj_runs"
770
- SET status = 'complete', completed_at = now()
812
+ SET status = 'complete', completed_at = now(), page_cursor = NULL
771
813
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
772
814
  [accountId, runStartedAt, object]
773
815
  );
@@ -783,7 +825,7 @@ var PostgresClient = class {
783
825
  async failObjectSync(accountId, runStartedAt, object, errorMessage) {
784
826
  await this.query(
785
827
  `UPDATE "${this.config.schema}"."_sync_obj_runs"
786
- SET status = 'error', error_message = $4, completed_at = now()
828
+ SET status = 'error', error_message = $4, completed_at = now(), page_cursor = NULL
787
829
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
788
830
  [accountId, runStartedAt, object, errorMessage]
789
831
  );
@@ -2084,57 +2126,74 @@ var StripeSync = class {
2084
2126
  * ```
2085
2127
  */
2086
2128
  async processNext(object, params) {
2087
- await this.getCurrentAccount();
2088
- const accountId = await this.getAccountId();
2089
- const resourceName = this.getResourceName(object);
2090
- let runStartedAt;
2091
- if (params?.runStartedAt) {
2092
- runStartedAt = params.runStartedAt;
2093
- } else {
2094
- const { runKey } = await this.joinOrCreateSyncRun(params?.triggeredBy ?? "processNext");
2095
- runStartedAt = runKey.runStartedAt;
2096
- }
2097
- await this.postgresClient.createObjectRuns(accountId, runStartedAt, [resourceName]);
2098
- const objRun = await this.postgresClient.getObjectRun(accountId, runStartedAt, resourceName);
2099
- if (objRun?.status === "complete" || objRun?.status === "error") {
2100
- return {
2101
- processed: 0,
2102
- hasMore: false,
2103
- runStartedAt
2104
- };
2105
- }
2106
- if (objRun?.status === "pending") {
2107
- const started = await this.postgresClient.tryStartObjectSync(
2108
- accountId,
2109
- runStartedAt,
2110
- resourceName
2111
- );
2112
- if (!started) {
2129
+ try {
2130
+ await this.getCurrentAccount();
2131
+ const accountId = await this.getAccountId();
2132
+ const resourceName = this.getResourceName(object);
2133
+ let runStartedAt;
2134
+ if (params?.runStartedAt) {
2135
+ runStartedAt = params.runStartedAt;
2136
+ } else {
2137
+ const { runKey } = await this.joinOrCreateSyncRun(params?.triggeredBy ?? "processNext");
2138
+ runStartedAt = runKey.runStartedAt;
2139
+ }
2140
+ await this.postgresClient.createObjectRuns(accountId, runStartedAt, [resourceName]);
2141
+ const objRun = await this.postgresClient.getObjectRun(accountId, runStartedAt, resourceName);
2142
+ if (objRun?.status === "complete" || objRun?.status === "error") {
2113
2143
  return {
2114
2144
  processed: 0,
2115
- hasMore: true,
2145
+ hasMore: false,
2116
2146
  runStartedAt
2117
2147
  };
2118
2148
  }
2119
- }
2120
- let cursor = null;
2121
- if (!params?.created) {
2122
- if (objRun?.cursor) {
2123
- cursor = objRun.cursor;
2124
- } else {
2125
- const lastCursor = await this.postgresClient.getLastCompletedCursor(accountId, resourceName);
2149
+ if (objRun?.status === "pending") {
2150
+ const started = await this.postgresClient.tryStartObjectSync(
2151
+ accountId,
2152
+ runStartedAt,
2153
+ resourceName
2154
+ );
2155
+ if (!started) {
2156
+ return {
2157
+ processed: 0,
2158
+ hasMore: true,
2159
+ runStartedAt
2160
+ };
2161
+ }
2162
+ }
2163
+ let cursor = null;
2164
+ if (!params?.created) {
2165
+ const lastCursor = await this.postgresClient.getLastCursorBeforeRun(
2166
+ accountId,
2167
+ resourceName,
2168
+ runStartedAt
2169
+ );
2126
2170
  cursor = lastCursor ?? null;
2127
2171
  }
2172
+ const result = await this.fetchOnePage(
2173
+ object,
2174
+ accountId,
2175
+ resourceName,
2176
+ runStartedAt,
2177
+ cursor,
2178
+ objRun?.pageCursor ?? null,
2179
+ params
2180
+ );
2181
+ return result;
2182
+ } catch (error) {
2183
+ throw this.appendMigrationHint(error);
2128
2184
  }
2129
- const result = await this.fetchOnePage(
2130
- object,
2131
- accountId,
2132
- resourceName,
2133
- runStartedAt,
2134
- cursor,
2135
- params
2136
- );
2137
- return result;
2185
+ }
2186
+ appendMigrationHint(error) {
2187
+ const hint = "Error occurred. Make sure you are up to date with DB migrations which can sometimes help with this. Details:";
2188
+ const withHint = (message) => message.includes(hint) ? message : `${hint}
2189
+ ${message}`;
2190
+ if (error instanceof Error) {
2191
+ const { stack } = error;
2192
+ error.message = withHint(error.message);
2193
+ if (stack) error.stack = stack;
2194
+ return error;
2195
+ }
2196
+ return new Error(withHint(String(error)));
2138
2197
  }
2139
2198
  /**
2140
2199
  * Get the database resource name for a SyncObject type
@@ -2166,7 +2225,7 @@ var StripeSync = class {
2166
2225
  * Uses resourceRegistry for DRY list/upsert operations.
2167
2226
  * Uses the observable sync system for tracking progress.
2168
2227
  */
2169
- async fetchOnePage(object, accountId, resourceName, runStartedAt, cursor, params) {
2228
+ async fetchOnePage(object, accountId, resourceName, runStartedAt, cursor, pageCursor, params) {
2170
2229
  const limit = 100;
2171
2230
  if (object === "payment_method" || object === "tax_id") {
2172
2231
  this.config.logger?.warn(`processNext for ${object} requires customer context`);
@@ -2194,7 +2253,16 @@ var StripeSync = class {
2194
2253
  listParams.created = created;
2195
2254
  }
2196
2255
  }
2256
+ if (pageCursor) {
2257
+ listParams.starting_after = pageCursor;
2258
+ }
2197
2259
  const response = await config.listFn(listParams);
2260
+ if (response.data.length === 0 && response.has_more) {
2261
+ const message = `Stripe returned has_more=true with empty page for ${resourceName}. Aborting to avoid infinite loop.`;
2262
+ this.config.logger?.warn(message);
2263
+ await this.postgresClient.failObjectSync(accountId, runStartedAt, resourceName, message);
2264
+ return { processed: 0, hasMore: false, runStartedAt };
2265
+ }
2198
2266
  if (response.data.length > 0) {
2199
2267
  this.config.logger?.info(`processNext: upserting ${response.data.length} ${resourceName}`);
2200
2268
  await config.upsertFn(response.data, accountId, params?.backfillRelatedEntities);
@@ -2215,6 +2283,15 @@ var StripeSync = class {
2215
2283
  String(maxCreated)
2216
2284
  );
2217
2285
  }
2286
+ const lastId = response.data[response.data.length - 1].id;
2287
+ if (response.has_more) {
2288
+ await this.postgresClient.updateObjectPageCursor(
2289
+ accountId,
2290
+ runStartedAt,
2291
+ resourceName,
2292
+ lastId
2293
+ );
2294
+ }
2218
2295
  }
2219
2296
  if (!response.has_more) {
2220
2297
  await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
@@ -2363,31 +2440,43 @@ var StripeSync = class {
2363
2440
  * This is used by workers and background processes that should cooperate.
2364
2441
  *
2365
2442
  * @param triggeredBy - What triggered this sync (for observability)
2443
+ * @param objectFilter - Optional specific object to sync (e.g. 'payment_intent'). If 'all' or undefined, syncs all objects.
2366
2444
  * @returns Run key and list of objects to sync
2367
2445
  */
2368
- async joinOrCreateSyncRun(triggeredBy = "worker") {
2446
+ async joinOrCreateSyncRun(triggeredBy = "worker", objectFilter) {
2369
2447
  await this.getCurrentAccount();
2370
2448
  const accountId = await this.getAccountId();
2371
2449
  const result = await this.postgresClient.getOrCreateSyncRun(accountId, triggeredBy);
2450
+ const objects = objectFilter === "all" || objectFilter === void 0 ? this.getSupportedSyncObjects() : [objectFilter];
2372
2451
  if (!result) {
2373
2452
  const activeRun = await this.postgresClient.getActiveSyncRun(accountId);
2374
2453
  if (!activeRun) {
2375
2454
  throw new Error("Failed to get or create sync run");
2376
2455
  }
2456
+ await this.postgresClient.createObjectRuns(
2457
+ activeRun.accountId,
2458
+ activeRun.runStartedAt,
2459
+ objects.map((obj) => this.getResourceName(obj))
2460
+ );
2377
2461
  return {
2378
2462
  runKey: { accountId: activeRun.accountId, runStartedAt: activeRun.runStartedAt },
2379
- objects: this.getSupportedSyncObjects()
2463
+ objects
2380
2464
  };
2381
2465
  }
2382
2466
  const { accountId: runAccountId, runStartedAt } = result;
2467
+ await this.postgresClient.createObjectRuns(
2468
+ runAccountId,
2469
+ runStartedAt,
2470
+ objects.map((obj) => this.getResourceName(obj))
2471
+ );
2383
2472
  return {
2384
2473
  runKey: { accountId: runAccountId, runStartedAt },
2385
- objects: this.getSupportedSyncObjects()
2474
+ objects
2386
2475
  };
2387
2476
  }
2388
2477
  async processUntilDone(params) {
2389
2478
  const { object } = params ?? { object: "all" };
2390
- const { runKey } = await this.joinOrCreateSyncRun("processUntilDone");
2479
+ const { runKey } = await this.joinOrCreateSyncRun("processUntilDone", object);
2391
2480
  return this.processUntilDoneWithRun(runKey.runStartedAt, object, params);
2392
2481
  }
2393
2482
  /**
package/dist/index.d.cts CHANGED
@@ -137,8 +137,10 @@ declare class PostgresClient {
137
137
  /**
138
138
  * Create object run entries for a sync run.
139
139
  * All objects start as 'pending'.
140
+ *
141
+ * @param resourceNames - Database resource names (e.g. 'products', 'customers', NOT 'product', 'customer')
140
142
  */
141
- createObjectRuns(accountId: string, runStartedAt: Date, objects: string[]): Promise<void>;
143
+ createObjectRuns(accountId: string, runStartedAt: Date, resourceNames: string[]): Promise<void>;
142
144
  /**
143
145
  * Try to start an object sync (respects max_concurrent).
144
146
  * Returns true if claimed, false if already running or at concurrency limit.
@@ -155,12 +157,21 @@ declare class PostgresClient {
155
157
  status: string;
156
158
  processedCount: number;
157
159
  cursor: string | null;
160
+ pageCursor: string | null;
158
161
  } | null>;
159
162
  /**
160
163
  * Update progress for an object sync.
161
164
  * Also touches updated_at for stale detection.
162
165
  */
163
166
  incrementObjectProgress(accountId: string, runStartedAt: Date, object: string, count: number): Promise<void>;
167
+ /**
168
+ * Update the pagination page_cursor used for backfills using Stripe list calls.
169
+ */
170
+ updateObjectPageCursor(accountId: string, runStartedAt: Date, object: string, pageCursor: string | null): Promise<void>;
171
+ /**
172
+ * Clear the pagination page_cursor for an object sync.
173
+ */
174
+ clearObjectPageCursor(accountId: string, runStartedAt: Date, object: string): Promise<void>;
164
175
  /**
165
176
  * Update the cursor for an object sync.
166
177
  * Only updates if the new cursor is higher than the existing one (cursors should never decrease).
@@ -170,15 +181,20 @@ declare class PostgresClient {
170
181
  updateObjectCursor(accountId: string, runStartedAt: Date, object: string, cursor: string | null): Promise<void>;
171
182
  /**
172
183
  * Get the highest cursor from previous syncs for an object type.
173
- * This considers completed, error, AND running runs to ensure recovery syncs
174
- * don't re-process data that was already synced before a crash.
175
- * A 'running' status with a cursor means the process was killed mid-sync.
184
+ * Uses only completed object runs.
185
+ * - During the initial backfill we page through history, but we also update the cursor as we go.
186
+ * If we crash mid-backfill and reuse that cursor, we can accidentally switch into incremental mode
187
+ * too early and only ever fetch the newest page (breaking the historical backfill).
176
188
  *
177
189
  * Handles two cursor formats:
178
190
  * - Numeric: compared as bigint for correct ordering
179
191
  * - Composite cursors: compared as strings with COLLATE "C"
180
192
  */
181
193
  getLastCompletedCursor(accountId: string, object: string): Promise<string | null>;
194
+ /**
195
+ * Get the highest cursor from previous syncs for an object type, excluding the current run.
196
+ */
197
+ getLastCursorBeforeRun(accountId: string, object: string, runStartedAt: Date): Promise<string | null>;
182
198
  /**
183
199
  * Delete all sync runs and object runs for an account.
184
200
  * Useful for testing or resetting sync state.
@@ -585,6 +601,7 @@ declare class StripeSync {
585
601
  * ```
586
602
  */
587
603
  processNext(object: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>, params?: ProcessNextParams): Promise<ProcessNextResult>;
604
+ private appendMigrationHint;
588
605
  /**
589
606
  * Get the database resource name for a SyncObject type
590
607
  */
@@ -621,9 +638,10 @@ declare class StripeSync {
621
638
  * This is used by workers and background processes that should cooperate.
622
639
  *
623
640
  * @param triggeredBy - What triggered this sync (for observability)
641
+ * @param objectFilter - Optional specific object to sync (e.g. 'payment_intent'). If 'all' or undefined, syncs all objects.
624
642
  * @returns Run key and list of objects to sync
625
643
  */
626
- joinOrCreateSyncRun(triggeredBy?: string): Promise<{
644
+ joinOrCreateSyncRun(triggeredBy?: string, objectFilter?: SyncObject): Promise<{
627
645
  runKey: RunKey;
628
646
  objects: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>[];
629
647
  }>;
package/dist/index.d.ts CHANGED
@@ -137,8 +137,10 @@ declare class PostgresClient {
137
137
  /**
138
138
  * Create object run entries for a sync run.
139
139
  * All objects start as 'pending'.
140
+ *
141
+ * @param resourceNames - Database resource names (e.g. 'products', 'customers', NOT 'product', 'customer')
140
142
  */
141
- createObjectRuns(accountId: string, runStartedAt: Date, objects: string[]): Promise<void>;
143
+ createObjectRuns(accountId: string, runStartedAt: Date, resourceNames: string[]): Promise<void>;
142
144
  /**
143
145
  * Try to start an object sync (respects max_concurrent).
144
146
  * Returns true if claimed, false if already running or at concurrency limit.
@@ -155,12 +157,21 @@ declare class PostgresClient {
155
157
  status: string;
156
158
  processedCount: number;
157
159
  cursor: string | null;
160
+ pageCursor: string | null;
158
161
  } | null>;
159
162
  /**
160
163
  * Update progress for an object sync.
161
164
  * Also touches updated_at for stale detection.
162
165
  */
163
166
  incrementObjectProgress(accountId: string, runStartedAt: Date, object: string, count: number): Promise<void>;
167
+ /**
168
+ * Update the pagination page_cursor used for backfills using Stripe list calls.
169
+ */
170
+ updateObjectPageCursor(accountId: string, runStartedAt: Date, object: string, pageCursor: string | null): Promise<void>;
171
+ /**
172
+ * Clear the pagination page_cursor for an object sync.
173
+ */
174
+ clearObjectPageCursor(accountId: string, runStartedAt: Date, object: string): Promise<void>;
164
175
  /**
165
176
  * Update the cursor for an object sync.
166
177
  * Only updates if the new cursor is higher than the existing one (cursors should never decrease).
@@ -170,15 +181,20 @@ declare class PostgresClient {
170
181
  updateObjectCursor(accountId: string, runStartedAt: Date, object: string, cursor: string | null): Promise<void>;
171
182
  /**
172
183
  * Get the highest cursor from previous syncs for an object type.
173
- * This considers completed, error, AND running runs to ensure recovery syncs
174
- * don't re-process data that was already synced before a crash.
175
- * A 'running' status with a cursor means the process was killed mid-sync.
184
+ * Uses only completed object runs.
185
+ * - During the initial backfill we page through history, but we also update the cursor as we go.
186
+ * If we crash mid-backfill and reuse that cursor, we can accidentally switch into incremental mode
187
+ * too early and only ever fetch the newest page (breaking the historical backfill).
176
188
  *
177
189
  * Handles two cursor formats:
178
190
  * - Numeric: compared as bigint for correct ordering
179
191
  * - Composite cursors: compared as strings with COLLATE "C"
180
192
  */
181
193
  getLastCompletedCursor(accountId: string, object: string): Promise<string | null>;
194
+ /**
195
+ * Get the highest cursor from previous syncs for an object type, excluding the current run.
196
+ */
197
+ getLastCursorBeforeRun(accountId: string, object: string, runStartedAt: Date): Promise<string | null>;
182
198
  /**
183
199
  * Delete all sync runs and object runs for an account.
184
200
  * Useful for testing or resetting sync state.
@@ -585,6 +601,7 @@ declare class StripeSync {
585
601
  * ```
586
602
  */
587
603
  processNext(object: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>, params?: ProcessNextParams): Promise<ProcessNextResult>;
604
+ private appendMigrationHint;
588
605
  /**
589
606
  * Get the database resource name for a SyncObject type
590
607
  */
@@ -621,9 +638,10 @@ declare class StripeSync {
621
638
  * This is used by workers and background processes that should cooperate.
622
639
  *
623
640
  * @param triggeredBy - What triggered this sync (for observability)
641
+ * @param objectFilter - Optional specific object to sync (e.g. 'payment_intent'). If 'all' or undefined, syncs all objects.
624
642
  * @returns Run key and list of objects to sync
625
643
  */
626
- joinOrCreateSyncRun(triggeredBy?: string): Promise<{
644
+ joinOrCreateSyncRun(triggeredBy?: string, objectFilter?: SyncObject): Promise<{
627
645
  runKey: RunKey;
628
646
  objects: Exclude<SyncObject, 'all' | 'customer_with_entitlements'>[];
629
647
  }>;
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  createStripeWebSocketClient,
6
6
  hashApiKey,
7
7
  runMigrations
8
- } from "./chunk-TV67ZOCK.js";
9
- import "./chunk-57SXDCMH.js";
8
+ } from "./chunk-XKBCLBFT.js";
9
+ import "./chunk-CMGFQCD7.js";
10
10
  export {
11
11
  PostgresClient,
12
12
  StripeSync,
@@ -0,0 +1,3 @@
1
+ -- Add page_cursor column for pagination state within a single sync run.
2
+ -- This is used to store the starting_after ID for backfills using Stripe list calls.
3
+ ALTER TABLE "stripe"."_sync_obj_runs" ADD COLUMN IF NOT EXISTS page_cursor text;
@@ -54,7 +54,7 @@ var workerFunctionCode = stripe_worker_default;
54
54
  // package.json
55
55
  var package_default = {
56
56
  name: "stripe-experiment-sync",
57
- version: "1.0.17",
57
+ version: "1.0.19",
58
58
  private: false,
59
59
  description: "Stripe Sync Engine to sync Stripe data to Postgres",
60
60
  type: "module",
@@ -9,8 +9,8 @@ import {
9
9
  uninstall,
10
10
  webhookFunctionCode,
11
11
  workerFunctionCode
12
- } from "../chunk-I7IFXSAU.js";
13
- import "../chunk-57SXDCMH.js";
12
+ } from "../chunk-4P6TAP7L.js";
13
+ import "../chunk-CMGFQCD7.js";
14
14
  export {
15
15
  INSTALLATION_ERROR_SUFFIX,
16
16
  INSTALLATION_INSTALLED_SUFFIX,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "stripe-experiment-sync",
3
- "version": "1.0.17",
3
+ "version": "1.0.19",
4
4
  "private": false,
5
5
  "description": "Stripe Sync Engine to sync Stripe data to Postgres",
6
6
  "type": "module",