@skillsmith/core 2.1.1 → 2.1.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.
Files changed (194) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/src/analysis/types.d.ts +2 -0
  3. package/dist/src/analysis/types.d.ts.map +1 -1
  4. package/dist/src/analysis/types.js +13 -1
  5. package/dist/src/analysis/types.js.map +1 -1
  6. package/dist/src/analytics/schema.d.ts +1 -1
  7. package/dist/src/analytics/schema.d.ts.map +1 -1
  8. package/dist/src/analytics/schema.js +68 -0
  9. package/dist/src/analytics/schema.js.map +1 -1
  10. package/dist/src/api/client.d.ts +25 -21
  11. package/dist/src/api/client.d.ts.map +1 -1
  12. package/dist/src/api/client.js +13 -8
  13. package/dist/src/api/client.js.map +1 -1
  14. package/dist/src/billing/BillingService.d.ts +139 -0
  15. package/dist/src/billing/BillingService.d.ts.map +1 -0
  16. package/dist/src/billing/BillingService.js +393 -0
  17. package/dist/src/billing/BillingService.js.map +1 -0
  18. package/dist/src/billing/GDPRComplianceService.d.ts +176 -0
  19. package/dist/src/billing/GDPRComplianceService.d.ts.map +1 -0
  20. package/dist/src/billing/GDPRComplianceService.js +361 -0
  21. package/dist/src/billing/GDPRComplianceService.js.map +1 -0
  22. package/dist/src/billing/StripeClient.d.ts +177 -0
  23. package/dist/src/billing/StripeClient.d.ts.map +1 -0
  24. package/dist/src/billing/StripeClient.js +462 -0
  25. package/dist/src/billing/StripeClient.js.map +1 -0
  26. package/dist/src/billing/StripeReconciliationJob.d.ts +95 -0
  27. package/dist/src/billing/StripeReconciliationJob.d.ts.map +1 -0
  28. package/dist/src/billing/StripeReconciliationJob.js +405 -0
  29. package/dist/src/billing/StripeReconciliationJob.js.map +1 -0
  30. package/dist/src/billing/StripeWebhookHandler.d.ts +92 -0
  31. package/dist/src/billing/StripeWebhookHandler.d.ts.map +1 -0
  32. package/dist/src/billing/StripeWebhookHandler.js +409 -0
  33. package/dist/src/billing/StripeWebhookHandler.js.map +1 -0
  34. package/dist/src/billing/index.d.ts +18 -0
  35. package/dist/src/billing/index.d.ts.map +1 -0
  36. package/dist/src/billing/index.js +19 -0
  37. package/dist/src/billing/index.js.map +1 -0
  38. package/dist/src/billing/types.d.ts +266 -0
  39. package/dist/src/billing/types.d.ts.map +1 -0
  40. package/dist/src/billing/types.js +23 -0
  41. package/dist/src/billing/types.js.map +1 -0
  42. package/dist/src/embeddings/hnsw-store.d.ts +568 -0
  43. package/dist/src/embeddings/hnsw-store.d.ts.map +1 -0
  44. package/dist/src/embeddings/hnsw-store.js +805 -0
  45. package/dist/src/embeddings/hnsw-store.js.map +1 -0
  46. package/dist/src/embeddings/index.d.ts +2 -0
  47. package/dist/src/embeddings/index.d.ts.map +1 -1
  48. package/dist/src/embeddings/index.js +2 -0
  49. package/dist/src/embeddings/index.js.map +1 -1
  50. package/dist/src/index.d.ts +1 -0
  51. package/dist/src/index.d.ts.map +1 -1
  52. package/dist/src/index.js +2 -0
  53. package/dist/src/index.js.map +1 -1
  54. package/dist/src/learning/PatternStore.d.ts +457 -0
  55. package/dist/src/learning/PatternStore.d.ts.map +1 -0
  56. package/dist/src/learning/PatternStore.js +893 -0
  57. package/dist/src/learning/PatternStore.js.map +1 -0
  58. package/dist/src/learning/ReasoningBankIntegration.d.ts +403 -0
  59. package/dist/src/learning/ReasoningBankIntegration.d.ts.map +1 -0
  60. package/dist/src/learning/ReasoningBankIntegration.js +627 -0
  61. package/dist/src/learning/ReasoningBankIntegration.js.map +1 -0
  62. package/dist/src/learning/index.d.ts +15 -0
  63. package/dist/src/learning/index.d.ts.map +1 -0
  64. package/dist/src/learning/index.js +15 -0
  65. package/dist/src/learning/index.js.map +1 -0
  66. package/dist/src/routing/SONARouter.d.ts +154 -0
  67. package/dist/src/routing/SONARouter.d.ts.map +1 -0
  68. package/dist/src/routing/SONARouter.js +679 -0
  69. package/dist/src/routing/SONARouter.js.map +1 -0
  70. package/dist/src/routing/index.d.ts +9 -0
  71. package/dist/src/routing/index.d.ts.map +1 -0
  72. package/dist/src/routing/index.js +10 -0
  73. package/dist/src/routing/index.js.map +1 -0
  74. package/dist/src/routing/types.d.ts +331 -0
  75. package/dist/src/routing/types.d.ts.map +1 -0
  76. package/dist/src/routing/types.js +203 -0
  77. package/dist/src/routing/types.js.map +1 -0
  78. package/dist/src/scripts/__tests__/scan-imported-skills.test.js +5 -0
  79. package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
  80. package/dist/src/security/SkillSandbox.d.ts +156 -0
  81. package/dist/src/security/SkillSandbox.d.ts.map +1 -0
  82. package/dist/src/security/SkillSandbox.js +303 -0
  83. package/dist/src/security/SkillSandbox.js.map +1 -0
  84. package/dist/src/security/index.d.ts +3 -1
  85. package/dist/src/security/index.d.ts.map +1 -1
  86. package/dist/src/security/index.js +5 -1
  87. package/dist/src/security/index.js.map +1 -1
  88. package/dist/src/security/rate-limiter/presets.d.ts +12 -0
  89. package/dist/src/security/rate-limiter/presets.d.ts.map +1 -1
  90. package/dist/src/security/rate-limiter/presets.js +12 -0
  91. package/dist/src/security/rate-limiter/presets.js.map +1 -1
  92. package/dist/src/security/sanitization.d.ts +85 -0
  93. package/dist/src/security/sanitization.d.ts.map +1 -1
  94. package/dist/src/security/sanitization.js +133 -0
  95. package/dist/src/security/sanitization.js.map +1 -1
  96. package/dist/src/security/scanner/SecurityScanner.d.ts +22 -1
  97. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  98. package/dist/src/security/scanner/SecurityScanner.js +190 -35
  99. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  100. package/dist/src/security/scanner/patterns.d.ts +13 -0
  101. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  102. package/dist/src/security/scanner/patterns.js +51 -0
  103. package/dist/src/security/scanner/patterns.js.map +1 -1
  104. package/dist/src/security/scanner/types.d.ts +13 -1
  105. package/dist/src/security/scanner/types.d.ts.map +1 -1
  106. package/dist/src/security/scanner/weights.d.ts.map +1 -1
  107. package/dist/src/security/scanner/weights.js +1 -0
  108. package/dist/src/security/scanner/weights.js.map +1 -1
  109. package/dist/src/session/SessionManager.d.ts +7 -0
  110. package/dist/src/session/SessionManager.d.ts.map +1 -1
  111. package/dist/src/session/SessionManager.js +117 -10
  112. package/dist/src/session/SessionManager.js.map +1 -1
  113. package/dist/src/sync/SyncEngine.d.ts.map +1 -1
  114. package/dist/src/sync/SyncEngine.js +9 -1
  115. package/dist/src/sync/SyncEngine.js.map +1 -1
  116. package/dist/src/testing/MultiLLMProvider.d.ts +374 -0
  117. package/dist/src/testing/MultiLLMProvider.d.ts.map +1 -0
  118. package/dist/src/testing/MultiLLMProvider.js +720 -0
  119. package/dist/src/testing/MultiLLMProvider.js.map +1 -0
  120. package/dist/src/testing/index.d.ts +8 -0
  121. package/dist/src/testing/index.d.ts.map +1 -0
  122. package/dist/src/testing/index.js +9 -0
  123. package/dist/src/testing/index.js.map +1 -0
  124. package/dist/tests/SecurityScanner.test.js +337 -1
  125. package/dist/tests/SecurityScanner.test.js.map +1 -1
  126. package/dist/tests/billing/BillingService.test.d.ts +7 -0
  127. package/dist/tests/billing/BillingService.test.d.ts.map +1 -0
  128. package/dist/tests/billing/BillingService.test.js +168 -0
  129. package/dist/tests/billing/BillingService.test.js.map +1 -0
  130. package/dist/tests/billing/GDPRCompliance.test.d.ts +7 -0
  131. package/dist/tests/billing/GDPRCompliance.test.d.ts.map +1 -0
  132. package/dist/tests/billing/GDPRCompliance.test.js +195 -0
  133. package/dist/tests/billing/GDPRCompliance.test.js.map +1 -0
  134. package/dist/tests/billing/StripeReconciliation.test.d.ts +7 -0
  135. package/dist/tests/billing/StripeReconciliation.test.d.ts.map +1 -0
  136. package/dist/tests/billing/StripeReconciliation.test.js +266 -0
  137. package/dist/tests/billing/StripeReconciliation.test.js.map +1 -0
  138. package/dist/tests/billing/stripe-validators.test.d.ts +7 -0
  139. package/dist/tests/billing/stripe-validators.test.d.ts.map +1 -0
  140. package/dist/tests/billing/stripe-validators.test.js +107 -0
  141. package/dist/tests/billing/stripe-validators.test.js.map +1 -0
  142. package/dist/tests/embeddings/hnsw-store.test.d.ts +7 -0
  143. package/dist/tests/embeddings/hnsw-store.test.d.ts.map +1 -0
  144. package/dist/tests/embeddings/hnsw-store.test.js +295 -0
  145. package/dist/tests/embeddings/hnsw-store.test.js.map +1 -0
  146. package/dist/tests/integration/neural/e2e-learning.test.d.ts +17 -0
  147. package/dist/tests/integration/neural/e2e-learning.test.d.ts.map +1 -0
  148. package/dist/tests/integration/neural/e2e-learning.test.js +238 -0
  149. package/dist/tests/integration/neural/e2e-learning.test.js.map +1 -0
  150. package/dist/tests/integration/neural/helpers.d.ts +132 -0
  151. package/dist/tests/integration/neural/helpers.d.ts.map +1 -0
  152. package/dist/tests/integration/neural/helpers.js +287 -0
  153. package/dist/tests/integration/neural/helpers.js.map +1 -0
  154. package/dist/tests/integration/neural/personalization.test.d.ts +21 -0
  155. package/dist/tests/integration/neural/personalization.test.d.ts.map +1 -0
  156. package/dist/tests/integration/neural/personalization.test.js +304 -0
  157. package/dist/tests/integration/neural/personalization.test.js.map +1 -0
  158. package/dist/tests/integration/neural/preference-learner.test.d.ts +23 -0
  159. package/dist/tests/integration/neural/preference-learner.test.d.ts.map +1 -0
  160. package/dist/tests/integration/neural/preference-learner.test.js +289 -0
  161. package/dist/tests/integration/neural/preference-learner.test.js.map +1 -0
  162. package/dist/tests/integration/neural/privacy.test.d.ts +19 -0
  163. package/dist/tests/integration/neural/privacy.test.d.ts.map +1 -0
  164. package/dist/tests/integration/neural/privacy.test.js +249 -0
  165. package/dist/tests/integration/neural/privacy.test.js.map +1 -0
  166. package/dist/tests/integration/neural/setup.d.ts +175 -0
  167. package/dist/tests/integration/neural/setup.d.ts.map +1 -0
  168. package/dist/tests/integration/neural/setup.js +487 -0
  169. package/dist/tests/integration/neural/setup.js.map +1 -0
  170. package/dist/tests/integration/neural/signal-collection.test.d.ts +21 -0
  171. package/dist/tests/integration/neural/signal-collection.test.d.ts.map +1 -0
  172. package/dist/tests/integration/neural/signal-collection.test.js +232 -0
  173. package/dist/tests/integration/neural/signal-collection.test.js.map +1 -0
  174. package/dist/tests/learning/PatternStore.test.d.ts +8 -0
  175. package/dist/tests/learning/PatternStore.test.d.ts.map +1 -0
  176. package/dist/tests/learning/PatternStore.test.js +589 -0
  177. package/dist/tests/learning/PatternStore.test.js.map +1 -0
  178. package/dist/tests/learning/ReasoningBankIntegration.test.d.ts +8 -0
  179. package/dist/tests/learning/ReasoningBankIntegration.test.d.ts.map +1 -0
  180. package/dist/tests/learning/ReasoningBankIntegration.test.js +269 -0
  181. package/dist/tests/learning/ReasoningBankIntegration.test.js.map +1 -0
  182. package/dist/tests/routing/SONARouter.test.d.ts +8 -0
  183. package/dist/tests/routing/SONARouter.test.d.ts.map +1 -0
  184. package/dist/tests/routing/SONARouter.test.js +400 -0
  185. package/dist/tests/routing/SONARouter.test.js.map +1 -0
  186. package/dist/tests/security/SkillSandbox.test.d.ts +8 -0
  187. package/dist/tests/security/SkillSandbox.test.d.ts.map +1 -0
  188. package/dist/tests/security/SkillSandbox.test.js +321 -0
  189. package/dist/tests/security/SkillSandbox.test.js.map +1 -0
  190. package/dist/tests/testing/MultiLLMProvider.test.d.ts +14 -0
  191. package/dist/tests/testing/MultiLLMProvider.test.d.ts.map +1 -0
  192. package/dist/tests/testing/MultiLLMProvider.test.js +438 -0
  193. package/dist/tests/testing/MultiLLMProvider.test.js.map +1 -0
  194. package/package.json +16 -3
