@skillsmith/core 0.6.3 → 0.7.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/CHANGELOG.md +22 -1
- package/README.md +18 -0
- package/dist/.tsbuildinfo +1 -1
- package/dist/src/api/client.d.ts.map +1 -1
- package/dist/src/api/client.events.d.ts.map +1 -1
- package/dist/src/api/client.events.js +10 -1
- package/dist/src/api/client.events.js.map +1 -1
- package/dist/src/api/client.health.d.ts.map +1 -1
- package/dist/src/api/client.health.js +7 -1
- package/dist/src/api/client.health.js.map +1 -1
- package/dist/src/api/client.js +11 -1
- package/dist/src/api/client.js.map +1 -1
- package/dist/src/api/utils.d.ts +14 -3
- package/dist/src/api/utils.d.ts.map +1 -1
- package/dist/src/api/utils.js +14 -4
- package/dist/src/api/utils.js.map +1 -1
- package/dist/src/exports/services.d.ts +0 -1
- package/dist/src/exports/services.d.ts.map +1 -1
- package/dist/src/exports/services.js +14 -3
- package/dist/src/exports/services.js.map +1 -1
- package/dist/src/index.d.ts +2 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/types.d.ts +12 -0
- package/dist/src/types.d.ts.map +1 -1
- package/dist/tests/api/client.auth.test.js +50 -0
- package/dist/tests/api/client.auth.test.js.map +1 -1
- package/dist/tests/api/utils.test.js +7 -3
- package/dist/tests/api/utils.test.js.map +1 -1
- package/dist/tests/{billing/stripe-validators.test.d.ts → security/sanitization-stripe-ids.test.d.ts} +1 -1
- package/dist/tests/security/sanitization-stripe-ids.test.d.ts.map +1 -0
- package/dist/tests/{billing/stripe-validators.test.js → security/sanitization-stripe-ids.test.js} +1 -1
- package/dist/tests/security/sanitization-stripe-ids.test.js.map +1 -0
- package/dist/tests/shared.test.js.map +1 -1
- package/package.json +2 -8
- package/dist/src/billing/BillingService.d.ts +0 -101
- package/dist/src/billing/BillingService.d.ts.map +0 -1
- package/dist/src/billing/BillingService.helpers.d.ts +0 -15
- package/dist/src/billing/BillingService.helpers.d.ts.map +0 -1
- package/dist/src/billing/BillingService.helpers.js +0 -45
- package/dist/src/billing/BillingService.helpers.js.map +0 -1
- package/dist/src/billing/BillingService.js +0 -263
- package/dist/src/billing/BillingService.js.map +0 -1
- package/dist/src/billing/BillingService.types.d.ts +0 -52
- package/dist/src/billing/BillingService.types.d.ts.map +0 -1
- package/dist/src/billing/BillingService.types.js +0 -6
- package/dist/src/billing/BillingService.types.js.map +0 -1
- package/dist/src/billing/GDPRComplianceService.d.ts +0 -81
- package/dist/src/billing/GDPRComplianceService.d.ts.map +0 -1
- package/dist/src/billing/GDPRComplianceService.js +0 -361
- package/dist/src/billing/GDPRComplianceService.js.map +0 -1
- package/dist/src/billing/StripeClient.d.ts +0 -119
- package/dist/src/billing/StripeClient.d.ts.map +0 -1
- package/dist/src/billing/StripeClient.js +0 -405
- package/dist/src/billing/StripeClient.js.map +0 -1
- package/dist/src/billing/StripeReconciliationJob.d.ts +0 -50
- package/dist/src/billing/StripeReconciliationJob.d.ts.map +0 -1
- package/dist/src/billing/StripeReconciliationJob.js +0 -365
- package/dist/src/billing/StripeReconciliationJob.js.map +0 -1
- package/dist/src/billing/StripeWebhookHandler.d.ts +0 -49
- package/dist/src/billing/StripeWebhookHandler.d.ts.map +0 -1
- package/dist/src/billing/StripeWebhookHandler.js +0 -162
- package/dist/src/billing/StripeWebhookHandler.js.map +0 -1
- package/dist/src/billing/gdpr-types.d.ts +0 -103
- package/dist/src/billing/gdpr-types.d.ts.map +0 -1
- package/dist/src/billing/gdpr-types.js +0 -7
- package/dist/src/billing/gdpr-types.js.map +0 -1
- package/dist/src/billing/index.d.ts +0 -18
- package/dist/src/billing/index.d.ts.map +0 -1
- package/dist/src/billing/index.js +0 -19
- package/dist/src/billing/index.js.map +0 -1
- package/dist/src/billing/reconciliation-helpers.d.ts +0 -16
- package/dist/src/billing/reconciliation-helpers.d.ts.map +0 -1
- package/dist/src/billing/reconciliation-helpers.js +0 -53
- package/dist/src/billing/reconciliation-helpers.js.map +0 -1
- package/dist/src/billing/reconciliation-types.d.ts +0 -71
- package/dist/src/billing/reconciliation-types.d.ts.map +0 -1
- package/dist/src/billing/reconciliation-types.js +0 -7
- package/dist/src/billing/reconciliation-types.js.map +0 -1
- package/dist/src/billing/stripe-client-types.d.ts +0 -45
- package/dist/src/billing/stripe-client-types.d.ts.map +0 -1
- package/dist/src/billing/stripe-client-types.js +0 -7
- package/dist/src/billing/stripe-client-types.js.map +0 -1
- package/dist/src/billing/stripe-helpers.d.ts +0 -17
- package/dist/src/billing/stripe-helpers.d.ts.map +0 -1
- package/dist/src/billing/stripe-helpers.js +0 -50
- package/dist/src/billing/stripe-helpers.js.map +0 -1
- package/dist/src/billing/types.d.ts +0 -266
- package/dist/src/billing/types.d.ts.map +0 -1
- package/dist/src/billing/types.js +0 -23
- package/dist/src/billing/types.js.map +0 -1
- package/dist/src/billing/webhook-handlers.d.ts +0 -56
- package/dist/src/billing/webhook-handlers.d.ts.map +0 -1
- package/dist/src/billing/webhook-handlers.js +0 -303
- package/dist/src/billing/webhook-handlers.js.map +0 -1
- package/dist/src/billing/webhook-types.d.ts +0 -42
- package/dist/src/billing/webhook-types.d.ts.map +0 -1
- package/dist/src/billing/webhook-types.js +0 -7
- package/dist/src/billing/webhook-types.js.map +0 -1
- package/dist/tests/billing/BillingService.test.d.ts +0 -7
- package/dist/tests/billing/BillingService.test.d.ts.map +0 -1
- package/dist/tests/billing/BillingService.test.js +0 -168
- package/dist/tests/billing/BillingService.test.js.map +0 -1
- package/dist/tests/billing/GDPRCompliance.test.d.ts +0 -7
- package/dist/tests/billing/GDPRCompliance.test.d.ts.map +0 -1
- package/dist/tests/billing/GDPRCompliance.test.js +0 -380
- package/dist/tests/billing/GDPRCompliance.test.js.map +0 -1
- package/dist/tests/billing/StripeClient.test.d.ts +0 -18
- package/dist/tests/billing/StripeClient.test.d.ts.map +0 -1
- package/dist/tests/billing/StripeClient.test.js +0 -566
- package/dist/tests/billing/StripeClient.test.js.map +0 -1
- package/dist/tests/billing/StripeReconciliation.test.d.ts +0 -7
- package/dist/tests/billing/StripeReconciliation.test.d.ts.map +0 -1
- package/dist/tests/billing/StripeReconciliation.test.js +0 -266
- package/dist/tests/billing/StripeReconciliation.test.js.map +0 -1
- package/dist/tests/billing/StripeWebhookHandler.test.d.ts +0 -16
- package/dist/tests/billing/StripeWebhookHandler.test.d.ts.map +0 -1
- package/dist/tests/billing/StripeWebhookHandler.test.js +0 -240
- package/dist/tests/billing/StripeWebhookHandler.test.js.map +0 -1
- package/dist/tests/billing/stripe-helpers.test.d.ts +0 -7
- package/dist/tests/billing/stripe-helpers.test.d.ts.map +0 -1
- package/dist/tests/billing/stripe-helpers.test.js +0 -91
- package/dist/tests/billing/stripe-helpers.test.js.map +0 -1
- package/dist/tests/billing/stripe-validators.test.d.ts.map +0 -1
- package/dist/tests/billing/stripe-validators.test.js.map +0 -1
- package/dist/tests/billing/webhook-handlers.test.d.ts +0 -16
- package/dist/tests/billing/webhook-handlers.test.d.ts.map +0 -1
- package/dist/tests/billing/webhook-handlers.test.js +0 -519
- package/dist/tests/billing/webhook-handlers.test.js.map +0 -1
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SMI-1069: Stripe Reconciliation Job
|
|
3
|
-
*
|
|
4
|
-
* Periodically reconciles local subscription and invoice data with Stripe.
|
|
5
|
-
* Identifies and reports discrepancies to ensure data consistency.
|
|
6
|
-
*
|
|
7
|
-
* Features:
|
|
8
|
-
* - Subscription status sync
|
|
9
|
-
* - Invoice status verification
|
|
10
|
-
* - Missing data detection
|
|
11
|
-
* - Automatic correction (optional)
|
|
12
|
-
* - Detailed reporting
|
|
13
|
-
*/
|
|
14
|
-
import { createLogger } from '../utils/logger.js';
|
|
15
|
-
import { mapStripeStatus, mapInvoiceStatus } from './reconciliation-helpers.js';
|
|
16
|
-
const logger = createLogger('StripeReconciliation');
|
|
17
|
-
// ============================================================================
|
|
18
|
-
// StripeReconciliationJob Class
|
|
19
|
-
// ============================================================================
|
|
20
|
-
/**
|
|
21
|
-
* Stripe Reconciliation Job
|
|
22
|
-
*
|
|
23
|
-
* @example
|
|
24
|
-
* ```typescript
|
|
25
|
-
* const job = new StripeReconciliationJob({
|
|
26
|
-
* stripeClient,
|
|
27
|
-
* db,
|
|
28
|
-
* autoFix: true,
|
|
29
|
-
* });
|
|
30
|
-
*
|
|
31
|
-
* // Run reconciliation
|
|
32
|
-
* const result = await job.run();
|
|
33
|
-
* console.log(`Found ${result.discrepancies.length} discrepancies`);
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export class StripeReconciliationJob {
|
|
37
|
-
stripe;
|
|
38
|
-
db;
|
|
39
|
-
autoFix;
|
|
40
|
-
batchSize;
|
|
41
|
-
constructor(config) {
|
|
42
|
-
this.stripe = config.stripeClient;
|
|
43
|
-
this.db = config.db;
|
|
44
|
-
this.autoFix = config.autoFix ?? false;
|
|
45
|
-
this.batchSize = config.batchSize ?? 100;
|
|
46
|
-
logger.info('Stripe reconciliation job initialized', {
|
|
47
|
-
autoFix: this.autoFix,
|
|
48
|
-
batchSize: this.batchSize,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
// ==========================================================================
|
|
52
|
-
// Main Entry Point
|
|
53
|
-
// ==========================================================================
|
|
54
|
-
/**
|
|
55
|
-
* Run the reconciliation job
|
|
56
|
-
*/
|
|
57
|
-
async run() {
|
|
58
|
-
const startedAt = new Date();
|
|
59
|
-
const discrepancies = [];
|
|
60
|
-
const errors = [];
|
|
61
|
-
let subscriptionsChecked = 0;
|
|
62
|
-
let invoicesChecked = 0;
|
|
63
|
-
let discrepanciesFixed = 0;
|
|
64
|
-
logger.info('Starting Stripe reconciliation job');
|
|
65
|
-
try {
|
|
66
|
-
// 1. Get all local subscriptions with Stripe IDs
|
|
67
|
-
const localSubscriptions = this.getLocalSubscriptions();
|
|
68
|
-
subscriptionsChecked = localSubscriptions.length;
|
|
69
|
-
// 2. Reconcile each subscription
|
|
70
|
-
for (const local of localSubscriptions) {
|
|
71
|
-
try {
|
|
72
|
-
const subDiscrepancies = await this.reconcileSubscription(local);
|
|
73
|
-
discrepancies.push(...subDiscrepancies);
|
|
74
|
-
}
|
|
75
|
-
catch (error) {
|
|
76
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
77
|
-
errors.push(`Subscription ${local.stripeSubscriptionId}: ${errorMsg}`);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
// 3. Reconcile invoices
|
|
81
|
-
const localInvoices = this.getLocalInvoices();
|
|
82
|
-
invoicesChecked = localInvoices.length;
|
|
83
|
-
for (const invoice of localInvoices) {
|
|
84
|
-
try {
|
|
85
|
-
const invDiscrepancies = await this.reconcileInvoice(invoice);
|
|
86
|
-
discrepancies.push(...invDiscrepancies);
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
90
|
-
errors.push(`Invoice ${invoice.stripeInvoiceId}: ${errorMsg}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
// 4. Apply fixes if autoFix is enabled
|
|
94
|
-
if (this.autoFix) {
|
|
95
|
-
for (const discrepancy of discrepancies) {
|
|
96
|
-
if (this.fixDiscrepancy(discrepancy)) {
|
|
97
|
-
discrepancy.fixed = true;
|
|
98
|
-
discrepanciesFixed++;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
105
|
-
errors.push(`Job failed: ${errorMsg}`);
|
|
106
|
-
logger.error('Reconciliation job failed', undefined, { error: errorMsg });
|
|
107
|
-
}
|
|
108
|
-
const completedAt = new Date();
|
|
109
|
-
const result = {
|
|
110
|
-
success: errors.length === 0,
|
|
111
|
-
startedAt: startedAt.toISOString(),
|
|
112
|
-
completedAt: completedAt.toISOString(),
|
|
113
|
-
durationMs: completedAt.getTime() - startedAt.getTime(),
|
|
114
|
-
stats: {
|
|
115
|
-
subscriptionsChecked,
|
|
116
|
-
invoicesChecked,
|
|
117
|
-
discrepanciesFound: discrepancies.length,
|
|
118
|
-
discrepanciesFixed,
|
|
119
|
-
},
|
|
120
|
-
discrepancies,
|
|
121
|
-
errors,
|
|
122
|
-
};
|
|
123
|
-
logger.info('Stripe reconciliation job completed', {
|
|
124
|
-
success: result.success,
|
|
125
|
-
subscriptionsChecked,
|
|
126
|
-
invoicesChecked,
|
|
127
|
-
discrepanciesFound: discrepancies.length,
|
|
128
|
-
discrepanciesFixed,
|
|
129
|
-
durationMs: result.durationMs,
|
|
130
|
-
});
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
133
|
-
// ==========================================================================
|
|
134
|
-
// Subscription Reconciliation
|
|
135
|
-
// ==========================================================================
|
|
136
|
-
getLocalSubscriptions() {
|
|
137
|
-
return this.db
|
|
138
|
-
.prepare(`SELECT
|
|
139
|
-
id,
|
|
140
|
-
customer_id as customerId,
|
|
141
|
-
stripe_subscription_id as stripeSubscriptionId,
|
|
142
|
-
stripe_customer_id as stripeCustomerId,
|
|
143
|
-
tier,
|
|
144
|
-
status,
|
|
145
|
-
seat_count as seatCount,
|
|
146
|
-
current_period_start as currentPeriodStart,
|
|
147
|
-
current_period_end as currentPeriodEnd
|
|
148
|
-
FROM user_subscriptions
|
|
149
|
-
WHERE stripe_subscription_id IS NOT NULL
|
|
150
|
-
LIMIT ?`)
|
|
151
|
-
.all(this.batchSize);
|
|
152
|
-
}
|
|
153
|
-
async reconcileSubscription(local) {
|
|
154
|
-
const discrepancies = [];
|
|
155
|
-
// Fetch from Stripe
|
|
156
|
-
const stripeSubscription = await this.stripe.getSubscription(local.stripeSubscriptionId);
|
|
157
|
-
if (!stripeSubscription) {
|
|
158
|
-
discrepancies.push({
|
|
159
|
-
type: 'missing_stripe',
|
|
160
|
-
entityType: 'subscription',
|
|
161
|
-
entityId: local.id,
|
|
162
|
-
stripeId: local.stripeSubscriptionId,
|
|
163
|
-
localValue: local.status,
|
|
164
|
-
stripeValue: null,
|
|
165
|
-
description: 'Subscription exists locally but not in Stripe',
|
|
166
|
-
fixed: false,
|
|
167
|
-
});
|
|
168
|
-
return discrepancies;
|
|
169
|
-
}
|
|
170
|
-
// Compare status
|
|
171
|
-
const stripeStatus = mapStripeStatus(stripeSubscription.status);
|
|
172
|
-
if (local.status !== stripeStatus) {
|
|
173
|
-
discrepancies.push({
|
|
174
|
-
type: 'status_mismatch',
|
|
175
|
-
entityType: 'subscription',
|
|
176
|
-
entityId: local.id,
|
|
177
|
-
stripeId: local.stripeSubscriptionId,
|
|
178
|
-
localValue: local.status,
|
|
179
|
-
stripeValue: stripeStatus,
|
|
180
|
-
description: `Status mismatch: local=${local.status}, stripe=${stripeStatus}`,
|
|
181
|
-
fixed: false,
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
// Compare tier (from metadata)
|
|
185
|
-
const stripeTier = stripeSubscription.metadata?.tier;
|
|
186
|
-
if (stripeTier && local.tier !== stripeTier) {
|
|
187
|
-
discrepancies.push({
|
|
188
|
-
type: 'tier_mismatch',
|
|
189
|
-
entityType: 'subscription',
|
|
190
|
-
entityId: local.id,
|
|
191
|
-
stripeId: local.stripeSubscriptionId,
|
|
192
|
-
localValue: local.tier,
|
|
193
|
-
stripeValue: stripeTier,
|
|
194
|
-
description: `Tier mismatch: local=${local.tier}, stripe=${stripeTier}`,
|
|
195
|
-
fixed: false,
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
// Compare seat count
|
|
199
|
-
const stripeQuantity = stripeSubscription.items.data[0]?.quantity ?? 1;
|
|
200
|
-
if (local.seatCount !== stripeQuantity) {
|
|
201
|
-
discrepancies.push({
|
|
202
|
-
type: 'seat_count_mismatch',
|
|
203
|
-
entityType: 'subscription',
|
|
204
|
-
entityId: local.id,
|
|
205
|
-
stripeId: local.stripeSubscriptionId,
|
|
206
|
-
localValue: local.seatCount,
|
|
207
|
-
stripeValue: stripeQuantity,
|
|
208
|
-
description: `Seat count mismatch: local=${local.seatCount}, stripe=${stripeQuantity}`,
|
|
209
|
-
fixed: false,
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
|
-
return discrepancies;
|
|
213
|
-
}
|
|
214
|
-
// ==========================================================================
|
|
215
|
-
// Invoice Reconciliation
|
|
216
|
-
// ==========================================================================
|
|
217
|
-
getLocalInvoices() {
|
|
218
|
-
return this.db
|
|
219
|
-
.prepare(`SELECT
|
|
220
|
-
id,
|
|
221
|
-
customer_id as customerId,
|
|
222
|
-
stripe_invoice_id as stripeInvoiceId,
|
|
223
|
-
amount_cents as amountCents,
|
|
224
|
-
status
|
|
225
|
-
FROM invoices
|
|
226
|
-
WHERE stripe_invoice_id IS NOT NULL
|
|
227
|
-
LIMIT ?`)
|
|
228
|
-
.all(this.batchSize);
|
|
229
|
-
}
|
|
230
|
-
async reconcileInvoice(local) {
|
|
231
|
-
const discrepancies = [];
|
|
232
|
-
// Fetch from Stripe
|
|
233
|
-
const stripeInvoice = await this.stripe.getInvoice(local.stripeInvoiceId);
|
|
234
|
-
if (!stripeInvoice) {
|
|
235
|
-
discrepancies.push({
|
|
236
|
-
type: 'missing_stripe',
|
|
237
|
-
entityType: 'invoice',
|
|
238
|
-
entityId: local.id,
|
|
239
|
-
stripeId: local.stripeInvoiceId,
|
|
240
|
-
localValue: local.status,
|
|
241
|
-
stripeValue: null,
|
|
242
|
-
description: 'Invoice exists locally but not in Stripe',
|
|
243
|
-
fixed: false,
|
|
244
|
-
});
|
|
245
|
-
return discrepancies;
|
|
246
|
-
}
|
|
247
|
-
// Compare status
|
|
248
|
-
const stripeStatus = mapInvoiceStatus(stripeInvoice.status);
|
|
249
|
-
if (local.status !== stripeStatus) {
|
|
250
|
-
discrepancies.push({
|
|
251
|
-
type: 'invoice_status_mismatch',
|
|
252
|
-
entityType: 'invoice',
|
|
253
|
-
entityId: local.id,
|
|
254
|
-
stripeId: local.stripeInvoiceId,
|
|
255
|
-
localValue: local.status,
|
|
256
|
-
stripeValue: stripeStatus,
|
|
257
|
-
description: `Invoice status mismatch: local=${local.status}, stripe=${stripeStatus}`,
|
|
258
|
-
fixed: false,
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
// Compare amount
|
|
262
|
-
const stripeAmount = stripeInvoice.amount_paid ?? stripeInvoice.amount_due;
|
|
263
|
-
if (local.amountCents !== stripeAmount) {
|
|
264
|
-
discrepancies.push({
|
|
265
|
-
type: 'invoice_amount_mismatch',
|
|
266
|
-
entityType: 'invoice',
|
|
267
|
-
entityId: local.id,
|
|
268
|
-
stripeId: local.stripeInvoiceId,
|
|
269
|
-
localValue: local.amountCents,
|
|
270
|
-
stripeValue: stripeAmount,
|
|
271
|
-
description: `Invoice amount mismatch: local=${local.amountCents}, stripe=${stripeAmount}`,
|
|
272
|
-
fixed: false,
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
return discrepancies;
|
|
276
|
-
}
|
|
277
|
-
// ==========================================================================
|
|
278
|
-
// Fix Discrepancies
|
|
279
|
-
// ==========================================================================
|
|
280
|
-
fixDiscrepancy(discrepancy) {
|
|
281
|
-
try {
|
|
282
|
-
if (discrepancy.entityType === 'subscription') {
|
|
283
|
-
return this.fixSubscriptionDiscrepancy(discrepancy);
|
|
284
|
-
}
|
|
285
|
-
else if (discrepancy.entityType === 'invoice') {
|
|
286
|
-
return this.fixInvoiceDiscrepancy(discrepancy);
|
|
287
|
-
}
|
|
288
|
-
return false;
|
|
289
|
-
}
|
|
290
|
-
catch (error) {
|
|
291
|
-
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
292
|
-
logger.error('Failed to fix discrepancy', undefined, {
|
|
293
|
-
type: discrepancy.type,
|
|
294
|
-
entityId: discrepancy.entityId,
|
|
295
|
-
error: errorMsg,
|
|
296
|
-
});
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
fixSubscriptionDiscrepancy(discrepancy) {
|
|
301
|
-
switch (discrepancy.type) {
|
|
302
|
-
case 'status_mismatch':
|
|
303
|
-
this.db
|
|
304
|
-
.prepare(`UPDATE user_subscriptions SET status = ?, updated_at = ? WHERE id = ?`)
|
|
305
|
-
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
306
|
-
logger.info('Fixed subscription status', {
|
|
307
|
-
entityId: discrepancy.entityId,
|
|
308
|
-
newStatus: discrepancy.stripeValue,
|
|
309
|
-
});
|
|
310
|
-
return true;
|
|
311
|
-
case 'tier_mismatch':
|
|
312
|
-
this.db
|
|
313
|
-
.prepare(`UPDATE user_subscriptions SET tier = ?, updated_at = ? WHERE id = ?`)
|
|
314
|
-
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
315
|
-
logger.info('Fixed subscription tier', {
|
|
316
|
-
entityId: discrepancy.entityId,
|
|
317
|
-
newTier: discrepancy.stripeValue,
|
|
318
|
-
});
|
|
319
|
-
return true;
|
|
320
|
-
case 'seat_count_mismatch':
|
|
321
|
-
this.db
|
|
322
|
-
.prepare(`UPDATE user_subscriptions SET seat_count = ?, updated_at = ? WHERE id = ?`)
|
|
323
|
-
.run(discrepancy.stripeValue, new Date().toISOString(), discrepancy.entityId);
|
|
324
|
-
logger.info('Fixed subscription seat count', {
|
|
325
|
-
entityId: discrepancy.entityId,
|
|
326
|
-
newSeatCount: discrepancy.stripeValue,
|
|
327
|
-
});
|
|
328
|
-
return true;
|
|
329
|
-
case 'missing_stripe':
|
|
330
|
-
// Mark local subscription as canceled if missing in Stripe
|
|
331
|
-
this.db
|
|
332
|
-
.prepare(`UPDATE user_subscriptions SET status = 'canceled', canceled_at = ?, updated_at = ? WHERE id = ?`)
|
|
333
|
-
.run(new Date().toISOString(), new Date().toISOString(), discrepancy.entityId);
|
|
334
|
-
logger.info('Marked missing subscription as canceled', { entityId: discrepancy.entityId });
|
|
335
|
-
return true;
|
|
336
|
-
default:
|
|
337
|
-
return false;
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
fixInvoiceDiscrepancy(discrepancy) {
|
|
341
|
-
switch (discrepancy.type) {
|
|
342
|
-
case 'invoice_status_mismatch':
|
|
343
|
-
this.db
|
|
344
|
-
.prepare(`UPDATE invoices SET status = ? WHERE id = ?`)
|
|
345
|
-
.run(discrepancy.stripeValue, discrepancy.entityId);
|
|
346
|
-
logger.info('Fixed invoice status', {
|
|
347
|
-
entityId: discrepancy.entityId,
|
|
348
|
-
newStatus: discrepancy.stripeValue,
|
|
349
|
-
});
|
|
350
|
-
return true;
|
|
351
|
-
case 'invoice_amount_mismatch':
|
|
352
|
-
this.db
|
|
353
|
-
.prepare(`UPDATE invoices SET amount_cents = ? WHERE id = ?`)
|
|
354
|
-
.run(discrepancy.stripeValue, discrepancy.entityId);
|
|
355
|
-
logger.info('Fixed invoice amount', {
|
|
356
|
-
entityId: discrepancy.entityId,
|
|
357
|
-
newAmount: discrepancy.stripeValue,
|
|
358
|
-
});
|
|
359
|
-
return true;
|
|
360
|
-
default:
|
|
361
|
-
return false;
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
//# sourceMappingURL=StripeReconciliationJob.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StripeReconciliationJob.js","sourceRoot":"","sources":["../../../src/billing/StripeReconciliationJob.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SMI-1070: Stripe Webhook Handler
|
|
3
|
-
*
|
|
4
|
-
* Processes Stripe webhook events for:
|
|
5
|
-
* - Subscription lifecycle (created, updated, deleted)
|
|
6
|
-
* - Invoice events (payment succeeded, payment failed)
|
|
7
|
-
* - Checkout session completion
|
|
8
|
-
*
|
|
9
|
-
* Features:
|
|
10
|
-
* - Idempotent event processing
|
|
11
|
-
* - Signature verification
|
|
12
|
-
* - License key generation on subscription creation
|
|
13
|
-
* - Status synchronization
|
|
14
|
-
*/
|
|
15
|
-
import type { WebhookProcessResult } from './types.js';
|
|
16
|
-
import type { StripeWebhookHandlerConfig } from './webhook-types.js';
|
|
17
|
-
export type { StripeWebhookHandlerConfig } from './webhook-types.js';
|
|
18
|
-
/**
|
|
19
|
-
* Handles Stripe webhook events
|
|
20
|
-
*
|
|
21
|
-
* @example
|
|
22
|
-
* ```typescript
|
|
23
|
-
* const handler = new StripeWebhookHandler({
|
|
24
|
-
* stripeClient,
|
|
25
|
-
* billingService,
|
|
26
|
-
* db,
|
|
27
|
-
* onLicenseKeyNeeded: async (params) => {
|
|
28
|
-
* return licenseGenerator.createLicense(params);
|
|
29
|
-
* },
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* // In webhook endpoint:
|
|
33
|
-
* const result = await handler.handleWebhook(payload, signature);
|
|
34
|
-
* ```
|
|
35
|
-
*/
|
|
36
|
-
export declare class StripeWebhookHandler {
|
|
37
|
-
private readonly stripe;
|
|
38
|
-
private readonly billing;
|
|
39
|
-
private readonly db;
|
|
40
|
-
private readonly onLicenseKeyNeeded?;
|
|
41
|
-
private readonly onEmailNeeded?;
|
|
42
|
-
constructor(config: StripeWebhookHandlerConfig);
|
|
43
|
-
/**
|
|
44
|
-
* Handle an incoming Stripe webhook
|
|
45
|
-
*/
|
|
46
|
-
handleWebhook(payload: string, signature: string): Promise<WebhookProcessResult>;
|
|
47
|
-
private routeEvent;
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=StripeWebhookHandler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StripeWebhookHandler.d.ts","sourceRoot":"","sources":["../../../src/billing/StripeWebhookHandler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,OAAO,KAAK,EAAiB,oBAAoB,EAAE,MAAM,YAAY,CAAA;AACrE,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAA;AAYpE,YAAY,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAA;AAQpE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAc;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAAkD;IACtF,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAA6C;gBAEhE,MAAM,EAAE,0BAA0B;IAc9C;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC;YAgFxE,UAAU;CAsCzB"}
|
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* SMI-1070: Stripe Webhook Handler
|
|
3
|
-
*
|
|
4
|
-
* Processes Stripe webhook events for:
|
|
5
|
-
* - Subscription lifecycle (created, updated, deleted)
|
|
6
|
-
* - Invoice events (payment succeeded, payment failed)
|
|
7
|
-
* - Checkout session completion
|
|
8
|
-
*
|
|
9
|
-
* Features:
|
|
10
|
-
* - Idempotent event processing
|
|
11
|
-
* - Signature verification
|
|
12
|
-
* - License key generation on subscription creation
|
|
13
|
-
* - Status synchronization
|
|
14
|
-
*/
|
|
15
|
-
import { createLogger } from '../utils/logger.js';
|
|
16
|
-
import { handleSubscriptionCreated, handleSubscriptionUpdated, handleSubscriptionDeleted, handleInvoicePaymentSucceeded, handleInvoicePaymentFailed, handleCheckoutSessionCompleted, } from './webhook-handlers.js';
|
|
17
|
-
const logger = createLogger('StripeWebhookHandler');
|
|
18
|
-
// ============================================================================
|
|
19
|
-
// StripeWebhookHandler Class
|
|
20
|
-
// ============================================================================
|
|
21
|
-
/**
|
|
22
|
-
* Handles Stripe webhook events
|
|
23
|
-
*
|
|
24
|
-
* @example
|
|
25
|
-
* ```typescript
|
|
26
|
-
* const handler = new StripeWebhookHandler({
|
|
27
|
-
* stripeClient,
|
|
28
|
-
* billingService,
|
|
29
|
-
* db,
|
|
30
|
-
* onLicenseKeyNeeded: async (params) => {
|
|
31
|
-
* return licenseGenerator.createLicense(params);
|
|
32
|
-
* },
|
|
33
|
-
* });
|
|
34
|
-
*
|
|
35
|
-
* // In webhook endpoint:
|
|
36
|
-
* const result = await handler.handleWebhook(payload, signature);
|
|
37
|
-
* ```
|
|
38
|
-
*/
|
|
39
|
-
export class StripeWebhookHandler {
|
|
40
|
-
stripe;
|
|
41
|
-
billing;
|
|
42
|
-
db;
|
|
43
|
-
onLicenseKeyNeeded;
|
|
44
|
-
onEmailNeeded;
|
|
45
|
-
constructor(config) {
|
|
46
|
-
this.stripe = config.stripeClient;
|
|
47
|
-
this.billing = config.billingService;
|
|
48
|
-
this.db = config.db;
|
|
49
|
-
this.onLicenseKeyNeeded = config.onLicenseKeyNeeded;
|
|
50
|
-
this.onEmailNeeded = config.onEmailNeeded;
|
|
51
|
-
logger.info('Stripe webhook handler initialized');
|
|
52
|
-
}
|
|
53
|
-
// ==========================================================================
|
|
54
|
-
// Main Entry Point
|
|
55
|
-
// ==========================================================================
|
|
56
|
-
/**
|
|
57
|
-
* Handle an incoming Stripe webhook
|
|
58
|
-
*/
|
|
59
|
-
async handleWebhook(payload, signature) {
|
|
60
|
-
// 1. Verify signature
|
|
61
|
-
let event;
|
|
62
|
-
try {
|
|
63
|
-
event = this.stripe.verifyWebhookSignature(payload, signature);
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
return {
|
|
67
|
-
success: false,
|
|
68
|
-
message: 'Signature verification failed',
|
|
69
|
-
eventId: '',
|
|
70
|
-
processed: false,
|
|
71
|
-
error: error instanceof Error ? error.message : 'Invalid signature',
|
|
72
|
-
};
|
|
73
|
-
}
|
|
74
|
-
const eventId = event.id;
|
|
75
|
-
// 2. Check for duplicate (idempotency)
|
|
76
|
-
if (this.billing.isEventProcessed(eventId)) {
|
|
77
|
-
logger.info('Duplicate webhook event', { eventId, type: event.type });
|
|
78
|
-
return {
|
|
79
|
-
success: true,
|
|
80
|
-
message: 'Event already processed',
|
|
81
|
-
eventId,
|
|
82
|
-
processed: false,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
// 3. Route to appropriate handler
|
|
86
|
-
try {
|
|
87
|
-
await this.routeEvent(event);
|
|
88
|
-
// 4. Record successful processing
|
|
89
|
-
this.billing.recordWebhookEvent({
|
|
90
|
-
stripeEventId: eventId,
|
|
91
|
-
eventType: event.type,
|
|
92
|
-
payload,
|
|
93
|
-
success: true,
|
|
94
|
-
});
|
|
95
|
-
logger.info('Webhook event processed', { eventId, type: event.type });
|
|
96
|
-
return {
|
|
97
|
-
success: true,
|
|
98
|
-
message: `Processed ${event.type}`,
|
|
99
|
-
eventId,
|
|
100
|
-
processed: true,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
catch (error) {
|
|
104
|
-
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
105
|
-
// Record failed processing
|
|
106
|
-
this.billing.recordWebhookEvent({
|
|
107
|
-
stripeEventId: eventId,
|
|
108
|
-
eventType: event.type,
|
|
109
|
-
payload,
|
|
110
|
-
success: false,
|
|
111
|
-
errorMessage,
|
|
112
|
-
});
|
|
113
|
-
logger.error('Webhook processing failed', undefined, {
|
|
114
|
-
eventId,
|
|
115
|
-
eventType: event.type,
|
|
116
|
-
errorDetails: errorMessage,
|
|
117
|
-
});
|
|
118
|
-
return {
|
|
119
|
-
success: false,
|
|
120
|
-
message: 'Processing failed',
|
|
121
|
-
eventId,
|
|
122
|
-
processed: false,
|
|
123
|
-
error: errorMessage,
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
// ==========================================================================
|
|
128
|
-
// Event Routing
|
|
129
|
-
// ==========================================================================
|
|
130
|
-
async routeEvent(event) {
|
|
131
|
-
const ctx = {
|
|
132
|
-
stripe: this.stripe,
|
|
133
|
-
billing: this.billing,
|
|
134
|
-
db: this.db,
|
|
135
|
-
onLicenseKeyNeeded: this.onLicenseKeyNeeded,
|
|
136
|
-
onEmailNeeded: this.onEmailNeeded,
|
|
137
|
-
};
|
|
138
|
-
switch (event.type) {
|
|
139
|
-
case 'customer.subscription.created':
|
|
140
|
-
await handleSubscriptionCreated(ctx, event.data.object);
|
|
141
|
-
break;
|
|
142
|
-
case 'customer.subscription.updated':
|
|
143
|
-
await handleSubscriptionUpdated(ctx, event.data.object);
|
|
144
|
-
break;
|
|
145
|
-
case 'customer.subscription.deleted':
|
|
146
|
-
await handleSubscriptionDeleted(ctx, event.data.object);
|
|
147
|
-
break;
|
|
148
|
-
case 'invoice.payment_succeeded':
|
|
149
|
-
await handleInvoicePaymentSucceeded(ctx, event.data.object);
|
|
150
|
-
break;
|
|
151
|
-
case 'invoice.payment_failed':
|
|
152
|
-
await handleInvoicePaymentFailed(ctx, event.data.object);
|
|
153
|
-
break;
|
|
154
|
-
case 'checkout.session.completed':
|
|
155
|
-
handleCheckoutSessionCompleted(event.data.object);
|
|
156
|
-
break;
|
|
157
|
-
default:
|
|
158
|
-
logger.debug('Unhandled webhook event type', { type: event.type });
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
//# sourceMappingURL=StripeWebhookHandler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"StripeWebhookHandler.js","sourceRoot":"","sources":["../../../src/billing/StripeWebhookHandler.ts"],"names":[],"mappings":"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"}
|