stripe-experiment-sync 1.0.1 → 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 +52 -35
- package/dist/index.d.cts +12 -8
- package/dist/index.d.ts +12 -8
- package/dist/index.js +52 -35
- package/dist/migrations/0055_bigint_money_columns.sql +72 -0
- package/dist/migrations/0056_sync_run_closed_at.sql +53 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -45,7 +45,7 @@ var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
|
45
45
|
// package.json
|
|
46
46
|
var package_default = {
|
|
47
47
|
name: "stripe-experiment-sync",
|
|
48
|
-
version: "1.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",
|
|
@@ -442,12 +442,20 @@ var PostgresClient = class {
|
|
|
442
442
|
*/
|
|
443
443
|
async cancelStaleRuns(accountId) {
|
|
444
444
|
await this.query(
|
|
445
|
-
`UPDATE "${this.config.schema}"."
|
|
445
|
+
`UPDATE "${this.config.schema}"."_sync_obj_run" o
|
|
446
446
|
SET status = 'error',
|
|
447
447
|
error_message = 'Auto-cancelled: stale (no update in 5 min)',
|
|
448
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()
|
|
449
457
|
WHERE r."_account_id" = $1
|
|
450
|
-
AND r.
|
|
458
|
+
AND r.closed_at IS NULL
|
|
451
459
|
AND EXISTS (
|
|
452
460
|
SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
|
|
453
461
|
WHERE o."_account_id" = r."_account_id"
|
|
@@ -457,7 +465,7 @@ var PostgresClient = class {
|
|
|
457
465
|
SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
|
|
458
466
|
WHERE o."_account_id" = r."_account_id"
|
|
459
467
|
AND o.run_started_at = r.started_at
|
|
460
|
-
AND o.
|
|
468
|
+
AND o.status IN ('pending', 'running')
|
|
461
469
|
)`,
|
|
462
470
|
[accountId]
|
|
463
471
|
);
|
|
@@ -473,7 +481,7 @@ var PostgresClient = class {
|
|
|
473
481
|
await this.cancelStaleRuns(accountId);
|
|
474
482
|
const existing = await this.query(
|
|
475
483
|
`SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
|
|
476
|
-
WHERE "_account_id" = $1 AND
|
|
484
|
+
WHERE "_account_id" = $1 AND closed_at IS NULL`,
|
|
477
485
|
[accountId]
|
|
478
486
|
);
|
|
479
487
|
if (existing.rows.length > 0) {
|
|
@@ -502,7 +510,7 @@ var PostgresClient = class {
|
|
|
502
510
|
async getActiveSyncRun(accountId) {
|
|
503
511
|
const result = await this.query(
|
|
504
512
|
`SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
|
|
505
|
-
WHERE "_account_id" = $1 AND
|
|
513
|
+
WHERE "_account_id" = $1 AND closed_at IS NULL`,
|
|
506
514
|
[accountId]
|
|
507
515
|
);
|
|
508
516
|
if (result.rows.length === 0) return null;
|
|
@@ -510,11 +518,12 @@ var PostgresClient = class {
|
|
|
510
518
|
return { accountId: row._account_id, runStartedAt: row.started_at };
|
|
511
519
|
}
|
|
512
520
|
/**
|
|
513
|
-
* Get
|
|
521
|
+
* Get sync run config (for concurrency control).
|
|
522
|
+
* Status is derived from sync_dashboard view.
|
|
514
523
|
*/
|
|
515
524
|
async getSyncRun(accountId, runStartedAt) {
|
|
516
525
|
const result = await this.query(
|
|
517
|
-
`SELECT "_account_id", started_at,
|
|
526
|
+
`SELECT "_account_id", started_at, max_concurrent, closed_at
|
|
518
527
|
FROM "${this.config.schema}"."_sync_run"
|
|
519
528
|
WHERE "_account_id" = $1 AND started_at = $2`,
|
|
520
529
|
[accountId, runStartedAt]
|
|
@@ -524,32 +533,22 @@ var PostgresClient = class {
|
|
|
524
533
|
return {
|
|
525
534
|
accountId: row._account_id,
|
|
526
535
|
runStartedAt: row.started_at,
|
|
527
|
-
|
|
528
|
-
|
|
536
|
+
maxConcurrent: row.max_concurrent,
|
|
537
|
+
closedAt: row.closed_at
|
|
529
538
|
};
|
|
530
539
|
}
|
|
531
540
|
/**
|
|
532
|
-
*
|
|
541
|
+
* Close a sync run (mark as done).
|
|
542
|
+
* Status (complete/error) is derived from object run states.
|
|
533
543
|
*/
|
|
534
|
-
async
|
|
544
|
+
async closeSyncRun(accountId, runStartedAt) {
|
|
535
545
|
await this.query(
|
|
536
546
|
`UPDATE "${this.config.schema}"."_sync_run"
|
|
537
|
-
SET
|
|
538
|
-
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`,
|
|
539
549
|
[accountId, runStartedAt]
|
|
540
550
|
);
|
|
541
551
|
}
|
|
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
552
|
/**
|
|
554
553
|
* Create object run entries for a sync run.
|
|
555
554
|
* All objects start as 'pending'.
|
|
@@ -673,6 +672,7 @@ var PostgresClient = class {
|
|
|
673
672
|
}
|
|
674
673
|
/**
|
|
675
674
|
* Mark an object sync as complete.
|
|
675
|
+
* Auto-closes the run when all objects are done.
|
|
676
676
|
*/
|
|
677
677
|
async completeObjectSync(accountId, runStartedAt, object) {
|
|
678
678
|
await this.query(
|
|
@@ -681,9 +681,14 @@ var PostgresClient = class {
|
|
|
681
681
|
WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
|
|
682
682
|
[accountId, runStartedAt, object]
|
|
683
683
|
);
|
|
684
|
+
const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
|
|
685
|
+
if (allDone) {
|
|
686
|
+
await this.closeSyncRun(accountId, runStartedAt);
|
|
687
|
+
}
|
|
684
688
|
}
|
|
685
689
|
/**
|
|
686
690
|
* Mark an object sync as failed.
|
|
691
|
+
* Auto-closes the run when all objects are done.
|
|
687
692
|
*/
|
|
688
693
|
async failObjectSync(accountId, runStartedAt, object, errorMessage) {
|
|
689
694
|
await this.query(
|
|
@@ -692,6 +697,21 @@ var PostgresClient = class {
|
|
|
692
697
|
WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
|
|
693
698
|
[accountId, runStartedAt, object, errorMessage]
|
|
694
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;
|
|
695
715
|
}
|
|
696
716
|
/**
|
|
697
717
|
* Count running objects in a run.
|
|
@@ -1287,8 +1307,8 @@ var StripeSync = class {
|
|
|
1287
1307
|
// Depends on invoice
|
|
1288
1308
|
listFn: (p) => this.stripe.creditNotes.list(p),
|
|
1289
1309
|
upsertFn: (items, id, bf) => this.upsertCreditNotes(items, id, bf),
|
|
1290
|
-
supportsCreatedFilter:
|
|
1291
|
-
// credit_notes
|
|
1310
|
+
supportsCreatedFilter: true
|
|
1311
|
+
// credit_notes support created filter
|
|
1292
1312
|
},
|
|
1293
1313
|
dispute: {
|
|
1294
1314
|
order: 14,
|
|
@@ -1941,14 +1961,10 @@ var StripeSync = class {
|
|
|
1941
1961
|
}
|
|
1942
1962
|
}
|
|
1943
1963
|
}
|
|
1944
|
-
await this.postgresClient.
|
|
1964
|
+
await this.postgresClient.closeSyncRun(accountId, runStartedAt);
|
|
1945
1965
|
return results;
|
|
1946
1966
|
} catch (error) {
|
|
1947
|
-
await this.postgresClient.
|
|
1948
|
-
accountId,
|
|
1949
|
-
runStartedAt,
|
|
1950
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1951
|
-
);
|
|
1967
|
+
await this.postgresClient.closeSyncRun(accountId, runStartedAt);
|
|
1952
1968
|
throw error;
|
|
1953
1969
|
}
|
|
1954
1970
|
}
|
|
@@ -2479,12 +2495,13 @@ var StripeSync = class {
|
|
|
2479
2495
|
await this.postgresClient.tryStartObjectSync(accountId, runStartedAt, resourceName);
|
|
2480
2496
|
try {
|
|
2481
2497
|
const result = await fn(cursor, runStartedAt);
|
|
2482
|
-
await this.postgresClient.
|
|
2498
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
2483
2499
|
return result;
|
|
2484
2500
|
} catch (error) {
|
|
2485
|
-
await this.postgresClient.
|
|
2501
|
+
await this.postgresClient.failObjectSync(
|
|
2486
2502
|
accountId,
|
|
2487
2503
|
runStartedAt,
|
|
2504
|
+
resourceName,
|
|
2488
2505
|
error instanceof Error ? error.message : "Unknown error"
|
|
2489
2506
|
);
|
|
2490
2507
|
throw error;
|
package/dist/index.d.cts
CHANGED
|
@@ -104,22 +104,20 @@ declare class PostgresClient {
|
|
|
104
104
|
runStartedAt: Date;
|
|
105
105
|
} | null>;
|
|
106
106
|
/**
|
|
107
|
-
* Get
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
*/
|
package/dist/index.d.ts
CHANGED
|
@@ -104,22 +104,20 @@ declare class PostgresClient {
|
|
|
104
104
|
runStartedAt: Date;
|
|
105
105
|
} | null>;
|
|
106
106
|
/**
|
|
107
|
-
* Get
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
*/
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// package.json
|
|
2
2
|
var package_default = {
|
|
3
3
|
name: "stripe-experiment-sync",
|
|
4
|
-
version: "1.0.
|
|
4
|
+
version: "1.0.2",
|
|
5
5
|
private: false,
|
|
6
6
|
description: "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
7
7
|
type: "module",
|
|
@@ -398,12 +398,20 @@ var PostgresClient = class {
|
|
|
398
398
|
*/
|
|
399
399
|
async cancelStaleRuns(accountId) {
|
|
400
400
|
await this.query(
|
|
401
|
-
`UPDATE "${this.config.schema}"."
|
|
401
|
+
`UPDATE "${this.config.schema}"."_sync_obj_run" o
|
|
402
402
|
SET status = 'error',
|
|
403
403
|
error_message = 'Auto-cancelled: stale (no update in 5 min)',
|
|
404
404
|
completed_at = now()
|
|
405
|
+
WHERE o."_account_id" = $1
|
|
406
|
+
AND o.status = 'running'
|
|
407
|
+
AND o.updated_at < now() - interval '5 minutes'`,
|
|
408
|
+
[accountId]
|
|
409
|
+
);
|
|
410
|
+
await this.query(
|
|
411
|
+
`UPDATE "${this.config.schema}"."_sync_run" r
|
|
412
|
+
SET closed_at = now()
|
|
405
413
|
WHERE r."_account_id" = $1
|
|
406
|
-
AND r.
|
|
414
|
+
AND r.closed_at IS NULL
|
|
407
415
|
AND EXISTS (
|
|
408
416
|
SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
|
|
409
417
|
WHERE o."_account_id" = r."_account_id"
|
|
@@ -413,7 +421,7 @@ var PostgresClient = class {
|
|
|
413
421
|
SELECT 1 FROM "${this.config.schema}"."_sync_obj_run" o
|
|
414
422
|
WHERE o."_account_id" = r."_account_id"
|
|
415
423
|
AND o.run_started_at = r.started_at
|
|
416
|
-
AND o.
|
|
424
|
+
AND o.status IN ('pending', 'running')
|
|
417
425
|
)`,
|
|
418
426
|
[accountId]
|
|
419
427
|
);
|
|
@@ -429,7 +437,7 @@ var PostgresClient = class {
|
|
|
429
437
|
await this.cancelStaleRuns(accountId);
|
|
430
438
|
const existing = await this.query(
|
|
431
439
|
`SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
|
|
432
|
-
WHERE "_account_id" = $1 AND
|
|
440
|
+
WHERE "_account_id" = $1 AND closed_at IS NULL`,
|
|
433
441
|
[accountId]
|
|
434
442
|
);
|
|
435
443
|
if (existing.rows.length > 0) {
|
|
@@ -458,7 +466,7 @@ var PostgresClient = class {
|
|
|
458
466
|
async getActiveSyncRun(accountId) {
|
|
459
467
|
const result = await this.query(
|
|
460
468
|
`SELECT "_account_id", started_at FROM "${this.config.schema}"."_sync_run"
|
|
461
|
-
WHERE "_account_id" = $1 AND
|
|
469
|
+
WHERE "_account_id" = $1 AND closed_at IS NULL`,
|
|
462
470
|
[accountId]
|
|
463
471
|
);
|
|
464
472
|
if (result.rows.length === 0) return null;
|
|
@@ -466,11 +474,12 @@ var PostgresClient = class {
|
|
|
466
474
|
return { accountId: row._account_id, runStartedAt: row.started_at };
|
|
467
475
|
}
|
|
468
476
|
/**
|
|
469
|
-
* Get
|
|
477
|
+
* Get sync run config (for concurrency control).
|
|
478
|
+
* Status is derived from sync_dashboard view.
|
|
470
479
|
*/
|
|
471
480
|
async getSyncRun(accountId, runStartedAt) {
|
|
472
481
|
const result = await this.query(
|
|
473
|
-
`SELECT "_account_id", started_at,
|
|
482
|
+
`SELECT "_account_id", started_at, max_concurrent, closed_at
|
|
474
483
|
FROM "${this.config.schema}"."_sync_run"
|
|
475
484
|
WHERE "_account_id" = $1 AND started_at = $2`,
|
|
476
485
|
[accountId, runStartedAt]
|
|
@@ -480,32 +489,22 @@ var PostgresClient = class {
|
|
|
480
489
|
return {
|
|
481
490
|
accountId: row._account_id,
|
|
482
491
|
runStartedAt: row.started_at,
|
|
483
|
-
|
|
484
|
-
|
|
492
|
+
maxConcurrent: row.max_concurrent,
|
|
493
|
+
closedAt: row.closed_at
|
|
485
494
|
};
|
|
486
495
|
}
|
|
487
496
|
/**
|
|
488
|
-
*
|
|
497
|
+
* Close a sync run (mark as done).
|
|
498
|
+
* Status (complete/error) is derived from object run states.
|
|
489
499
|
*/
|
|
490
|
-
async
|
|
500
|
+
async closeSyncRun(accountId, runStartedAt) {
|
|
491
501
|
await this.query(
|
|
492
502
|
`UPDATE "${this.config.schema}"."_sync_run"
|
|
493
|
-
SET
|
|
494
|
-
WHERE "_account_id" = $1 AND started_at = $2`,
|
|
503
|
+
SET closed_at = now()
|
|
504
|
+
WHERE "_account_id" = $1 AND started_at = $2 AND closed_at IS NULL`,
|
|
495
505
|
[accountId, runStartedAt]
|
|
496
506
|
);
|
|
497
507
|
}
|
|
498
|
-
/**
|
|
499
|
-
* Mark a sync run as failed.
|
|
500
|
-
*/
|
|
501
|
-
async failSyncRun(accountId, runStartedAt, errorMessage) {
|
|
502
|
-
await this.query(
|
|
503
|
-
`UPDATE "${this.config.schema}"."_sync_run"
|
|
504
|
-
SET status = 'error', error_message = $3, completed_at = now()
|
|
505
|
-
WHERE "_account_id" = $1 AND started_at = $2`,
|
|
506
|
-
[accountId, runStartedAt, errorMessage]
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
508
|
/**
|
|
510
509
|
* Create object run entries for a sync run.
|
|
511
510
|
* All objects start as 'pending'.
|
|
@@ -629,6 +628,7 @@ var PostgresClient = class {
|
|
|
629
628
|
}
|
|
630
629
|
/**
|
|
631
630
|
* Mark an object sync as complete.
|
|
631
|
+
* Auto-closes the run when all objects are done.
|
|
632
632
|
*/
|
|
633
633
|
async completeObjectSync(accountId, runStartedAt, object) {
|
|
634
634
|
await this.query(
|
|
@@ -637,9 +637,14 @@ var PostgresClient = class {
|
|
|
637
637
|
WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
|
|
638
638
|
[accountId, runStartedAt, object]
|
|
639
639
|
);
|
|
640
|
+
const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
|
|
641
|
+
if (allDone) {
|
|
642
|
+
await this.closeSyncRun(accountId, runStartedAt);
|
|
643
|
+
}
|
|
640
644
|
}
|
|
641
645
|
/**
|
|
642
646
|
* Mark an object sync as failed.
|
|
647
|
+
* Auto-closes the run when all objects are done.
|
|
643
648
|
*/
|
|
644
649
|
async failObjectSync(accountId, runStartedAt, object, errorMessage) {
|
|
645
650
|
await this.query(
|
|
@@ -648,6 +653,21 @@ var PostgresClient = class {
|
|
|
648
653
|
WHERE "_account_id" = $1 AND run_started_at = $2 AND object = $3`,
|
|
649
654
|
[accountId, runStartedAt, object, errorMessage]
|
|
650
655
|
);
|
|
656
|
+
const allDone = await this.areAllObjectsComplete(accountId, runStartedAt);
|
|
657
|
+
if (allDone) {
|
|
658
|
+
await this.closeSyncRun(accountId, runStartedAt);
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
/**
|
|
662
|
+
* Check if any object in a run has errored.
|
|
663
|
+
*/
|
|
664
|
+
async hasAnyObjectErrors(accountId, runStartedAt) {
|
|
665
|
+
const result = await this.query(
|
|
666
|
+
`SELECT COUNT(*) as count FROM "${this.config.schema}"."_sync_obj_run"
|
|
667
|
+
WHERE "_account_id" = $1 AND run_started_at = $2 AND status = 'error'`,
|
|
668
|
+
[accountId, runStartedAt]
|
|
669
|
+
);
|
|
670
|
+
return parseInt(result.rows[0].count) > 0;
|
|
651
671
|
}
|
|
652
672
|
/**
|
|
653
673
|
* Count running objects in a run.
|
|
@@ -1243,8 +1263,8 @@ var StripeSync = class {
|
|
|
1243
1263
|
// Depends on invoice
|
|
1244
1264
|
listFn: (p) => this.stripe.creditNotes.list(p),
|
|
1245
1265
|
upsertFn: (items, id, bf) => this.upsertCreditNotes(items, id, bf),
|
|
1246
|
-
supportsCreatedFilter:
|
|
1247
|
-
// credit_notes
|
|
1266
|
+
supportsCreatedFilter: true
|
|
1267
|
+
// credit_notes support created filter
|
|
1248
1268
|
},
|
|
1249
1269
|
dispute: {
|
|
1250
1270
|
order: 14,
|
|
@@ -1897,14 +1917,10 @@ var StripeSync = class {
|
|
|
1897
1917
|
}
|
|
1898
1918
|
}
|
|
1899
1919
|
}
|
|
1900
|
-
await this.postgresClient.
|
|
1920
|
+
await this.postgresClient.closeSyncRun(accountId, runStartedAt);
|
|
1901
1921
|
return results;
|
|
1902
1922
|
} catch (error) {
|
|
1903
|
-
await this.postgresClient.
|
|
1904
|
-
accountId,
|
|
1905
|
-
runStartedAt,
|
|
1906
|
-
error instanceof Error ? error.message : "Unknown error"
|
|
1907
|
-
);
|
|
1923
|
+
await this.postgresClient.closeSyncRun(accountId, runStartedAt);
|
|
1908
1924
|
throw error;
|
|
1909
1925
|
}
|
|
1910
1926
|
}
|
|
@@ -2435,12 +2451,13 @@ var StripeSync = class {
|
|
|
2435
2451
|
await this.postgresClient.tryStartObjectSync(accountId, runStartedAt, resourceName);
|
|
2436
2452
|
try {
|
|
2437
2453
|
const result = await fn(cursor, runStartedAt);
|
|
2438
|
-
await this.postgresClient.
|
|
2454
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
2439
2455
|
return result;
|
|
2440
2456
|
} catch (error) {
|
|
2441
|
-
await this.postgresClient.
|
|
2457
|
+
await this.postgresClient.failObjectSync(
|
|
2442
2458
|
accountId,
|
|
2443
2459
|
runStartedAt,
|
|
2460
|
+
resourceName,
|
|
2444
2461
|
error instanceof Error ? error.message : "Unknown error"
|
|
2445
2462
|
);
|
|
2446
2463
|
throw error;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
-- Fix generated columns: must drop and recreate with ::bigint cast
|
|
2
|
+
-- Money columns that can overflow PostgreSQL integer max (~2.1 billion)
|
|
3
|
+
|
|
4
|
+
-- checkout_session_line_items
|
|
5
|
+
ALTER TABLE "stripe"."checkout_session_line_items" DROP COLUMN "amount_discount";
|
|
6
|
+
ALTER TABLE "stripe"."checkout_session_line_items" ADD COLUMN "amount_discount" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_discount')::bigint) STORED;
|
|
7
|
+
ALTER TABLE "stripe"."checkout_session_line_items" DROP COLUMN "amount_subtotal";
|
|
8
|
+
ALTER TABLE "stripe"."checkout_session_line_items" ADD COLUMN "amount_subtotal" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_subtotal')::bigint) STORED;
|
|
9
|
+
ALTER TABLE "stripe"."checkout_session_line_items" DROP COLUMN "amount_tax";
|
|
10
|
+
ALTER TABLE "stripe"."checkout_session_line_items" ADD COLUMN "amount_tax" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_tax')::bigint) STORED;
|
|
11
|
+
ALTER TABLE "stripe"."checkout_session_line_items" DROP COLUMN "amount_total";
|
|
12
|
+
ALTER TABLE "stripe"."checkout_session_line_items" ADD COLUMN "amount_total" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_total')::bigint) STORED;
|
|
13
|
+
|
|
14
|
+
-- checkout_sessions
|
|
15
|
+
ALTER TABLE "stripe"."checkout_sessions" DROP COLUMN "amount_subtotal";
|
|
16
|
+
ALTER TABLE "stripe"."checkout_sessions" ADD COLUMN "amount_subtotal" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_subtotal')::bigint) STORED;
|
|
17
|
+
ALTER TABLE "stripe"."checkout_sessions" DROP COLUMN "amount_total";
|
|
18
|
+
ALTER TABLE "stripe"."checkout_sessions" ADD COLUMN "amount_total" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_total')::bigint) STORED;
|
|
19
|
+
|
|
20
|
+
-- credit_notes
|
|
21
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "amount";
|
|
22
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "amount" bigint GENERATED ALWAYS AS ((_raw_data->>'amount')::bigint) STORED;
|
|
23
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "amount_shipping";
|
|
24
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "amount_shipping" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_shipping')::bigint) STORED;
|
|
25
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "discount_amount";
|
|
26
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "discount_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'discount_amount')::bigint) STORED;
|
|
27
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "out_of_band_amount";
|
|
28
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "out_of_band_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'out_of_band_amount')::bigint) STORED;
|
|
29
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "subtotal";
|
|
30
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "subtotal" bigint GENERATED ALWAYS AS ((_raw_data->>'subtotal')::bigint) STORED;
|
|
31
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "subtotal_excluding_tax";
|
|
32
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "subtotal_excluding_tax" bigint GENERATED ALWAYS AS ((_raw_data->>'subtotal_excluding_tax')::bigint) STORED;
|
|
33
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "total";
|
|
34
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "total" bigint GENERATED ALWAYS AS ((_raw_data->>'total')::bigint) STORED;
|
|
35
|
+
ALTER TABLE "stripe"."credit_notes" DROP COLUMN "total_excluding_tax";
|
|
36
|
+
ALTER TABLE "stripe"."credit_notes" ADD COLUMN "total_excluding_tax" bigint GENERATED ALWAYS AS ((_raw_data->>'total_excluding_tax')::bigint) STORED;
|
|
37
|
+
|
|
38
|
+
-- customers
|
|
39
|
+
ALTER TABLE "stripe"."customers" DROP COLUMN "balance";
|
|
40
|
+
ALTER TABLE "stripe"."customers" ADD COLUMN "balance" bigint GENERATED ALWAYS AS ((_raw_data->>'balance')::bigint) STORED;
|
|
41
|
+
|
|
42
|
+
-- invoices
|
|
43
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "ending_balance";
|
|
44
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "ending_balance" bigint GENERATED ALWAYS AS ((_raw_data->>'ending_balance')::bigint) STORED;
|
|
45
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "starting_balance";
|
|
46
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "starting_balance" bigint GENERATED ALWAYS AS ((_raw_data->>'starting_balance')::bigint) STORED;
|
|
47
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "subtotal";
|
|
48
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "subtotal" bigint GENERATED ALWAYS AS ((_raw_data->>'subtotal')::bigint) STORED;
|
|
49
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "tax";
|
|
50
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "tax" bigint GENERATED ALWAYS AS ((_raw_data->>'tax')::bigint) STORED;
|
|
51
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "post_payment_credit_notes_amount";
|
|
52
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "post_payment_credit_notes_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'post_payment_credit_notes_amount')::bigint) STORED;
|
|
53
|
+
ALTER TABLE "stripe"."invoices" DROP COLUMN "pre_payment_credit_notes_amount";
|
|
54
|
+
ALTER TABLE "stripe"."invoices" ADD COLUMN "pre_payment_credit_notes_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'pre_payment_credit_notes_amount')::bigint) STORED;
|
|
55
|
+
|
|
56
|
+
-- payment_intents
|
|
57
|
+
ALTER TABLE "stripe"."payment_intents" DROP COLUMN "amount";
|
|
58
|
+
ALTER TABLE "stripe"."payment_intents" ADD COLUMN "amount" bigint GENERATED ALWAYS AS ((_raw_data->>'amount')::bigint) STORED;
|
|
59
|
+
ALTER TABLE "stripe"."payment_intents" DROP COLUMN "amount_capturable";
|
|
60
|
+
ALTER TABLE "stripe"."payment_intents" ADD COLUMN "amount_capturable" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_capturable')::bigint) STORED;
|
|
61
|
+
ALTER TABLE "stripe"."payment_intents" DROP COLUMN "amount_received";
|
|
62
|
+
ALTER TABLE "stripe"."payment_intents" ADD COLUMN "amount_received" bigint GENERATED ALWAYS AS ((_raw_data->>'amount_received')::bigint) STORED;
|
|
63
|
+
ALTER TABLE "stripe"."payment_intents" DROP COLUMN "application_fee_amount";
|
|
64
|
+
ALTER TABLE "stripe"."payment_intents" ADD COLUMN "application_fee_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'application_fee_amount')::bigint) STORED;
|
|
65
|
+
|
|
66
|
+
-- prices
|
|
67
|
+
ALTER TABLE "stripe"."prices" DROP COLUMN "unit_amount";
|
|
68
|
+
ALTER TABLE "stripe"."prices" ADD COLUMN "unit_amount" bigint GENERATED ALWAYS AS ((_raw_data->>'unit_amount')::bigint) STORED;
|
|
69
|
+
|
|
70
|
+
-- refunds
|
|
71
|
+
ALTER TABLE "stripe"."refunds" DROP COLUMN "amount";
|
|
72
|
+
ALTER TABLE "stripe"."refunds" ADD COLUMN "amount" bigint GENERATED ALWAYS AS ((_raw_data->>'amount')::bigint) STORED;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
-- Add closed_at column to _sync_run
|
|
2
|
+
-- closed_at IS NULL means the run is still active
|
|
3
|
+
-- Status is derived from object states when closed_at IS NOT NULL
|
|
4
|
+
|
|
5
|
+
-- Step 1: Drop dependent view first
|
|
6
|
+
DROP VIEW IF EXISTS "stripe"."sync_dashboard";
|
|
7
|
+
|
|
8
|
+
-- Step 2: Drop the old constraint, status column, and completed_at column
|
|
9
|
+
ALTER TABLE "stripe"."_sync_run" DROP CONSTRAINT IF EXISTS one_active_run_per_account;
|
|
10
|
+
ALTER TABLE "stripe"."_sync_run" DROP COLUMN IF EXISTS status;
|
|
11
|
+
ALTER TABLE "stripe"."_sync_run" DROP COLUMN IF EXISTS completed_at;
|
|
12
|
+
|
|
13
|
+
-- Step 3: Add closed_at column
|
|
14
|
+
ALTER TABLE "stripe"."_sync_run" ADD COLUMN IF NOT EXISTS closed_at TIMESTAMPTZ;
|
|
15
|
+
|
|
16
|
+
-- Step 4: Create exclusion constraint (only one active run per account)
|
|
17
|
+
ALTER TABLE "stripe"."_sync_run"
|
|
18
|
+
ADD CONSTRAINT one_active_run_per_account
|
|
19
|
+
EXCLUDE ("_account_id" WITH =) WHERE (closed_at IS NULL);
|
|
20
|
+
|
|
21
|
+
-- Step 5: Recreate sync_dashboard view (run-level only, one row per run)
|
|
22
|
+
-- Base table: _sync_run (parent sync operation)
|
|
23
|
+
-- Child table: _sync_obj_run (individual object syncs)
|
|
24
|
+
CREATE OR REPLACE VIEW "stripe"."sync_dashboard" AS
|
|
25
|
+
SELECT
|
|
26
|
+
run."_account_id" as account_id,
|
|
27
|
+
run.started_at,
|
|
28
|
+
run.closed_at,
|
|
29
|
+
run.max_concurrent,
|
|
30
|
+
run.triggered_by,
|
|
31
|
+
run.updated_at,
|
|
32
|
+
-- Derived status from object states
|
|
33
|
+
CASE
|
|
34
|
+
WHEN run.closed_at IS NULL THEN 'running'
|
|
35
|
+
WHEN EXISTS (
|
|
36
|
+
SELECT 1 FROM "stripe"."_sync_obj_run" obj
|
|
37
|
+
WHERE obj."_account_id" = run."_account_id"
|
|
38
|
+
AND obj.run_started_at = run.started_at
|
|
39
|
+
AND obj.status = 'error'
|
|
40
|
+
) THEN 'error'
|
|
41
|
+
ELSE 'complete'
|
|
42
|
+
END as status,
|
|
43
|
+
-- First error message from failed objects
|
|
44
|
+
(SELECT obj.error_message FROM "stripe"."_sync_obj_run" obj
|
|
45
|
+
WHERE obj."_account_id" = run."_account_id"
|
|
46
|
+
AND obj.run_started_at = run.started_at
|
|
47
|
+
AND obj.status = 'error'
|
|
48
|
+
ORDER BY obj.object LIMIT 1) as error_message,
|
|
49
|
+
-- Total processed count across all objects
|
|
50
|
+
COALESCE((SELECT SUM(obj.processed_count) FROM "stripe"."_sync_obj_run" obj
|
|
51
|
+
WHERE obj."_account_id" = run."_account_id"
|
|
52
|
+
AND obj.run_started_at = run.started_at), 0) as processed_count
|
|
53
|
+
FROM "stripe"."_sync_run" run;
|