@@ -0,0 +1,393 @@
1
+ /**
2
+ * SMI-1063: Billing Service
3
+ *
4
+ * High-level billing operations that coordinate between:
5
+ * - StripeClient (Stripe API)
6
+ * - Database (subscription/invoice storage)
7
+ * - LicenseKeyGenerator (license key generation)
8
+ */
9
+ import { randomUUID } from 'crypto';
10
+ import { createLogger } from '../utils/logger.js';
11
+ import { BillingError } from './types.js';
12
+ const logger = createLogger('BillingService');
13
+ // ============================================================================
14
+ // BillingService Class
15
+ // ============================================================================
16
+ /**
17
+ * Billing service for subscription management
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const billing = new BillingService({
22
+ * stripeClient,
23
+ * db,
24
+ * });
25
+ *
26
+ * // Create checkout session
27
+ * const session = await billing.createCheckoutSession({
28
+ * tier: 'team',
29
+ * billingPeriod: 'monthly',
30
+ * seatCount: 5,
31
+ * email: 'admin@company.com',
32
+ * successUrl: '/success',
33
+ * cancelUrl: '/cancel',
34
+ * });
35
+ *
36
+ * // Get subscription
37
+ * const subscription = await billing.getSubscriptionByCustomerId('cust_123');
38
+ * ```
39
+ */
40
+ export class BillingService {
41
+ stripe;
42
+ db;
43
+ constructor(config) {
44
+ this.stripe = config.stripeClient;
45
+ this.db = config.db;
46
+ logger.info('Billing service initialized');
47
+ }
48
+ // ==========================================================================
49
+ // Checkout Flow
50
+ // ==========================================================================
51
+ /**
52
+ * Create a Stripe Checkout session
53
+ */
54
+ async createCheckoutSession(request) {
55
+ return this.stripe.createCheckoutSession(request);
56
+ }
57
+ // ==========================================================================
58
+ // Subscription Management
59
+ // ==========================================================================
60
+ /**
61
+ * Get subscription by customer ID (our internal ID)
62
+ */
63
+ getSubscriptionByCustomerId(customerId) {
64
+ const row = this.db
65
+ .prepare(`SELECT
66
+ id,
67
+ customer_id as customerId,
68
+ stripe_subscription_id as stripeSubscriptionId,
69
+ stripe_price_id as stripePriceId,
70
+ tier,
71
+ status,
72
+ seat_count as seatCount,
73
+ current_period_start as currentPeriodStart,
74
+ current_period_end as currentPeriodEnd,
75
+ canceled_at as canceledAt,
76
+ created_at as createdAt,
77
+ updated_at as updatedAt
78
+ FROM user_subscriptions
79
+ WHERE customer_id = ?`)
80
+ .get(customerId);
81
+ if (!row)
82
+ return null;
83
+ return this.mapRowToSubscription(row);
84
+ }
85
+ /**
86
+ * Get subscription by Stripe subscription ID
87
+ */
88
+ getSubscriptionByStripeId(stripeSubscriptionId) {
89
+ const row = this.db
90
+ .prepare(`SELECT
91
+ id,
92
+ customer_id as customerId,
93
+ stripe_subscription_id as stripeSubscriptionId,
94
+ stripe_price_id as stripePriceId,
95
+ tier,
96
+ status,
97
+ seat_count as seatCount,
98
+ current_period_start as currentPeriodStart,
99
+ current_period_end as currentPeriodEnd,
100
+ canceled_at as canceledAt,
101
+ created_at as createdAt,
102
+ updated_at as updatedAt
103
+ FROM user_subscriptions
104
+ WHERE stripe_subscription_id = ?`)
105
+ .get(stripeSubscriptionId);
106
+ if (!row)
107
+ return null;
108
+ return this.mapRowToSubscription(row);
109
+ }
110
+ /**
111
+ * Create or update subscription from Stripe data
112
+ */
113
+ upsertSubscription(params) {
114
+ const id = randomUUID();
115
+ const now = new Date().toISOString();
116
+ this.db
117
+ .prepare(`INSERT INTO user_subscriptions (
118
+ id, customer_id, email, stripe_customer_id, stripe_subscription_id,
119
+ stripe_price_id, tier, status, seat_count,
120
+ current_period_start, current_period_end, canceled_at,
121
+ created_at, updated_at
122
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
123
+ ON CONFLICT(customer_id) DO UPDATE SET
124
+ stripe_subscription_id = excluded.stripe_subscription_id,
125
+ stripe_price_id = excluded.stripe_price_id,
126
+ tier = excluded.tier,
127
+ status = excluded.status,
128
+ seat_count = excluded.seat_count,
129
+ current_period_start = excluded.current_period_start,
130
+ current_period_end = excluded.current_period_end,
131
+ canceled_at = excluded.canceled_at,
132
+ updated_at = excluded.updated_at`)
133
+ .run(id, params.customerId, params.email, params.stripeCustomerId, params.stripeSubscriptionId, params.stripePriceId, params.tier, params.status, params.seatCount, params.currentPeriodStart.toISOString(), params.currentPeriodEnd.toISOString(), params.canceledAt?.toISOString() ?? null, now, now);
134
+ logger.info('Subscription upserted', {
135
+ customerId: params.customerId,
136
+ tier: params.tier,
137
+ status: params.status,
138
+ });
139
+ return this.getSubscriptionByCustomerId(params.customerId);
140
+ }
141
+ /**
142
+ * Update subscription status
143
+ */
144
+ updateSubscriptionStatus(stripeSubscriptionId, status, canceledAt) {
145
+ this.db
146
+ .prepare(`UPDATE user_subscriptions
147
+ SET status = ?, canceled_at = ?, updated_at = ?
148
+ WHERE stripe_subscription_id = ?`)
149
+ .run(status, canceledAt?.toISOString() ?? null, new Date().toISOString(), stripeSubscriptionId);
150
+ logger.info('Subscription status updated', { stripeSubscriptionId, status });
151
+ }
152
+ /**
153
+ * Update seat count
154
+ */
155
+ async updateSeatCount(stripeSubscriptionId, seatCount, prorate = true) {
156
+ // Update in Stripe
157
+ await this.stripe.updateSubscription(stripeSubscriptionId, {
158
+ seatCount,
159
+ prorate,
160
+ });
161
+ // Update locally
162
+ this.db
163
+ .prepare(`UPDATE user_subscriptions
164
+ SET seat_count = ?, updated_at = ?
165
+ WHERE stripe_subscription_id = ?`)
166
+ .run(seatCount, new Date().toISOString(), stripeSubscriptionId);
167
+ logger.info('Seat count updated', { stripeSubscriptionId, seatCount });
168
+ return this.getSubscriptionByStripeId(stripeSubscriptionId);
169
+ }
170
+ /**
171
+ * Cancel a subscription
172
+ */
173
+ async cancelSubscription(customerId, options) {
174
+ const subscription = this.getSubscriptionByCustomerId(customerId);
175
+ if (!subscription?.stripeSubscriptionId) {
176
+ throw new BillingError('Subscription not found', 'SUBSCRIPTION_NOT_FOUND');
177
+ }
178
+ await this.stripe.cancelSubscription(subscription.stripeSubscriptionId, options);
179
+ // Update local status
180
+ const newStatus = options?.immediately ? 'canceled' : subscription.status;
181
+ const canceledAt = options?.immediately ? new Date() : null;
182
+ this.updateSubscriptionStatus(subscription.stripeSubscriptionId, newStatus, canceledAt);
183
+ return this.getSubscriptionByCustomerId(customerId);
184
+ }
185
+ /**
186
+ * Upgrade subscription tier
187
+ */
188
+ async upgradeTier(customerId, newTier, billingPeriod) {
189
+ const subscription = this.getSubscriptionByCustomerId(customerId);
190
+ if (!subscription?.stripeSubscriptionId) {
191
+ throw new BillingError('Subscription not found', 'SUBSCRIPTION_NOT_FOUND');
192
+ }
193
+ // Validate tier upgrade
194
+ const tierOrder = ['community', 'individual', 'team', 'enterprise'];
195
+ const currentIndex = tierOrder.indexOf(subscription.tier);
196
+ const newIndex = tierOrder.indexOf(newTier);
197
+ if (newIndex <= currentIndex) {
198
+ throw new BillingError('Can only upgrade to a higher tier', 'DOWNGRADE_NOT_ALLOWED', {
199
+ currentTier: subscription.tier,
200
+ requestedTier: newTier,
201
+ });
202
+ }
203
+ await this.stripe.updateSubscription(subscription.stripeSubscriptionId, {
204
+ tier: newTier,
205
+ billingPeriod,
206
+ prorate: true,
207
+ });
208
+ // Update local tier
209
+ this.db
210
+ .prepare(`UPDATE user_subscriptions
211
+ SET tier = ?, updated_at = ?
212
+ WHERE customer_id = ?`)
213
+ .run(newTier, new Date().toISOString(), customerId);
214
+ logger.info('Tier upgraded', {
215
+ customerId,
216
+ fromTier: subscription.tier,
217
+ toTier: newTier,
218
+ });
219
+ return this.getSubscriptionByCustomerId(customerId);
220
+ }
221
+ // ==========================================================================
222
+ // Customer Portal
223
+ // ==========================================================================
224
+ /**
225
+ * Create a Customer Portal session
226
+ */
227
+ async createPortalSession(customerId, returnUrl) {
228
+ const subscription = this.getSubscriptionByCustomerId(customerId);
229
+ if (!subscription) {
230
+ throw new BillingError('Customer not found', 'CUSTOMER_NOT_FOUND');
231
+ }
232
+ const row = this.db
233
+ .prepare(`SELECT stripe_customer_id FROM user_subscriptions WHERE customer_id = ?`)
234
+ .get(customerId);
235
+ if (!row?.stripe_customer_id) {
236
+ throw new BillingError('No Stripe customer found', 'CUSTOMER_NOT_FOUND');
237
+ }
238
+ return this.stripe.createPortalSession({
239
+ customerId: row.stripe_customer_id,
240
+ returnUrl,
241
+ });
242
+ }
243
+ // ==========================================================================
244
+ // Invoice Management
245
+ // ==========================================================================
246
+ /**
247
+ * Get invoices for a customer
248
+ */
249
+ getInvoices(customerId, limit = 10) {
250
+ const rows = this.db
251
+ .prepare(`SELECT
252
+ id,
253
+ customer_id as customerId,
254
+ stripe_invoice_id as stripeInvoiceId,
255
+ subscription_id as subscriptionId,
256
+ amount_cents as amountCents,
257
+ currency,
258
+ status,
259
+ pdf_url as pdfUrl,
260
+ hosted_invoice_url as hostedInvoiceUrl,
261
+ invoice_number as invoiceNumber,
262
+ paid_at as paidAt,
263
+ period_start as periodStart,
264
+ period_end as periodEnd,
265
+ created_at as createdAt
266
+ FROM invoices
267
+ WHERE customer_id = ?
268
+ ORDER BY created_at DESC
269
+ LIMIT ?`)
270
+ .all(customerId, limit);
271
+ return rows.map(this.mapRowToInvoice);
272
+ }
273
+ /**
274
+ * Store an invoice from Stripe
275
+ */
276
+ storeInvoice(params) {
277
+ const id = randomUUID();
278
+ const now = new Date().toISOString();
279
+ this.db
280
+ .prepare(`INSERT INTO invoices (
281
+ id, customer_id, stripe_invoice_id, subscription_id,
282
+ amount_cents, currency, status, pdf_url, hosted_invoice_url,
283
+ invoice_number, paid_at, period_start, period_end, created_at
284
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
285
+ ON CONFLICT(stripe_invoice_id) DO UPDATE SET
286
+ status = excluded.status,
287
+ pdf_url = excluded.pdf_url,
288
+ paid_at = excluded.paid_at`)
289
+ .run(id, params.customerId, params.stripeInvoiceId, params.subscriptionId ?? null, params.amountCents, params.currency, params.status, params.pdfUrl ?? null, params.hostedInvoiceUrl ?? null, params.invoiceNumber ?? null, params.paidAt?.toISOString() ?? null, params.periodStart?.toISOString() ?? null, params.periodEnd?.toISOString() ?? null, now);
290
+ logger.info('Invoice stored', {
291
+ invoiceId: id,
292
+ stripeInvoiceId: params.stripeInvoiceId,
293
+ status: params.status,
294
+ });
295
+ const row = this.db
296
+ .prepare(`SELECT
297
+ id,
298
+ customer_id as customerId,
299
+ stripe_invoice_id as stripeInvoiceId,
300
+ subscription_id as subscriptionId,
301
+ amount_cents as amountCents,
302
+ currency,
303
+ status,
304
+ pdf_url as pdfUrl,
305
+ hosted_invoice_url as hostedInvoiceUrl,
306
+ invoice_number as invoiceNumber,
307
+ paid_at as paidAt,
308
+ period_start as periodStart,
309
+ period_end as periodEnd,
310
+ created_at as createdAt
311
+ FROM invoices WHERE stripe_invoice_id = ?`)
312
+ .get(params.stripeInvoiceId);
313
+ return this.mapRowToInvoice(row);
314
+ }
315
+ // ==========================================================================
316
+ // Webhook Event Tracking (Idempotency)
317
+ // ==========================================================================
318
+ /**
319
+ * Check if a webhook event has already been processed
320
+ */
321
+ isEventProcessed(stripeEventId) {
322
+ const row = this.db
323
+ .prepare(`SELECT id FROM stripe_webhook_events WHERE stripe_event_id = ?`)
324
+ .get(stripeEventId);
325
+ return !!row;
326
+ }
327
+ /**
328
+ * Record a processed webhook event
329
+ */
330
+ recordWebhookEvent(params) {
331
+ const id = randomUUID();
332
+ const now = new Date().toISOString();
333
+ this.db
334
+ .prepare(`INSERT INTO stripe_webhook_events (
335
+ id, stripe_event_id, event_type, processed_at,
336
+ payload, success, error_message, created_at
337
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
338
+ .run(id, params.stripeEventId, params.eventType, now, params.payload ?? null, params.success !== false ? 1 : 0, params.errorMessage ?? null, now);
339
+ logger.info('Webhook event recorded', {
340
+ eventId: params.stripeEventId,
341
+ eventType: params.eventType,
342
+ success: params.success !== false,
343
+ });
344
+ return {
345
+ id,
346
+ stripeEventId: params.stripeEventId,
347
+ eventType: params.eventType,
348
+ processedAt: new Date(now),
349
+ payload: params.payload ?? '',
350
+ success: params.success !== false,
351
+ errorMessage: params.errorMessage ?? null,
352
+ createdAt: new Date(now),
353
+ };
354
+ }
355
+ // ==========================================================================
356
+ // Helper Methods
357
+ // ==========================================================================
358
+ mapRowToSubscription(row) {
359
+ return {
360
+ id: row.id,
361
+ customerId: row.customerId,
362
+ stripeSubscriptionId: row.stripeSubscriptionId,
363
+ stripePriceId: row.stripePriceId,
364
+ tier: row.tier,
365
+ status: row.status,
366
+ seatCount: row.seatCount ?? 1,
367
+ currentPeriodStart: row.currentPeriodStart ? new Date(row.currentPeriodStart) : null,
368
+ currentPeriodEnd: row.currentPeriodEnd ? new Date(row.currentPeriodEnd) : null,
369
+ canceledAt: row.canceledAt ? new Date(row.canceledAt) : null,
370
+ createdAt: new Date(row.createdAt),
371
+ updatedAt: new Date(row.updatedAt),
372
+ };
373
+ }
374
+ mapRowToInvoice(row) {
375
+ return {
376
+ id: row.id,
377
+ customerId: row.customerId,
378
+ stripeInvoiceId: row.stripeInvoiceId,
379
+ subscriptionId: row.subscriptionId,
380
+ amountCents: row.amountCents,
381
+ currency: row.currency,
382
+ status: row.status,
383
+ pdfUrl: row.pdfUrl,
384
+ hostedInvoiceUrl: row.hostedInvoiceUrl,
385
+ invoiceNumber: row.invoiceNumber,
386
+ paidAt: row.paidAt ? new Date(row.paidAt) : null,
387
+ periodStart: row.periodStart ? new Date(row.periodStart) : null,
388
+ periodEnd: row.periodEnd ? new Date(row.periodEnd) : null,
389
+ createdAt: new Date(row.createdAt),
390
+ };
391
+ }
392
+ }
393
+ //# sourceMappingURL=BillingService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BillingService.js","sourceRoot":"","sources":["../../../src/billing/BillingService.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,176 @@
1
+ /**
2
+ * SMI-1068: GDPR Compliance Service
3
+ *
4
+ * Provides data subject rights implementation for billing data:
5
+ * - Article 17: Right to Erasure (data deletion)
6
+ * - Article 20: Right to Data Portability (data export)
7
+ *
8
+ * All operations are logged for audit purposes.
9
+ */
10
+ import type { Database as BetterSqliteDatabase } from 'better-sqlite3';
11
+ import type { StripeClient } from './StripeClient.js';
12
+ export interface GDPRComplianceServiceConfig {
13
+ /**
14
+ * Database connection (better-sqlite3)
15
+ */
16
+ db: BetterSqliteDatabase;
17
+ /**
18
+ * Optional StripeClient for Stripe data operations
19
+ */
20
+ stripeClient?: StripeClient;
21
+ }
22
+ /**
23
+ * Exported customer data format
24
+ */
25
+ export interface CustomerDataExport {
26
+ /**
27
+ * Export metadata
28
+ */
29
+ metadata: {
30
+ exportedAt: string;
31
+ customerId: string;
32
+ format: 'json';
33
+ version: '1.0';
34
+ };
35
+ /**
36
+ * Subscription data
37
+ */
38
+ subscriptions: SubscriptionExportData[];
39
+ /**
40
+ * Invoice data
41
+ */
42
+ invoices: InvoiceExportData[];
43
+ /**
44
+ * License key data (without the actual JWT for security)
45
+ */
46
+ licenseKeys: LicenseKeyExportData[];
47
+ /**
48
+ * Webhook events related to this customer
49
+ */
50
+ webhookEvents: WebhookEventExportData[];
51
+ }
52
+ export interface SubscriptionExportData {
53
+ id: string;
54
+ stripeSubscriptionId: string | null;
55
+ tier: string;
56
+ status: string;
57
+ seatCount: number;
58
+ currentPeriodStart: string | null;
59
+ currentPeriodEnd: string | null;
60
+ canceledAt: string | null;
61
+ createdAt: string;
62
+ updatedAt: string;
63
+ }
64
+ export interface InvoiceExportData {
65
+ id: string;
66
+ stripeInvoiceId: string;
67
+ amountCents: number;
68
+ currency: string;
69
+ status: string;
70
+ invoiceNumber: string | null;
71
+ paidAt: string | null;
72
+ periodStart: string | null;
73
+ periodEnd: string | null;
74
+ createdAt: string;
75
+ }
76
+ export interface LicenseKeyExportData {
77
+ id: string;
78
+ keyExpiry: string;
79
+ isActive: boolean;
80
+ generatedAt: string;
81
+ revokedAt: string | null;
82
+ revocationReason: string | null;
83
+ }
84
+ export interface WebhookEventExportData {
85
+ id: string;
86
+ stripeEventId: string;
87
+ eventType: string;
88
+ processedAt: string;
89
+ success: boolean;
90
+ }
91
+ /**
92
+ * Result of a data deletion operation
93
+ */
94
+ export interface DeletionResult {
95
+ success: boolean;
96
+ customerId: string;
97
+ deletedAt: string;
98
+ counts: {
99
+ subscriptions: number;
100
+ invoices: number;
101
+ licenseKeys: number;
102
+ webhookEvents: number;
103
+ };
104
+ stripeDeleted: boolean;
105
+ errors: string[];
106
+ }
107
+ /**
108
+ * GDPR Compliance Service for billing data
109
+ *
110
+ * @example
111
+ * ```typescript
112
+ * const gdpr = new GDPRComplianceService({
113
+ * db,
114
+ * stripeClient,
115
+ * });
116
+ *
117
+ * // Export customer data (Article 20)
118
+ * const data = gdpr.exportCustomerData('customer_123');
119
+ *
120
+ * // Delete customer data (Article 17)
121
+ * const result = await gdpr.deleteCustomerData('customer_123');
122
+ * ```
123
+ */
124
+ export declare class GDPRComplianceService {
125
+ private readonly db;
126
+ private readonly stripe?;
127
+ constructor(config: GDPRComplianceServiceConfig);
128
+ /**
129
+ * Export all billing data for a customer
130
+ *
131
+ * Returns a structured JSON export of all data associated with the customer.
132
+ * This fulfills GDPR Article 20 requirements.
133
+ *
134
+ * @param customerId - The customer ID to export data for
135
+ * @returns Complete data export in JSON format
136
+ */
137
+ exportCustomerData(customerId: string): CustomerDataExport;
138
+ private exportSubscriptions;
139
+ private exportInvoices;
140
+ private exportLicenseKeys;
141
+ private exportWebhookEvents;
142
+ /**
143
+ * Delete all billing data for a customer
144
+ *
145
+ * Performs cascading deletion of:
146
+ * 1. License keys
147
+ * 2. Invoices
148
+ * 3. Webhook events (those containing customer data)
149
+ * 4. Subscriptions
150
+ * 5. Stripe customer (if stripeClient provided)
151
+ *
152
+ * This fulfills GDPR Article 17 requirements.
153
+ *
154
+ * @param customerId - The customer ID to delete data for
155
+ * @param options - Deletion options
156
+ * @returns Result of the deletion operation
157
+ */
158
+ deleteCustomerData(customerId: string, options?: {
159
+ deleteFromStripe?: boolean;
160
+ dryRun?: boolean;
161
+ }): Promise<DeletionResult>;
162
+ /**
163
+ * Check if a customer has any billing data
164
+ */
165
+ hasCustomerData(customerId: string): boolean;
166
+ /**
167
+ * Get a summary of customer data (for consent/overview purposes)
168
+ */
169
+ getDataSummary(customerId: string): {
170
+ hasSubscription: boolean;
171
+ invoiceCount: number;
172
+ licenseKeyCount: number;
173
+ stripeCustomerId: string | null;
174
+ };
175
+ }
176
+ //# sourceMappingURL=GDPRComplianceService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GDPRComplianceService.d.ts","sourceRoot":"","sources":["../../../src/billing/GDPRComplianceService.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,QAAQ,IAAI,oBAAoB,EAAE,MAAM,gBAAgB,CAAA;AAEtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAA;AAQrD,MAAM,WAAW,2BAA2B;IAC1C;;OAEG;IACH,EAAE,EAAE,oBAAoB,CAAA;IAExB;;OAEG;IACH,YAAY,CAAC,EAAE,YAAY,CAAA;CAC5B;AAMD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,QAAQ,EAAE;QACR,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,MAAM,EAAE,MAAM,CAAA;QACd,OAAO,EAAE,KAAK,CAAA;KACf,CAAA;IAED;;OAEG;IACH,aAAa,EAAE,sBAAsB,EAAE,CAAA;IAEvC;;OAEG;IACH,QAAQ,EAAE,iBAAiB,EAAE,CAAA;IAE7B;;OAEG;IACH,WAAW,EAAE,oBAAoB,EAAE,CAAA;IAEnC;;OAEG;IACH,aAAa,EAAE,sBAAsB,EAAE,CAAA;CACxC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAA;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,eAAe,EAAE,MAAM,CAAA;IACvB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,aAAa,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;IACrB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,MAAM,CAAA;IACV,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,OAAO,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;CAChC;AAED,MAAM,WAAW,sBAAsB;IACrC,EAAE,EAAE,MAAM,CAAA;IACV,aAAa,EAAE,MAAM,CAAA;IACrB,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,OAAO,EAAE,OAAO,CAAA;CACjB;AAMD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE;QACN,aAAa,EAAE,MAAM,CAAA;QACrB,QAAQ,EAAE,MAAM,CAAA;QAChB,WAAW,EAAE,MAAM,CAAA;QACnB,aAAa,EAAE,MAAM,CAAA;KACtB,CAAA;IACD,aAAa,EAAE,OAAO,CAAA;IACtB,MAAM,EAAE,MAAM,EAAE,CAAA;CACjB;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAsB;IACzC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAc;gBAE1B,MAAM,EAAE,2BAA2B;IAW/C;;;;;;;;OAQG;IACH,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,kBAAkB;IAgC1D,OAAO,CAAC,mBAAmB;IAyB3B,OAAO,CAAC,cAAc;IAsBtB,OAAO,CAAC,iBAAiB;IA4CzB,OAAO,CAAC,mBAAmB;IA2C3B;;;;;;;;;;;;;;;OAeG;IACG,kBAAkB,CACtB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,EAAE,OAAO,CAAA;QAC1B,MAAM,CAAC,EAAE,OAAO,CAAA;KACjB,GACA,OAAO,CAAC,cAAc,CAAC;IA+I1B;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO;IAQ5C;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,GAAG;QAClC,eAAe,EAAE,OAAO,CAAA;QACxB,YAAY,EAAE,MAAM,CAAA;QACpB,eAAe,EAAE,MAAM,CAAA;QACvB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAA;KAChC;CA+BF"}