stripe-experiment-sync 1.0.0 → 1.0.2

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
@@ -45,47 +45,25 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
45
45
  // package.json
46
46
  var package_default = {
47
47
  name: "stripe-experiment-sync",
48
- version: "1.0.0",
48
+ version: "1.0.2",
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
53
  exports: {
54
- ".": {
55
- import: {
56
- types: "./dist/index.d.ts",
57
- default: "./dist/index.js"
58
- },
59
- require: {
60
- types: "./dist/index.d.cts",
61
- default: "./dist/index.cjs"
62
- }
63
- },
64
- "./pg": {
65
- import: {
66
- types: "./dist/pg.d.ts",
67
- default: "./dist/pg.js"
68
- },
69
- require: {
70
- types: "./dist/pg.d.cts",
71
- default: "./dist/pg.cjs"
72
- }
54
+ import: {
55
+ types: "./dist/index.d.ts",
56
+ import: "./dist/index.js"
73
57
  },
74
- "./postgres-js": {
75
- import: {
76
- types: "./dist/postgres-js.d.ts",
77
- default: "./dist/postgres-js.js"
78
- },
79
- require: {
80
- types: "./dist/postgres-js.d.cts",
81
- default: "./dist/postgres-js.cjs"
82
- }
58
+ require: {
59
+ types: "./dist/index.d.cts",
60
+ require: "./dist/index.cjs"
83
61
  }
84
62
  },
85
63
  scripts: {
86
64
  clean: "rimraf dist",
87
65
  prebuild: "npm run clean",
88
- build: "tsup src/index.ts src/pg.ts src/postgres-js.ts --format esm,cjs --dts --shims && cp -r src/database/migrations dist/migrations",
66
+ build: "tsup src/index.ts --format esm,cjs --dts --shims && cp -r src/database/migrations dist/migrations",
89
67
  lint: "eslint src --ext .ts",
90
68
  test: "vitest"
91
69
  },
@@ -95,7 +73,6 @@ var package_default = {
95
73
  dependencies: {
96
74
  pg: "^8.16.3",
97
75
  "pg-node-migrations": "0.0.8",
98
- postgres: "^3.4.7",
99
76
  ws: "^8.18.0",
100
77
  yesql: "^7.0.0"
101
78
  },
@@ -108,7 +85,6 @@ var package_default = {
108
85
  "@types/ws": "^8.5.13",
109
86
  "@types/yesql": "^4.1.4",
110
87
  "@vitest/ui": "^4.0.9",
111
- stripe: "^20.0.0",
112
88
  vitest: "^3.2.4"
113
89
  },
114
90
  repository: {
@@ -137,6 +113,7 @@ var import_stripe2 = __toESM(require("stripe"), 1);
137
113
  var import_yesql2 = require("yesql");
138
114
 
139
115
  // src/database/postgres.ts
116
+ var import_pg = __toESM(require("pg"), 1);
140
117
  var import_yesql = require("yesql");
141
118
  var ORDERED_STRIPE_TABLES = [
142
119
  "subscription_items",
@@ -170,22 +147,9 @@ var TABLES_WITH_ACCOUNT_ID = /* @__PURE__ */ new Set(["_managed_webhooks"]);
170
147
  var PostgresClient = class {
171
148
  constructor(config) {
172
149
  this.config = config;
173
- this.adapter = config.adapter;
174
- }
175
- adapter;
176
- /**
177
- * Get the underlying adapter.
178
- * Useful for accessing adapter-specific features.
179
- */
180
- getAdapter() {
181
- return this.adapter;
182
- }
183
- /**
184
- * Close all database connections.
185
- */
186
- async end() {
187
- await this.adapter.end();
150
+ this.pool = new import_pg.default.Pool(config.poolConfig);
188
151
  }
152
+ pool;
189
153
  async delete(table, id) {
190
154
  const prepared = (0, import_yesql.pg)(`
191
155
  delete from "${this.config.schema}"."${table}"
@@ -197,7 +161,7 @@ var PostgresClient = class {
197
161
  }
198
162
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
199
163
  async query(text, params) {
200
- return this.adapter.query(text, params);
164
+ return this.pool.query(text, params);
201
165
  }
202
166
  async upsertMany(entries, table) {
203
167
  if (!entries.length) return [];
@@ -216,7 +180,7 @@ var PostgresClient = class {
216
180
  "_raw_data" = EXCLUDED."_raw_data"
217
181
  RETURNING *
218
182
  `;
219
- queries.push(this.adapter.query(upsertSql, [rawData]));
183
+ queries.push(this.pool.query(upsertSql, [rawData]));
220
184
  });
221
185
  results.push(...await Promise.all(queries));
222
186
  }
@@ -255,7 +219,7 @@ var PostgresClient = class {
255
219
  cleansed.last_synced_at = timestamp;
256
220
  cleansed.account_id = accountId;
257
221
  const prepared = (0, import_yesql.pg)(upsertSql, { useNullForMissing: true })(cleansed);
258
- queries.push(this.adapter.query(prepared.text, prepared.values));
222
+ queries.push(this.pool.query(prepared.text, prepared.values));
259
223
  } else {
260
224
  const rawData = JSON.stringify(entry);
261
225
  const upsertSql = `
@@ -270,7 +234,7 @@ var PostgresClient = class {
270
234
  OR "${table}"."_last_synced_at" < $2
271
235
  RETURNING *
272
236
  `;
273
- queries.push(this.adapter.query(upsertSql, [rawData, timestamp, accountId]));
237
+ queries.push(this.pool.query(upsertSql, [rawData, timestamp, accountId]));
274
238
  }
275
239
  });
276
240
  results.push(...await Promise.all(queries));
@@ -442,13 +406,27 @@ var PostgresClient = class {
442
406
  * Execute a function while holding an advisory lock.
443
407
  * The lock is automatically released after the function completes (success or error).
444
408
  *
409
+ * IMPORTANT: This acquires a dedicated connection from the pool and holds it for the
410
+ * duration of the function execution. PostgreSQL advisory locks are session-level,
411
+ * so we must use the same connection for lock acquisition, operations, and release.
412
+ *
445
413
  * @param key - A string key to lock on (will be hashed to an integer)
446
414
  * @param fn - The function to execute while holding the lock
447
415
  * @returns The result of the function
448
416
  */
449
417
  async withAdvisoryLock(key, fn) {
450
418
  const lockId = this.hashToInt32(key);
451
- return this.adapter.withAdvisoryLock(lockId, fn);
419
+ const client = await this.pool.connect();
420
+ try {
421
+ await client.query("SELECT pg_advisory_lock($1)", [lockId]);
422
+ return await fn();
423
+ } finally {
424
+ try {
425
+ await client.query("SELECT pg_advisory_unlock($1)", [lockId]);
426
+ } finally {
427
+ client.release();
428
+ }
429
+ }
452
430
  }
453
431
  // =============================================================================
454
432
  // Observable Sync System Methods
@@ -464,12 +442,20 @@ var PostgresClient = class {
464
442
  */
465
443
  async cancelStaleRuns(accountId) {
466
444
  await this.query(
467
- `UPDATE "${this.config.schema}"."_sync_run" r
445
+ `UPDATE "${this.config.schema}"."_sync_obj_run" o
468
446
  SET status = 'error',
469
447
  error_message = 'Auto-cancelled: stale (no update in 5 min)',
470
448
  completed_at = now()
449
+ WHERE o."_account_id" = $1
450
+ AND o.status = 'running'
451
+ AND o.updated_at < now() - interval '5 minutes'`,
452
+ [accountId]
453
+ );
454
+ await this.query(
455
+ `UPDATE "${this.config.schema}"."_sync_run" r
456
+ SET closed_at = now()
471
457
  WHERE r."_account_id" = $1
472
- AND r.status = 'running'
458
+ AND r.closed_at IS NULL
473
459
  AND EXISTS (
474
460
  SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
475
461
  WHERE o."_account_id" = r."_account_id"
@@ -479,7 +465,7 @@ var PostgresClient = class {
479
465
  SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
480
466
  WHERE o."_account_id" = r."_account_id"
481
467
  AND o.run_started_at = r.started_at
482
- AND o.updated_at >= now() - interval '5 minutes'
468
+ AND o.status IN ('pending', 'running')
483
469
  )`,
484
470
  [accountId]
485
471
  );
@@ -495,7 +481,7 @@ var PostgresClient = class {
495
481
  await this.cancelStaleRuns(accountId);
496
482
  const existing = await this.query(
497
483
  `SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
498
- WHERE "_account_id" = $1 AND status = 'running'`,
484
+ WHERE "_account_id" = $1 AND closed_at IS NULL`,
499
485
  [accountId]
500
486
  );
501
487
  if (existing.rows.length > 0) {
@@ -524,7 +510,7 @@ var PostgresClient = class {
524
510
  async getActiveSyncRun(accountId) {
525
511
  const result = await this.query(
526
512
  `SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
527
- WHERE "_account_id" = $1 AND status = 'running'`,
513
+ WHERE "_account_id" = $1 AND closed_at IS NULL`,
528
514
  [accountId]
529
515
  );
530
516
  if (result.rows.length === 0) return null;
@@ -532,11 +518,12 @@ var PostgresClient = class {
532
518
  return { accountId: row._account_id, runStartedAt: row.started_at };
533
519
  }
534
520
  /**
535
- * Get full sync run details.
521
+ * Get sync run config (for concurrency control).
522
+ * Status is derived from sync_dashboard view.
536
523
  */
537
524
  async getSyncRun(accountId, runStartedAt) {
538
525
  const result = await this.query(
539
- `SELECT "_account_id", started_at, status, max_concurrent
526
+ `SELECT "_account_id", started_at, max_concurrent, closed_at
540
527
  FROM "${this.config.schema}"."_sync_run"
541
528
  WHERE "_account_id" = $1 AND started_at = $2`,
542
529
  [accountId, runStartedAt]
@@ -546,32 +533,22 @@ var PostgresClient = class {
546
533
  return {
547
534
  accountId: row._account_id,
548
535
  runStartedAt: row.started_at,
549
- status: row.status,
550
- maxConcurrent: row.max_concurrent
536
+ maxConcurrent: row.max_concurrent,
537
+ closedAt: row.closed_at
551
538
  };
552
539
  }
553
540
  /**
554
- * Mark a sync run as complete.
541
+ * Close a sync run (mark as done).
542
+ * Status (complete/error) is derived from object run states.
555
543
  */
556
- async completeSyncRun(accountId, runStartedAt) {
544
+ async closeSyncRun(accountId, runStartedAt) {
557
545
  await this.query(
558
546
  `UPDATE "${this.config.schema}"."_sync_run"
559
- SET status = 'complete', completed_at = now()
560
- WHERE "_account_id" = $1 AND started_at = $2`,
547
+ SET closed_at = now()
548
+ WHERE "_account_id" = $1 AND started_at = $2 AND closed_at IS NULL`,
561
549
  [accountId, runStartedAt]
562
550
  );
563
551
  }
564
- /**
565
- * Mark a sync run as failed.
566
- */
567
- async failSyncRun(accountId, runStartedAt, errorMessage) {
568
- await this.query(
569
- `UPDATE "${this.config.schema}"."_sync_run"
570
- SET status = 'error', error_message = $3, completed_at = now()
571
- WHERE "_account_id" = $1 AND started_at = $2`,
572
- [accountId, runStartedAt, errorMessage]
573
- );
574
- }
575
552
  /**
576
553
  * Create object run entries for a sync run.
577
554
  * All objects start as 'pending'.
@@ -695,6 +672,7 @@ var PostgresClient = class {
695
672
  }
696
673
  /**
697
674
  * Mark an object sync as complete.
675
+ * Auto-closes the run when all objects are done.
698
676
  */
699
677
  async completeObjectSync(accountId, runStartedAt, object) {
700
678
  await this.query(
@@ -703,9 +681,14 @@ var PostgresClient = class {
703
681
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
704
682
  [accountId, runStartedAt, object]
705
683
  );
684
+ const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
685
+ if (allDone) {
686
+ await this.closeSyncRun(accountId, runStartedAt);
687
+ }
706
688
  }
707
689
  /**
708
690
  * Mark an object sync as failed.
691
+ * Auto-closes the run when all objects are done.
709
692
  */
710
693
  async failObjectSync(accountId, runStartedAt, object, errorMessage) {
711
694
  await this.query(
@@ -714,6 +697,21 @@ var PostgresClient = class {
714
697
  WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
715
698
  [accountId, runStartedAt, object, errorMessage]
716
699
  );
700
+ const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
701
+ if (allDone) {
702
+ await this.closeSyncRun(accountId, runStartedAt);
703
+ }
704
+ }
705
+ /**
706
+ * Check if any object in a run has errored.
707
+ */
708
+ async hasAnyObjectErrors(accountId, runStartedAt) {
709
+ const result = await this.query(
710
+ `SELECT COUNT(*) as count FROM "${this.config.schema}"."_sync_obj_run"
711
+ WHERE "_account_id" = $1 AND run_started_at = $2 AND status = 'error'`,
712
+ [accountId, runStartedAt]
713
+ );
714
+ return parseInt(result.rows[0].count) > 0;
717
715
  }
718
716
  /**
719
717
  * Count running objects in a run.
@@ -952,9 +950,22 @@ var StripeSync = class {
952
950
  { autoExpandLists: config.autoExpandLists, stripeApiVersion: config.stripeApiVersion },
953
951
  "StripeSync initialized"
954
952
  );
953
+ const poolConfig = config.poolConfig ?? {};
954
+ if (config.databaseUrl) {
955
+ poolConfig.connectionString = config.databaseUrl;
956
+ }
957
+ if (config.maxPostgresConnections) {
958
+ poolConfig.max = config.maxPostgresConnections;
959
+ }
960
+ if (poolConfig.max === void 0) {
961
+ poolConfig.max = 10;
962
+ }
963
+ if (poolConfig.keepAlive === void 0) {
964
+ poolConfig.keepAlive = true;
965
+ }
955
966
  this.postgresClient = new PostgresClient({
956
967
  schema: "stripe",
957
- adapter: config.adapter
968
+ poolConfig
958
969
  });
959
970
  }
960
971
  stripe;
@@ -1296,8 +1307,8 @@ var StripeSync = class {
1296
1307
  // Depends on invoice
1297
1308
  listFn: (p) => this.stripe.creditNotes.list(p),
1298
1309
  upsertFn: (items, id, bf) => this.upsertCreditNotes(items, id, bf),
1299
- supportsCreatedFilter: false
1300
- // credit_notes don't support created filter
1310
+ supportsCreatedFilter: true
1311
+ // credit_notes support created filter
1301
1312
  },
1302
1313
  dispute: {
1303
1314
  order: 14,
@@ -1950,14 +1961,10 @@ var StripeSync = class {
1950
1961
  }
1951
1962
  }
1952
1963
  }
1953
- await this.postgresClient.completeSyncRun(accountId, runStartedAt);
1964
+ await this.postgresClient.closeSyncRun(accountId, runStartedAt);
1954
1965
  return results;
1955
1966
  } catch (error) {
1956
- await this.postgresClient.failSyncRun(
1957
- accountId,
1958
- runStartedAt,
1959
- error instanceof Error ? error.message : "Unknown error"
1960
- );
1967
+ await this.postgresClient.closeSyncRun(accountId, runStartedAt);
1961
1968
  throw error;
1962
1969
  }
1963
1970
  }
@@ -2488,12 +2495,13 @@ var StripeSync = class {
2488
2495
  await this.postgresClient.tryStartObjectSync(accountId, runStartedAt, resourceName);
2489
2496
  try {
2490
2497
  const result = await fn(cursor, runStartedAt);
2491
- await this.postgresClient.completeSyncRun(accountId, runStartedAt);
2498
+ await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
2492
2499
  return result;
2493
2500
  } catch (error) {
2494
- await this.postgresClient.failSyncRun(
2501
+ await this.postgresClient.failObjectSync(
2495
2502
  accountId,
2496
2503
  runStartedAt,
2504
+ resourceName,
2497
2505
  error instanceof Error ? error.message : "Unknown error"
2498
2506
  );
2499
2507
  throw error;
@@ -3251,6 +3259,7 @@ function chunkArray(array, chunkSize) {
3251
3259
  }
3252
3260
 
3253
3261
  // src/database/migrate.ts
3262
+ var import_pg2 = require("pg");
3254
3263
  var import_pg_node_migrations = require("pg-node-migrations");
3255
3264
  var import_node_fs = __toESM(require("fs"), 1);
3256
3265
  var import_node_path = __toESM(require("path"), 1);
@@ -3258,15 +3267,15 @@ var import_node_url = require("url");
3258
3267
  var __filename2 = (0, import_node_url.fileURLToPath)(importMetaUrl);
3259
3268
  var __dirname = import_node_path.default.dirname(__filename2);
3260
3269
  async function doesTableExist(client, schema, tableName) {
3261
- const result = await client.query({
3262
- text: `SELECT EXISTS (
3270
+ const result = await client.query(
3271
+ `SELECT EXISTS (
3263
3272
  SELECT 1
3264
3273
  FROM information_schema.tables
3265
3274
  WHERE table_schema = $1
3266
3275
  AND table_name = $2
3267
3276
  )`,
3268
- values: [schema, tableName]
3269
- });
3277
+ [schema, tableName]
3278
+ );
3270
3279
  return result.rows[0]?.exists || false;
3271
3280
  }
3272
3281
  async function renameMigrationsTableIfNeeded(client, schema = "stripe", logger) {
@@ -3284,9 +3293,9 @@ async function cleanupSchema(client, schema, logger) {
3284
3293
  await client.query(`CREATE SCHEMA "${schema}"`);
3285
3294
  logger?.info(`Schema "${schema}" has been reset`);
3286
3295
  }
3287
- async function connectAndMigrate(client, migrationsDirectory, logger, logOnError = false) {
3296
+ async function connectAndMigrate(client, migrationsDirectory, config, logOnError = false) {
3288
3297
  if (!import_node_fs.default.existsSync(migrationsDirectory)) {
3289
- logger?.info(`Migrations directory ${migrationsDirectory} not found, skipping`);
3298
+ config.logger?.info(`Migrations directory ${migrationsDirectory} not found, skipping`);
3290
3299
  return;
3291
3300
  }
3292
3301
  const optionalConfig = {
@@ -3297,18 +3306,23 @@ async function connectAndMigrate(client, migrationsDirectory, logger, logOnError
3297
3306
  await (0, import_pg_node_migrations.migrate)({ client }, migrationsDirectory, optionalConfig);
3298
3307
  } catch (error) {
3299
3308
  if (logOnError && error instanceof Error) {
3300
- logger?.error(error, "Migration error:");
3309
+ config.logger?.error(error, "Migration error:");
3301
3310
  } else {
3302
3311
  throw error;
3303
3312
  }
3304
3313
  }
3305
3314
  }
3306
- async function runMigrations(adapter, logger) {
3307
- const client = adapter.toPgClient();
3315
+ async function runMigrations(config) {
3316
+ const client = new import_pg2.Client({
3317
+ connectionString: config.databaseUrl,
3318
+ ssl: config.ssl,
3319
+ connectionTimeoutMillis: 1e4
3320
+ });
3308
3321
  const schema = "stripe";
3309
3322
  try {
3323
+ await client.connect();
3310
3324
  await client.query(`CREATE SCHEMA IF NOT EXISTS ${schema};`);
3311
- await renameMigrationsTableIfNeeded(client, schema, logger);
3325
+ await renameMigrationsTableIfNeeded(client, schema, config.logger);
3312
3326
  const tableExists = await doesTableExist(client, schema, "_migrations");
3313
3327
  if (tableExists) {
3314
3328
  const migrationCount = await client.query(
@@ -3316,16 +3330,17 @@ async function runMigrations(adapter, logger) {
3316
3330
  );
3317
3331
  const isEmpty = migrationCount.rows[0]?.count === "0";
3318
3332
  if (isEmpty) {
3319
- await cleanupSchema(client, schema, logger);
3333
+ await cleanupSchema(client, schema, config.logger);
3320
3334
  }
3321
3335
  }
3322
- logger?.info("Running migrations");
3323
- await connectAndMigrate(client, import_node_path.default.resolve(__dirname, "./migrations"), logger);
3336
+ config.logger?.info("Running migrations");
3337
+ await connectAndMigrate(client, import_node_path.default.resolve(__dirname, "./migrations"), config);
3324
3338
  } catch (err) {
3325
- logger?.error(err, "Error running migrations");
3339
+ config.logger?.error(err, "Error running migrations");
3326
3340
  throw err;
3327
3341
  } finally {
3328
- logger?.info("Finished migrations");
3342
+ await client.end();
3343
+ config.logger?.info("Finished migrations");
3329
3344
  }
3330
3345
  }
3331
3346
 
package/dist/index.d.cts CHANGED
@@ -1,29 +1,17 @@
1
1
  import Stripe from 'stripe';
2
- import { D as DatabaseAdapter } from './adapter-BtXT5w9r.cjs';
3
- export { P as PgCompatibleClient } from './adapter-BtXT5w9r.cjs';
2
+ import pg, { PoolConfig, QueryResult } from 'pg';
3
+ import { ConnectionOptions } from 'node:tls';
4
4
 
5
5
  type PostgresConfig = {
6
6
  schema: string;
7
- adapter: DatabaseAdapter;
7
+ poolConfig: PoolConfig;
8
8
  };
9
9
  declare class PostgresClient {
10
10
  private config;
11
- private adapter;
11
+ pool: pg.Pool;
12
12
  constructor(config: PostgresConfig);
13
- /**
14
- * Get the underlying adapter.
15
- * Useful for accessing adapter-specific features.
16
- */
17
- getAdapter(): DatabaseAdapter;
18
- /**
19
- * Close all database connections.
20
- */
21
- end(): Promise<void>;
22
13
  delete(table: string, id: string): Promise<boolean>;
23
- query<T = any>(text: string, params?: any[]): Promise<{
24
- rows: T[];
25
- rowCount: number;
26
- }>;
14
+ query(text: string, params?: any[]): Promise<QueryResult>;
27
15
  upsertMany<T extends {
28
16
  [Key: string]: any;
29
17
  }>(entries: T[], table: string): Promise<T[]>;
@@ -80,6 +68,10 @@ declare class PostgresClient {
80
68
  * Execute a function while holding an advisory lock.
81
69
  * The lock is automatically released after the function completes (success or error).
82
70
  *
71
+ * IMPORTANT: This acquires a dedicated connection from the pool and holds it for the
72
+ * duration of the function execution. PostgreSQL advisory locks are session-level,
73
+ * so we must use the same connection for lock acquisition, operations, and release.
74
+ *
83
75
  * @param key - A string key to lock on (will be hashed to an integer)
84
76
  * @param fn - The function to execute while holding the lock
85
77
  * @returns The result of the function
@@ -112,22 +104,20 @@ declare class PostgresClient {
112
104
  runStartedAt: Date;
113
105
  } | null>;
114
106
  /**
115
- * Get full sync run details.
107
+ * Get sync run config (for concurrency control).
108
+ * Status is derived from sync_dashboard view.
116
109
  */
117
110
  getSyncRun(accountId: string, runStartedAt: Date): Promise<{
118
111
  accountId: string;
119
112
  runStartedAt: Date;
120
- status: string;
121
113
  maxConcurrent: number;
114
+ closedAt: Date | null;
122
115
  } | null>;
123
116
  /**
124
- * Mark a sync run as complete.
117
+ * Close a sync run (mark as done).
118
+ * Status (complete/error) is derived from object run states.
125
119
  */
126
- completeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
127
- /**
128
- * Mark a sync run as failed.
129
- */
130
- failSyncRun(accountId: string, runStartedAt: Date, errorMessage: string): Promise<void>;
120
+ closeSyncRun(accountId: string, runStartedAt: Date): Promise<void>;
131
121
  /**
132
122
  * Create object run entries for a sync run.
133
123
  * All objects start as 'pending'.
@@ -176,12 +166,18 @@ declare class PostgresClient {
176
166
  deleteSyncRuns(accountId: string): Promise<void>;
177
167
  /**
178
168
  * Mark an object sync as complete.
169
+ * Auto-closes the run when all objects are done.
179
170
  */
180
171
  completeObjectSync(accountId: string, runStartedAt: Date, object: string): Promise<void>;
181
172
  /**
182
173
  * Mark an object sync as failed.
174
+ * Auto-closes the run when all objects are done.
183
175
  */
184
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>;
185
181
  /**
186
182
  * Count running objects in a run.
187
183
  */
@@ -233,11 +229,9 @@ type StripeSyncConfig = {
233
229
  * Default: false
234
230
  */
235
231
  revalidateObjectsViaStripeApi?: Array<RevalidateEntity>;
236
- /**
237
- * Database adapter for database operations.
238
- * Use PgAdapter for Node.js or a custom adapter for other environments (e.g., Deno).
239
- */
240
- adapter: DatabaseAdapter;
232
+ /** @deprecated Use `poolConfig` instead. */
233
+ maxPostgresConnections?: number;
234
+ poolConfig: PoolConfig;
241
235
  logger?: Logger;
242
236
  /**
243
237
  * Maximum number of retry attempts for 429 rate limit errors.
@@ -579,6 +573,13 @@ declare class StripeSync {
579
573
  private fetchMissingEntities;
580
574
  }
581
575
 
576
+ type MigrationConfig = {
577
+ databaseUrl: string;
578
+ ssl?: ConnectionOptions;
579
+ logger?: Logger;
580
+ };
581
+ declare function runMigrations(config: MigrationConfig): Promise<void>;
582
+
582
583
  /**
583
584
  * Hashes a Stripe API key using SHA-256
584
585
  * Used to store API key hashes in the database for fast account lookups
@@ -589,14 +590,6 @@ declare class StripeSync {
589
590
  */
590
591
  declare function hashApiKey(apiKey: string): string;
591
592
 
592
- /**
593
- * Run database migrations using the provided adapter.
594
- *
595
- * @param adapter - Database adapter (PgAdapter or PostgresJsAdapter)
596
- * @param logger - Optional logger for migration progress
597
- */
598
- declare function runMigrations(adapter: DatabaseAdapter, logger?: Logger): Promise<void>;
599
-
600
593
  declare const VERSION: string;
601
594
 
602
- export { DatabaseAdapter, type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type RevalidateEntity, StripeSync, type StripeSyncConfig, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, hashApiKey, runMigrations };
595
+ export { type Logger, PostgresClient, type ProcessNextParams, type ProcessNextResult, type RevalidateEntity, StripeSync, type StripeSyncConfig, type Sync, type SyncBackfill, type SyncEntitlementsParams, type SyncFeaturesParams, type SyncObject, type SyncParams, VERSION, hashApiKey, runMigrations };