@paymentsdb/sync-engine 0.0.5 → 0.0.7
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/{chunk-HXSDJSKR.js → chunk-7DYBM7H3.js} +1 -1
- package/dist/{chunk-LB4HG4Q6.js → chunk-IQ64IUIL.js} +475 -4
- package/dist/{chunk-DZMKGCU5.js → chunk-LN6KHV6O.js} +2 -2
- package/dist/{chunk-Q3AGYUHN.js → chunk-OLHHINPH.js} +1 -1
- package/dist/cli/index.cjs +475 -4
- package/dist/cli/index.js +4 -4
- package/dist/cli/lib.cjs +475 -4
- package/dist/cli/lib.js +4 -4
- package/dist/index.cjs +475 -4
- package/dist/index.d.cts +40 -1
- package/dist/index.d.ts +40 -1
- package/dist/index.js +2 -2
- package/dist/supabase/index.cjs +1 -1
- package/dist/supabase/index.js +2 -2
- package/package.json +2 -2
package/dist/cli/index.cjs
CHANGED
|
@@ -33,7 +33,7 @@ var import_commander = require("commander");
|
|
|
33
33
|
// package.json
|
|
34
34
|
var package_default = {
|
|
35
35
|
name: "@paymentsdb/sync-engine",
|
|
36
|
-
version: "0.0.
|
|
36
|
+
version: "0.0.7",
|
|
37
37
|
private: false,
|
|
38
38
|
description: "Stripe Sync Engine to sync Stripe data to Postgres",
|
|
39
39
|
type: "module",
|
|
@@ -45501,6 +45501,13 @@ var StripeSync = class {
|
|
|
45501
45501
|
listFn: (p) => this.stripe.checkout.sessions.list(p),
|
|
45502
45502
|
upsertFn: (items, id) => this.upsertCheckoutSessions(items, id),
|
|
45503
45503
|
supportsCreatedFilter: true
|
|
45504
|
+
},
|
|
45505
|
+
_event_catchup: {
|
|
45506
|
+
order: 99,
|
|
45507
|
+
// Always runs last — catches missed webhook events
|
|
45508
|
+
listFn: (_p) => Promise.resolve({ data: [], has_more: false }),
|
|
45509
|
+
upsertFn: async () => [],
|
|
45510
|
+
supportsCreatedFilter: true
|
|
45504
45511
|
}
|
|
45505
45512
|
};
|
|
45506
45513
|
const maxOrder = Math.max(...Object.values(core).map((cfg) => cfg.order));
|
|
@@ -46267,7 +46274,8 @@ ${message}`;
|
|
|
46267
46274
|
credit_note: "credit_notes",
|
|
46268
46275
|
early_fraud_warning: "early_fraud_warnings",
|
|
46269
46276
|
refund: "refunds",
|
|
46270
|
-
checkout_sessions: "checkout_sessions"
|
|
46277
|
+
checkout_sessions: "checkout_sessions",
|
|
46278
|
+
_event_catchup: "_event_catchup"
|
|
46271
46279
|
};
|
|
46272
46280
|
return mapping[object] || object;
|
|
46273
46281
|
}
|
|
@@ -46278,11 +46286,16 @@ ${message}`;
|
|
|
46278
46286
|
*/
|
|
46279
46287
|
async fetchOnePage(object, accountId, resourceName, runStartedAt, cursor, pageCursor, params) {
|
|
46280
46288
|
const limit = 100;
|
|
46281
|
-
if (object === "payment_method"
|
|
46282
|
-
this.
|
|
46289
|
+
if (object === "payment_method") {
|
|
46290
|
+
return this.fetchOnePagePaymentMethods(accountId, resourceName, runStartedAt, cursor, pageCursor, params);
|
|
46291
|
+
}
|
|
46292
|
+
if (object === "tax_id") {
|
|
46283
46293
|
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
46284
46294
|
return { processed: 0, hasMore: false, runStartedAt };
|
|
46285
46295
|
}
|
|
46296
|
+
if (object === "_event_catchup") {
|
|
46297
|
+
return this.fetchOnePageEventCatchup(accountId, resourceName, runStartedAt, cursor, pageCursor);
|
|
46298
|
+
}
|
|
46286
46299
|
const config = this.resourceRegistry[object];
|
|
46287
46300
|
if (!config) {
|
|
46288
46301
|
throw new Error(`Unsupported object type for processNext: ${object}`);
|
|
@@ -46459,6 +46472,437 @@ ${message}`;
|
|
|
46459
46472
|
}
|
|
46460
46473
|
return { processed: entries.length, hasMore, runStartedAt };
|
|
46461
46474
|
}
|
|
46475
|
+
/**
|
|
46476
|
+
* Fetch payment methods by iterating customers in batches.
|
|
46477
|
+
*
|
|
46478
|
+
* Most customers have 1-2 PMs, so processing one customer per processNext call
|
|
46479
|
+
* would be extremely wasteful (10,000 customers = 10,000 worker round-trips).
|
|
46480
|
+
* Instead, each call fetches a batch of customers (sized by maxConcurrentCustomers,
|
|
46481
|
+
* default 10) and lists+upserts PMs for all of them concurrently.
|
|
46482
|
+
*
|
|
46483
|
+
* Cursor semantics:
|
|
46484
|
+
* - cursor: max customer `created` timestamp — filters to only new customers on subsequent runs
|
|
46485
|
+
* - pageCursor: last processed customer ID — tracks position in customer iteration
|
|
46486
|
+
*/
|
|
46487
|
+
async fetchOnePagePaymentMethods(accountId, resourceName, runStartedAt, cursor, pageCursor, params) {
|
|
46488
|
+
const batchSize = this.config.maxConcurrentCustomers ?? 10;
|
|
46489
|
+
try {
|
|
46490
|
+
const customerBatch = await this.findNextCustomerBatchForPmSync(
|
|
46491
|
+
accountId,
|
|
46492
|
+
pageCursor,
|
|
46493
|
+
cursor,
|
|
46494
|
+
batchSize
|
|
46495
|
+
);
|
|
46496
|
+
if (customerBatch.length === 0) {
|
|
46497
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
46498
|
+
return { processed: 0, hasMore: false, runStartedAt };
|
|
46499
|
+
}
|
|
46500
|
+
this.config.logger?.info(
|
|
46501
|
+
`processNext: fetching payment_methods for ${customerBatch.length} customers`
|
|
46502
|
+
);
|
|
46503
|
+
let totalProcessed = 0;
|
|
46504
|
+
await Promise.all(
|
|
46505
|
+
customerBatch.map(async (customer) => {
|
|
46506
|
+
const allPms = [];
|
|
46507
|
+
let hasMore = true;
|
|
46508
|
+
let startingAfter;
|
|
46509
|
+
while (hasMore) {
|
|
46510
|
+
const response = await this.stripe.paymentMethods.list({
|
|
46511
|
+
customer: customer.id,
|
|
46512
|
+
limit: 100,
|
|
46513
|
+
...startingAfter ? { starting_after: startingAfter } : {}
|
|
46514
|
+
});
|
|
46515
|
+
allPms.push(...response.data);
|
|
46516
|
+
hasMore = response.has_more;
|
|
46517
|
+
if (response.data.length > 0) {
|
|
46518
|
+
startingAfter = response.data[response.data.length - 1].id;
|
|
46519
|
+
}
|
|
46520
|
+
}
|
|
46521
|
+
if (allPms.length > 0) {
|
|
46522
|
+
await this.upsertPaymentMethods(allPms, accountId, params?.backfillRelatedEntities);
|
|
46523
|
+
totalProcessed += allPms.length;
|
|
46524
|
+
}
|
|
46525
|
+
})
|
|
46526
|
+
);
|
|
46527
|
+
if (totalProcessed > 0) {
|
|
46528
|
+
await this.postgresClient.incrementObjectProgress(
|
|
46529
|
+
accountId,
|
|
46530
|
+
runStartedAt,
|
|
46531
|
+
resourceName,
|
|
46532
|
+
totalProcessed
|
|
46533
|
+
);
|
|
46534
|
+
}
|
|
46535
|
+
const maxCreated = Math.max(...customerBatch.map((c) => c.created).filter((c) => c != null));
|
|
46536
|
+
if (maxCreated > 0) {
|
|
46537
|
+
await this.postgresClient.updateObjectCursor(
|
|
46538
|
+
accountId,
|
|
46539
|
+
runStartedAt,
|
|
46540
|
+
resourceName,
|
|
46541
|
+
String(maxCreated)
|
|
46542
|
+
);
|
|
46543
|
+
}
|
|
46544
|
+
const lastCustomerId = customerBatch[customerBatch.length - 1].id;
|
|
46545
|
+
const nextBatch = await this.findNextCustomerBatchForPmSync(
|
|
46546
|
+
accountId,
|
|
46547
|
+
lastCustomerId,
|
|
46548
|
+
cursor,
|
|
46549
|
+
1
|
|
46550
|
+
);
|
|
46551
|
+
if (nextBatch.length > 0) {
|
|
46552
|
+
await this.postgresClient.updateObjectPageCursor(
|
|
46553
|
+
accountId,
|
|
46554
|
+
runStartedAt,
|
|
46555
|
+
resourceName,
|
|
46556
|
+
lastCustomerId
|
|
46557
|
+
);
|
|
46558
|
+
return { processed: totalProcessed, hasMore: true, runStartedAt };
|
|
46559
|
+
}
|
|
46560
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
46561
|
+
return { processed: totalProcessed, hasMore: false, runStartedAt };
|
|
46562
|
+
} catch (error) {
|
|
46563
|
+
await this.postgresClient.failObjectSync(
|
|
46564
|
+
accountId,
|
|
46565
|
+
runStartedAt,
|
|
46566
|
+
resourceName,
|
|
46567
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
46568
|
+
);
|
|
46569
|
+
throw error;
|
|
46570
|
+
}
|
|
46571
|
+
}
|
|
46572
|
+
/**
|
|
46573
|
+
* Fetch the next batch of non-deleted customers for PM sync.
|
|
46574
|
+
* Returns customer IDs and created timestamps, ordered by id ASC.
|
|
46575
|
+
*/
|
|
46576
|
+
async findNextCustomerBatchForPmSync(accountId, afterCustomerId, cursor, limit) {
|
|
46577
|
+
let query = `SELECT id, created FROM stripe.customers WHERE _account_id = $1 AND COALESCE(deleted, false) <> true`;
|
|
46578
|
+
const params = [accountId];
|
|
46579
|
+
if (afterCustomerId) {
|
|
46580
|
+
params.push(afterCustomerId);
|
|
46581
|
+
query += ` AND id > $${params.length}`;
|
|
46582
|
+
}
|
|
46583
|
+
if (cursor && /^\d+$/.test(cursor)) {
|
|
46584
|
+
params.push(Number.parseInt(cursor, 10));
|
|
46585
|
+
query += ` AND created >= $${params.length}`;
|
|
46586
|
+
}
|
|
46587
|
+
params.push(limit);
|
|
46588
|
+
query += ` ORDER BY id ASC LIMIT $${params.length}`;
|
|
46589
|
+
const result = await this.postgresClient.query(query, params);
|
|
46590
|
+
return result.rows;
|
|
46591
|
+
}
|
|
46592
|
+
/**
|
|
46593
|
+
* Fetch one page of events from the Stripe Events API and reconcile affected entities.
|
|
46594
|
+
*
|
|
46595
|
+
* Instead of replaying events (which can resurrect deleted objects due to newest-first ordering),
|
|
46596
|
+
* we deduplicate by entity and re-fetch current state from Stripe for each affected entity.
|
|
46597
|
+
*
|
|
46598
|
+
* Cursor: event `created` timestamp. On first run, starts from the sync run's startedAt.
|
|
46599
|
+
* On subsequent runs, picks up where the last completed run left off.
|
|
46600
|
+
*/
|
|
46601
|
+
async fetchOnePageEventCatchup(accountId, resourceName, runStartedAt, cursor, pageCursor) {
|
|
46602
|
+
try {
|
|
46603
|
+
let createdGte;
|
|
46604
|
+
if (cursor && /^\d+$/.test(cursor)) {
|
|
46605
|
+
createdGte = Number.parseInt(cursor, 10);
|
|
46606
|
+
} else {
|
|
46607
|
+
createdGte = Math.floor(runStartedAt.getTime() / 1e3);
|
|
46608
|
+
}
|
|
46609
|
+
const thirtyDaysAgo = Math.floor(Date.now() / 1e3) - 30 * 24 * 60 * 60;
|
|
46610
|
+
if (createdGte < thirtyDaysAgo) {
|
|
46611
|
+
this.config.logger?.warn(
|
|
46612
|
+
`_event_catchup: cursor ${createdGte} is older than 30 days, clamping to ${thirtyDaysAgo}`
|
|
46613
|
+
);
|
|
46614
|
+
createdGte = thirtyDaysAgo;
|
|
46615
|
+
}
|
|
46616
|
+
const listParams = {
|
|
46617
|
+
limit: 100,
|
|
46618
|
+
created: { gte: createdGte }
|
|
46619
|
+
};
|
|
46620
|
+
if (pageCursor) {
|
|
46621
|
+
listParams.starting_after = pageCursor;
|
|
46622
|
+
}
|
|
46623
|
+
const response = await this.stripe.events.list(listParams);
|
|
46624
|
+
if (response.data.length === 0) {
|
|
46625
|
+
await this.postgresClient.updateObjectCursor(
|
|
46626
|
+
accountId,
|
|
46627
|
+
runStartedAt,
|
|
46628
|
+
resourceName,
|
|
46629
|
+
String(createdGte)
|
|
46630
|
+
);
|
|
46631
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
46632
|
+
return { processed: 0, hasMore: false, runStartedAt };
|
|
46633
|
+
}
|
|
46634
|
+
const entityMap = /* @__PURE__ */ new Map();
|
|
46635
|
+
for (const event of response.data) {
|
|
46636
|
+
const obj = event.data.object;
|
|
46637
|
+
if (!obj?.id || !obj?.object) continue;
|
|
46638
|
+
const key = `${obj.object}:${obj.id}`;
|
|
46639
|
+
const existing = entityMap.get(key);
|
|
46640
|
+
if (!existing || event.created > existing.created) {
|
|
46641
|
+
entityMap.set(key, event);
|
|
46642
|
+
}
|
|
46643
|
+
}
|
|
46644
|
+
const hardDeleteEventTypes = /* @__PURE__ */ new Set([
|
|
46645
|
+
"product.deleted",
|
|
46646
|
+
"price.deleted",
|
|
46647
|
+
"plan.deleted",
|
|
46648
|
+
"customer.deleted",
|
|
46649
|
+
"customer.tax_id.deleted"
|
|
46650
|
+
]);
|
|
46651
|
+
let processed = 0;
|
|
46652
|
+
let skipped = 0;
|
|
46653
|
+
const skipObjectTypes = /* @__PURE__ */ new Set(["tax_id"]);
|
|
46654
|
+
for (const [, event] of entityMap) {
|
|
46655
|
+
const obj = event.data.object;
|
|
46656
|
+
const eventType = event.type;
|
|
46657
|
+
if (skipObjectTypes.has(obj.object)) continue;
|
|
46658
|
+
try {
|
|
46659
|
+
if (!hardDeleteEventTypes.has(eventType)) {
|
|
46660
|
+
const tableName = eventObjectTypeToTable(obj.object);
|
|
46661
|
+
if (tableName) {
|
|
46662
|
+
const localRecord = await this.postgresClient.query(
|
|
46663
|
+
`SELECT "_last_synced_at" FROM stripe."${tableName}"
|
|
46664
|
+
WHERE id = $1 AND "_account_id" = $2 LIMIT 1`,
|
|
46665
|
+
[obj.id, accountId]
|
|
46666
|
+
);
|
|
46667
|
+
if (localRecord.rows.length > 0 && localRecord.rows[0]._last_synced_at != null) {
|
|
46668
|
+
const syncedAt = new Date(localRecord.rows[0]._last_synced_at).getTime() / 1e3;
|
|
46669
|
+
if (syncedAt >= event.created) {
|
|
46670
|
+
skipped++;
|
|
46671
|
+
continue;
|
|
46672
|
+
}
|
|
46673
|
+
}
|
|
46674
|
+
}
|
|
46675
|
+
}
|
|
46676
|
+
if (hardDeleteEventTypes.has(eventType)) {
|
|
46677
|
+
await this.handleEventCatchupDelete(obj.object, obj.id, accountId);
|
|
46678
|
+
} else {
|
|
46679
|
+
await this.handleEventCatchupUpsert(obj.object, obj.id, accountId);
|
|
46680
|
+
}
|
|
46681
|
+
processed++;
|
|
46682
|
+
} catch (err) {
|
|
46683
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
46684
|
+
this.config.logger?.warn(
|
|
46685
|
+
`_event_catchup: failed to process ${obj.object}:${obj.id} (event ${event.id}): ${errMsg}`
|
|
46686
|
+
);
|
|
46687
|
+
}
|
|
46688
|
+
}
|
|
46689
|
+
if (skipped > 0) {
|
|
46690
|
+
this.config.logger?.info(
|
|
46691
|
+
`_event_catchup: skipped ${skipped} entities already up-to-date, processed ${processed}`
|
|
46692
|
+
);
|
|
46693
|
+
}
|
|
46694
|
+
if (processed > 0) {
|
|
46695
|
+
await this.postgresClient.incrementObjectProgress(
|
|
46696
|
+
accountId,
|
|
46697
|
+
runStartedAt,
|
|
46698
|
+
resourceName,
|
|
46699
|
+
processed
|
|
46700
|
+
);
|
|
46701
|
+
}
|
|
46702
|
+
const maxCreated = Math.max(...response.data.map((e) => e.created));
|
|
46703
|
+
await this.postgresClient.updateObjectCursor(
|
|
46704
|
+
accountId,
|
|
46705
|
+
runStartedAt,
|
|
46706
|
+
resourceName,
|
|
46707
|
+
String(maxCreated)
|
|
46708
|
+
);
|
|
46709
|
+
const lastEventId = response.data[response.data.length - 1].id;
|
|
46710
|
+
if (response.has_more) {
|
|
46711
|
+
await this.postgresClient.updateObjectPageCursor(
|
|
46712
|
+
accountId,
|
|
46713
|
+
runStartedAt,
|
|
46714
|
+
resourceName,
|
|
46715
|
+
lastEventId
|
|
46716
|
+
);
|
|
46717
|
+
}
|
|
46718
|
+
if (!response.has_more) {
|
|
46719
|
+
await this.postgresClient.completeObjectSync(accountId, runStartedAt, resourceName);
|
|
46720
|
+
}
|
|
46721
|
+
return { processed, hasMore: response.has_more, runStartedAt };
|
|
46722
|
+
} catch (error) {
|
|
46723
|
+
await this.postgresClient.failObjectSync(
|
|
46724
|
+
accountId,
|
|
46725
|
+
runStartedAt,
|
|
46726
|
+
resourceName,
|
|
46727
|
+
error instanceof Error ? error.message : "Unknown error"
|
|
46728
|
+
);
|
|
46729
|
+
throw error;
|
|
46730
|
+
}
|
|
46731
|
+
}
|
|
46732
|
+
/**
|
|
46733
|
+
* Handle a delete for an entity discovered via event catch-up.
|
|
46734
|
+
* Maps Stripe object types to the appropriate delete method.
|
|
46735
|
+
*/
|
|
46736
|
+
async handleEventCatchupDelete(objectType, entityId, accountId) {
|
|
46737
|
+
switch (objectType) {
|
|
46738
|
+
case "product":
|
|
46739
|
+
await this.deleteProduct(entityId);
|
|
46740
|
+
break;
|
|
46741
|
+
case "price":
|
|
46742
|
+
await this.deletePrice(entityId);
|
|
46743
|
+
break;
|
|
46744
|
+
case "plan":
|
|
46745
|
+
await this.deletePlan(entityId);
|
|
46746
|
+
break;
|
|
46747
|
+
case "customer": {
|
|
46748
|
+
const deletedCustomer = {
|
|
46749
|
+
id: entityId,
|
|
46750
|
+
object: "customer",
|
|
46751
|
+
deleted: true
|
|
46752
|
+
};
|
|
46753
|
+
await this.upsertCustomers([deletedCustomer], accountId);
|
|
46754
|
+
break;
|
|
46755
|
+
}
|
|
46756
|
+
case "tax_id":
|
|
46757
|
+
await this.deleteTaxId(entityId);
|
|
46758
|
+
break;
|
|
46759
|
+
default:
|
|
46760
|
+
this.config.logger?.warn(
|
|
46761
|
+
`_event_catchup: no delete handler for object type "${objectType}", skipping ${entityId}`
|
|
46762
|
+
);
|
|
46763
|
+
}
|
|
46764
|
+
}
|
|
46765
|
+
/**
|
|
46766
|
+
* Handle an upsert for an entity discovered via event catch-up.
|
|
46767
|
+
* Re-fetches the current state from Stripe and upserts it.
|
|
46768
|
+
* If the entity has been deleted (404), falls back to the delete handler.
|
|
46769
|
+
*/
|
|
46770
|
+
async handleEventCatchupUpsert(objectType, entityId, accountId) {
|
|
46771
|
+
try {
|
|
46772
|
+
switch (objectType) {
|
|
46773
|
+
case "product": {
|
|
46774
|
+
const product = await this.stripe.products.retrieve(entityId);
|
|
46775
|
+
await this.upsertProducts([product], accountId);
|
|
46776
|
+
break;
|
|
46777
|
+
}
|
|
46778
|
+
case "price": {
|
|
46779
|
+
const price = await this.stripe.prices.retrieve(entityId);
|
|
46780
|
+
await this.upsertPrices([price], accountId);
|
|
46781
|
+
break;
|
|
46782
|
+
}
|
|
46783
|
+
case "plan": {
|
|
46784
|
+
const plan = await this.stripe.plans.retrieve(entityId);
|
|
46785
|
+
await this.upsertPlans([plan], accountId);
|
|
46786
|
+
break;
|
|
46787
|
+
}
|
|
46788
|
+
case "customer": {
|
|
46789
|
+
const customer = await this.stripe.customers.retrieve(entityId);
|
|
46790
|
+
await this.upsertCustomers([customer], accountId);
|
|
46791
|
+
break;
|
|
46792
|
+
}
|
|
46793
|
+
case "subscription": {
|
|
46794
|
+
const sub = await this.stripe.subscriptions.retrieve(entityId);
|
|
46795
|
+
await this.upsertSubscriptions([sub], accountId);
|
|
46796
|
+
break;
|
|
46797
|
+
}
|
|
46798
|
+
case "subscription_schedule": {
|
|
46799
|
+
const schedule = await this.stripe.subscriptionSchedules.retrieve(entityId);
|
|
46800
|
+
await this.upsertSubscriptionSchedules([schedule], accountId);
|
|
46801
|
+
break;
|
|
46802
|
+
}
|
|
46803
|
+
case "invoice": {
|
|
46804
|
+
const invoice = await this.stripe.invoices.retrieve(entityId);
|
|
46805
|
+
await this.upsertInvoices([invoice], accountId);
|
|
46806
|
+
break;
|
|
46807
|
+
}
|
|
46808
|
+
case "charge": {
|
|
46809
|
+
const charge = await this.stripe.charges.retrieve(entityId, {
|
|
46810
|
+
expand: ["balance_transaction"]
|
|
46811
|
+
});
|
|
46812
|
+
if (charge.balance_transaction && typeof charge.balance_transaction === "object") {
|
|
46813
|
+
await this.upsertBalanceTransactions(
|
|
46814
|
+
[charge.balance_transaction],
|
|
46815
|
+
accountId
|
|
46816
|
+
);
|
|
46817
|
+
}
|
|
46818
|
+
await this.upsertCharges([charge], accountId);
|
|
46819
|
+
break;
|
|
46820
|
+
}
|
|
46821
|
+
case "payment_intent": {
|
|
46822
|
+
const pi = await this.stripe.paymentIntents.retrieve(entityId);
|
|
46823
|
+
await this.upsertPaymentIntents([pi], accountId);
|
|
46824
|
+
break;
|
|
46825
|
+
}
|
|
46826
|
+
case "payment_method": {
|
|
46827
|
+
const pm = await this.stripe.paymentMethods.retrieve(entityId);
|
|
46828
|
+
await this.upsertPaymentMethods([pm], accountId);
|
|
46829
|
+
break;
|
|
46830
|
+
}
|
|
46831
|
+
case "setup_intent": {
|
|
46832
|
+
const si = await this.stripe.setupIntents.retrieve(entityId);
|
|
46833
|
+
await this.upsertSetupIntents([si], accountId);
|
|
46834
|
+
break;
|
|
46835
|
+
}
|
|
46836
|
+
case "dispute": {
|
|
46837
|
+
const dispute = await this.stripe.disputes.retrieve(entityId, {
|
|
46838
|
+
expand: ["balance_transactions"]
|
|
46839
|
+
});
|
|
46840
|
+
if (dispute.balance_transactions && Array.isArray(dispute.balance_transactions)) {
|
|
46841
|
+
const expandedBts = dispute.balance_transactions.filter(
|
|
46842
|
+
(bt) => typeof bt === "object"
|
|
46843
|
+
);
|
|
46844
|
+
if (expandedBts.length > 0) {
|
|
46845
|
+
await this.upsertBalanceTransactions(expandedBts, accountId);
|
|
46846
|
+
}
|
|
46847
|
+
}
|
|
46848
|
+
await this.upsertDisputes([dispute], accountId);
|
|
46849
|
+
break;
|
|
46850
|
+
}
|
|
46851
|
+
case "credit_note": {
|
|
46852
|
+
const cn = await this.stripe.creditNotes.retrieve(entityId);
|
|
46853
|
+
await this.upsertCreditNotes([cn], accountId);
|
|
46854
|
+
break;
|
|
46855
|
+
}
|
|
46856
|
+
case "refund": {
|
|
46857
|
+
const refund = await this.stripe.refunds.retrieve(entityId, {
|
|
46858
|
+
expand: ["balance_transaction"]
|
|
46859
|
+
});
|
|
46860
|
+
if (refund.balance_transaction && typeof refund.balance_transaction === "object") {
|
|
46861
|
+
await this.upsertBalanceTransactions(
|
|
46862
|
+
[refund.balance_transaction],
|
|
46863
|
+
accountId
|
|
46864
|
+
);
|
|
46865
|
+
}
|
|
46866
|
+
await this.upsertRefunds([refund], accountId);
|
|
46867
|
+
break;
|
|
46868
|
+
}
|
|
46869
|
+
case "tax_id": {
|
|
46870
|
+
const taxId = await this.stripe.taxIds.retrieve(entityId);
|
|
46871
|
+
await this.upsertTaxIds([taxId], accountId);
|
|
46872
|
+
break;
|
|
46873
|
+
}
|
|
46874
|
+
case "balance_transaction": {
|
|
46875
|
+
const bt = await this.stripe.balanceTransactions.retrieve(entityId);
|
|
46876
|
+
await this.upsertBalanceTransactions([bt], accountId);
|
|
46877
|
+
break;
|
|
46878
|
+
}
|
|
46879
|
+
case "checkout.session": {
|
|
46880
|
+
const session = await this.stripe.checkout.sessions.retrieve(entityId);
|
|
46881
|
+
await this.upsertCheckoutSessions([session], accountId);
|
|
46882
|
+
break;
|
|
46883
|
+
}
|
|
46884
|
+
case "radar.early_fraud_warning": {
|
|
46885
|
+
const efw = await this.stripe.radar.earlyFraudWarnings.retrieve(entityId);
|
|
46886
|
+
await this.upsertEarlyFraudWarning([efw], accountId);
|
|
46887
|
+
break;
|
|
46888
|
+
}
|
|
46889
|
+
default:
|
|
46890
|
+
this.config.logger?.warn(
|
|
46891
|
+
`_event_catchup: no upsert handler for object type "${objectType}", skipping ${entityId}`
|
|
46892
|
+
);
|
|
46893
|
+
}
|
|
46894
|
+
} catch (err) {
|
|
46895
|
+
const isNotFound = (err instanceof import_stripe3.default.errors.StripeInvalidRequestError || err instanceof import_stripe3.default.errors.StripeAPIError) && (err.code === "resource_missing" || err.statusCode === 404);
|
|
46896
|
+
if (isNotFound) {
|
|
46897
|
+
this.config.logger?.info(
|
|
46898
|
+
`_event_catchup: ${objectType}:${entityId} not found on Stripe, treating as deleted`
|
|
46899
|
+
);
|
|
46900
|
+
await this.handleEventCatchupDelete(objectType, entityId, accountId);
|
|
46901
|
+
return;
|
|
46902
|
+
}
|
|
46903
|
+
throw err;
|
|
46904
|
+
}
|
|
46905
|
+
}
|
|
46462
46906
|
/**
|
|
46463
46907
|
* Process all pages for all (or specified) object types until complete.
|
|
46464
46908
|
*
|
|
@@ -46532,6 +46976,7 @@ ${message}`;
|
|
|
46532
46976
|
};
|
|
46533
46977
|
}
|
|
46534
46978
|
applySyncBackfillResult(results, object, result) {
|
|
46979
|
+
if (object === "_event_catchup") return;
|
|
46535
46980
|
if (this.isSigmaResource(object)) {
|
|
46536
46981
|
results.sigma = results.sigma ?? {};
|
|
46537
46982
|
results.sigma[object] = result;
|
|
@@ -46567,6 +47012,9 @@ ${message}`;
|
|
|
46567
47012
|
case "setup_intent":
|
|
46568
47013
|
results.setupIntents = result;
|
|
46569
47014
|
break;
|
|
47015
|
+
case "payment_method":
|
|
47016
|
+
results.paymentMethods = result;
|
|
47017
|
+
break;
|
|
46570
47018
|
case "payment_intent":
|
|
46571
47019
|
results.paymentIntents = result;
|
|
46572
47020
|
break;
|
|
@@ -48074,6 +48522,29 @@ function chunkArray(array, chunkSize) {
|
|
|
48074
48522
|
}
|
|
48075
48523
|
return result;
|
|
48076
48524
|
}
|
|
48525
|
+
function eventObjectTypeToTable(objectType) {
|
|
48526
|
+
const mapping = {
|
|
48527
|
+
product: "products",
|
|
48528
|
+
price: "prices",
|
|
48529
|
+
plan: "plans",
|
|
48530
|
+
customer: "customers",
|
|
48531
|
+
subscription: "subscriptions",
|
|
48532
|
+
subscription_schedule: "subscription_schedules",
|
|
48533
|
+
invoice: "invoices",
|
|
48534
|
+
charge: "charges",
|
|
48535
|
+
balance_transaction: "balance_transactions",
|
|
48536
|
+
payment_intent: "payment_intents",
|
|
48537
|
+
payment_method: "payment_methods",
|
|
48538
|
+
setup_intent: "setup_intents",
|
|
48539
|
+
dispute: "disputes",
|
|
48540
|
+
credit_note: "credit_notes",
|
|
48541
|
+
refund: "refunds",
|
|
48542
|
+
tax_id: "tax_ids",
|
|
48543
|
+
"checkout.session": "checkout_sessions",
|
|
48544
|
+
"radar.early_fraud_warning": "early_fraud_warnings"
|
|
48545
|
+
};
|
|
48546
|
+
return mapping[objectType] ?? null;
|
|
48547
|
+
}
|
|
48077
48548
|
|
|
48078
48549
|
// src/database/migrate.ts
|
|
48079
48550
|
var import_pg2 = require("pg");
|
package/dist/cli/index.js
CHANGED
|
@@ -5,12 +5,12 @@ import {
|
|
|
5
5
|
migrateCommand,
|
|
6
6
|
syncCommand,
|
|
7
7
|
uninstallCommand
|
|
8
|
-
} from "../chunk-
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-
|
|
8
|
+
} from "../chunk-LN6KHV6O.js";
|
|
9
|
+
import "../chunk-IQ64IUIL.js";
|
|
10
|
+
import "../chunk-OLHHINPH.js";
|
|
11
11
|
import {
|
|
12
12
|
package_default
|
|
13
|
-
} from "../chunk-
|
|
13
|
+
} from "../chunk-7DYBM7H3.js";
|
|
14
14
|
|
|
15
15
|
// src/cli/index.ts
|
|
16
16
|
import { Command } from "commander";
|