@@ -72,7 +72,9 @@ export class StripeSync {
72
72
case 'charge.refunded' :
73
73
case 'charge.succeeded' :
74
74
case 'charge.updated' : {
75
- const charge = event . data . object as Stripe . Charge
75
+ const charge = await this . fetchOrUseWebhookData ( event . data . object as Stripe . Charge , ( id ) =>
76
+ this . stripe . charges . retrieve ( id )
77
+ )
76
78
77
79
this . config . logger ?. info (
78
80
`Received webhook ${ event . id } : ${ event . type } for charge ${ charge . id } `
@@ -84,7 +86,10 @@ export class StripeSync {
84
86
case 'customer.created' :
85
87
case 'customer.deleted' :
86
88
case 'customer.updated' : {
87
- const customer = event . data . object as Stripe . Customer
89
+ const customer = await this . fetchOrUseWebhookData (
90
+ event . data . object as Stripe . Customer | Stripe . DeletedCustomer ,
91
+ ( id ) => this . stripe . customers . retrieve ( id )
92
+ )
88
93
89
94
this . config . logger ?. info (
90
95
`Received webhook ${ event . id } : ${ event . type } for customer ${ customer . id } `
@@ -101,7 +106,10 @@ export class StripeSync {
101
106
case 'customer.subscription.trial_will_end' :
102
107
case 'customer.subscription.resumed' :
103
108
case 'customer.subscription.updated' : {
104
- const subscription = event . data . object as Stripe . Subscription
109
+ const subscription = await this . fetchOrUseWebhookData (
110
+ event . data . object as Stripe . Subscription ,
111
+ ( id ) => this . stripe . subscriptions . retrieve ( id )
112
+ )
105
113
106
114
this . config . logger ?. info (
107
115
`Received webhook ${ event . id } : ${ event . type } for subscription ${ subscription . id } `
@@ -112,7 +120,9 @@ export class StripeSync {
112
120
}
113
121
case 'customer.tax_id.updated' :
114
122
case 'customer.tax_id.created' : {
115
- const taxId = event . data . object as Stripe . TaxId
123
+ const taxId = await this . fetchOrUseWebhookData ( event . data . object as Stripe . TaxId , ( id ) =>
124
+ this . stripe . taxIds . retrieve ( id )
125
+ )
116
126
117
127
this . config . logger ?. info (
118
128
`Received webhook ${ event . id } : ${ event . type } for taxId ${ taxId . id } `
@@ -144,7 +154,10 @@ export class StripeSync {
144
154
case 'invoice.voided' :
145
155
case 'invoice.marked_uncollectible' :
146
156
case 'invoice.updated' : {
147
- const invoice = event . data . object as Stripe . Invoice
157
+ const invoice = await this . fetchOrUseWebhookData (
158
+ event . data . object as Stripe . Invoice ,
159
+ ( id ) => this . stripe . invoices . retrieve ( id )
160
+ )
148
161
149
162
this . config . logger ?. info (
150
163
`Received webhook ${ event . id } : ${ event . type } for invoice ${ invoice . id } `
@@ -155,13 +168,25 @@ export class StripeSync {
155
168
}
156
169
case 'product.created' :
157
170
case 'product.updated' : {
158
- const product = event . data . object as Stripe . Product
171
+ try {
172
+ const product = await this . fetchOrUseWebhookData (
173
+ event . data . object as Stripe . Product ,
174
+ ( id ) => this . stripe . products . retrieve ( id )
175
+ )
159
176
160
- this . config . logger ?. info (
161
- `Received webhook ${ event . id } : ${ event . type } for product ${ product . id } `
162
- )
177
+ this . config . logger ?. info (
178
+ `Received webhook ${ event . id } : ${ event . type } for product ${ product . id } `
179
+ )
180
+
181
+ await this . upsertProducts ( [ product ] )
182
+ } catch ( err ) {
183
+ if ( err instanceof Stripe . errors . StripeAPIError && err . code === 'resource_missing' ) {
184
+ await this . deleteProduct ( event . data . object . id )
185
+ } else {
186
+ throw err
187
+ }
188
+ }
163
189
164
- await this . upsertProducts ( [ product ] )
165
190
break
166
191
}
167
192
case 'product.deleted' : {
@@ -176,13 +201,24 @@ export class StripeSync {
176
201
}
177
202
case 'price.created' :
178
203
case 'price.updated' : {
179
- const price = event . data . object as Stripe . Price
204
+ try {
205
+ const price = await this . fetchOrUseWebhookData ( event . data . object as Stripe . Price , ( id ) =>
206
+ this . stripe . prices . retrieve ( id )
207
+ )
180
208
181
- this . config . logger ?. info (
182
- `Received webhook ${ event . id } : ${ event . type } for price ${ price . id } `
183
- )
209
+ this . config . logger ?. info (
210
+ `Received webhook ${ event . id } : ${ event . type } for price ${ price . id } `
211
+ )
212
+
213
+ await this . upsertPrices ( [ price ] )
214
+ } catch ( err ) {
215
+ if ( err instanceof Stripe . errors . StripeAPIError && err . code === 'resource_missing' ) {
216
+ await this . deletePrice ( event . data . object . id )
217
+ } else {
218
+ throw err
219
+ }
220
+ }
184
221
185
- await this . upsertPrices ( [ price ] )
186
222
break
187
223
}
188
224
case 'price.deleted' : {
@@ -197,11 +233,24 @@ export class StripeSync {
197
233
}
198
234
case 'plan.created' :
199
235
case 'plan.updated' : {
200
- const plan = event . data . object as Stripe . Plan
236
+ try {
237
+ const plan = await this . fetchOrUseWebhookData ( event . data . object as Stripe . Plan , ( id ) =>
238
+ this . stripe . plans . retrieve ( id )
239
+ )
201
240
202
- this . config . logger ?. info ( `Received webhook ${ event . id } : ${ event . type } for plan ${ plan . id } ` )
241
+ this . config . logger ?. info (
242
+ `Received webhook ${ event . id } : ${ event . type } for plan ${ plan . id } `
243
+ )
244
+
245
+ await this . upsertPlans ( [ plan ] )
246
+ } catch ( err ) {
247
+ if ( err instanceof Stripe . errors . StripeAPIError && err . code === 'resource_missing' ) {
248
+ await this . deletePlan ( event . data . object . id )
249
+ } else {
250
+ throw err
251
+ }
252
+ }
203
253
204
- await this . upsertPlans ( [ plan ] )
205
254
break
206
255
}
207
256
case 'plan.deleted' : {
@@ -217,7 +266,10 @@ export class StripeSync {
217
266
case 'setup_intent.requires_action' :
218
267
case 'setup_intent.setup_failed' :
219
268
case 'setup_intent.succeeded' : {
220
- const setupIntent = event . data . object as Stripe . SetupIntent
269
+ const setupIntent = await this . fetchOrUseWebhookData (
270
+ event . data . object as Stripe . SetupIntent ,
271
+ ( id ) => this . stripe . setupIntents . retrieve ( id )
272
+ )
221
273
222
274
this . config . logger ?. info (
223
275
`Received webhook ${ event . id } : ${ event . type } for setupIntent ${ setupIntent . id } `
@@ -233,7 +285,10 @@ export class StripeSync {
233
285
case 'subscription_schedule.expiring' :
234
286
case 'subscription_schedule.released' :
235
287
case 'subscription_schedule.updated' : {
236
- const subscriptionSchedule = event . data . object as Stripe . SubscriptionSchedule
288
+ const subscriptionSchedule = await this . fetchOrUseWebhookData (
289
+ event . data . object as Stripe . SubscriptionSchedule ,
290
+ ( id ) => this . stripe . subscriptionSchedules . retrieve ( id )
291
+ )
237
292
238
293
this . config . logger ?. info (
239
294
`Received webhook ${ event . id } : ${ event . type } for subscriptionSchedule ${ subscriptionSchedule . id } `
@@ -246,7 +301,10 @@ export class StripeSync {
246
301
case 'payment_method.automatically_updated' :
247
302
case 'payment_method.detached' :
248
303
case 'payment_method.updated' : {
249
- const paymentMethod = event . data . object as Stripe . PaymentMethod
304
+ const paymentMethod = await this . fetchOrUseWebhookData (
305
+ event . data . object as Stripe . PaymentMethod ,
306
+ ( id ) => this . stripe . paymentMethods . retrieve ( id )
307
+ )
250
308
251
309
this . config . logger ?. info (
252
310
`Received webhook ${ event . id } : ${ event . type } for paymentMethod ${ paymentMethod . id } `
@@ -260,7 +318,10 @@ export class StripeSync {
260
318
case 'charge.dispute.funds_withdrawn' :
261
319
case 'charge.dispute.updated' :
262
320
case 'charge.dispute.closed' : {
263
- const dispute = event . data . object as Stripe . Dispute
321
+ const dispute = await this . fetchOrUseWebhookData (
322
+ event . data . object as Stripe . Dispute ,
323
+ ( id ) => this . stripe . disputes . retrieve ( id )
324
+ )
264
325
265
326
this . config . logger ?. info (
266
327
`Received webhook ${ event . id } : ${ event . type } for dispute ${ dispute . id } `
@@ -277,7 +338,10 @@ export class StripeSync {
277
338
case 'payment_intent.processing' :
278
339
case 'payment_intent.requires_action' :
279
340
case 'payment_intent.succeeded' : {
280
- const paymentIntent = event . data . object as Stripe . PaymentIntent
341
+ const paymentIntent = await this . fetchOrUseWebhookData (
342
+ event . data . object as Stripe . PaymentIntent ,
343
+ ( id ) => this . stripe . paymentIntents . retrieve ( id )
344
+ )
281
345
282
346
this . config . logger ?. info (
283
347
`Received webhook ${ event . id } : ${ event . type } for paymentIntent ${ paymentIntent . id } `
@@ -290,7 +354,10 @@ export class StripeSync {
290
354
case 'credit_note.created' :
291
355
case 'credit_note.updated' :
292
356
case 'credit_note.voided' : {
293
- const creditNote = event . data . object as Stripe . CreditNote
357
+ const creditNote = await this . fetchOrUseWebhookData (
358
+ event . data . object as Stripe . CreditNote ,
359
+ ( id ) => this . stripe . creditNotes . retrieve ( id )
360
+ )
294
361
295
362
this . config . logger ?. info (
296
363
`Received webhook ${ event . id } : ${ event . type } for creditNote ${ creditNote . id } `
@@ -305,6 +372,19 @@ export class StripeSync {
305
372
}
306
373
}
307
374
375
+ private async fetchOrUseWebhookData < T extends { id ?: string } > (
376
+ entity : T ,
377
+ fetchFn : ( id : string ) => Promise < T >
378
+ ) : Promise < T > {
379
+ if ( ! entity . id ) return entity
380
+
381
+ if ( this . config . revalidateEntityViaStripeApi ) {
382
+ return fetchFn ( entity . id )
383
+ }
384
+
385
+ return entity
386
+ }
387
+
308
388
async syncSingleEntity ( stripeId : string ) {
309
389
if ( stripeId . startsWith ( 'cus_' ) ) {
310
390
return this . stripe . customers . retrieve ( stripeId ) . then ( ( it ) => {
0 commit comments