@skillsmith/core 0.4.15 → 0.4.17

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 (221) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +57 -2
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/src/analysis/DependencyMerger.d.ts +39 -0
  5. package/dist/src/analysis/DependencyMerger.d.ts.map +1 -0
  6. package/dist/src/analysis/DependencyMerger.js +191 -0
  7. package/dist/src/analysis/DependencyMerger.js.map +1 -0
  8. package/dist/src/analysis/DependencyMerger.test.d.ts +2 -0
  9. package/dist/src/analysis/DependencyMerger.test.d.ts.map +1 -0
  10. package/dist/src/analysis/DependencyMerger.test.js +258 -0
  11. package/dist/src/analysis/DependencyMerger.test.js.map +1 -0
  12. package/dist/src/analysis/McpReferenceExtractor.d.ts +42 -0
  13. package/dist/src/analysis/McpReferenceExtractor.d.ts.map +1 -0
  14. package/dist/src/analysis/McpReferenceExtractor.js +92 -0
  15. package/dist/src/analysis/McpReferenceExtractor.js.map +1 -0
  16. package/dist/src/analysis/McpReferenceExtractor.test.d.ts +2 -0
  17. package/dist/src/analysis/McpReferenceExtractor.test.d.ts.map +1 -0
  18. package/dist/src/analysis/McpReferenceExtractor.test.js +262 -0
  19. package/dist/src/analysis/McpReferenceExtractor.test.js.map +1 -0
  20. package/dist/src/api/client.d.ts +2 -0
  21. package/dist/src/api/client.d.ts.map +1 -1
  22. package/dist/src/api/client.js.map +1 -1
  23. package/dist/src/db/drivers/sqljsDriver.d.ts.map +1 -1
  24. package/dist/src/db/drivers/sqljsDriver.js +4 -8
  25. package/dist/src/db/drivers/sqljsDriver.js.map +1 -1
  26. package/dist/src/db/migrations/v10-dependencies.d.ts +18 -0
  27. package/dist/src/db/migrations/v10-dependencies.d.ts.map +1 -0
  28. package/dist/src/db/migrations/v10-dependencies.js +50 -0
  29. package/dist/src/db/migrations/v10-dependencies.js.map +1 -0
  30. package/dist/src/db/migrations/v2-phase5-columns.d.ts +7 -0
  31. package/dist/src/db/migrations/v2-phase5-columns.d.ts.map +1 -0
  32. package/dist/src/db/migrations/v2-phase5-columns.js +16 -0
  33. package/dist/src/db/migrations/v2-phase5-columns.js.map +1 -0
  34. package/dist/src/db/migrations/v3-sync-tables.d.ts +6 -0
  35. package/dist/src/db/migrations/v3-sync-tables.d.ts.map +1 -0
  36. package/dist/src/db/migrations/v3-sync-tables.js +41 -0
  37. package/dist/src/db/migrations/v3-sync-tables.js.map +1 -0
  38. package/dist/src/db/migrations/v4-security-columns.d.ts +7 -0
  39. package/dist/src/db/migrations/v4-security-columns.d.ts.map +1 -0
  40. package/dist/src/db/migrations/v4-security-columns.js +17 -0
  41. package/dist/src/db/migrations/v4-security-columns.js.map +1 -0
  42. package/dist/src/db/schema.d.ts +2 -2
  43. package/dist/src/db/schema.d.ts.map +1 -1
  44. package/dist/src/db/schema.js +20 -58
  45. package/dist/src/db/schema.js.map +1 -1
  46. package/dist/src/embeddings/hnsw-store.d.ts +1 -1
  47. package/dist/src/embeddings/hnsw-store.d.ts.map +1 -1
  48. package/dist/src/embeddings/hnsw-store.js +4 -34
  49. package/dist/src/embeddings/hnsw-store.js.map +1 -1
  50. package/dist/src/embeddings/hnsw-store.types.d.ts +18 -0
  51. package/dist/src/embeddings/hnsw-store.types.d.ts.map +1 -1
  52. package/dist/src/embeddings/hnsw-store.types.js.map +1 -1
  53. package/dist/src/exports/repositories.d.ts +1 -0
  54. package/dist/src/exports/repositories.d.ts.map +1 -1
  55. package/dist/src/exports/repositories.js +4 -0
  56. package/dist/src/exports/repositories.js.map +1 -1
  57. package/dist/src/exports/services.d.ts +5 -0
  58. package/dist/src/exports/services.d.ts.map +1 -1
  59. package/dist/src/exports/services.js +11 -0
  60. package/dist/src/exports/services.js.map +1 -1
  61. package/dist/src/exports/types.d.ts +1 -0
  62. package/dist/src/exports/types.d.ts.map +1 -1
  63. package/dist/src/exports/types.js.map +1 -1
  64. package/dist/src/index.d.ts +1 -1
  65. package/dist/src/index.d.ts.map +1 -1
  66. package/dist/src/index.js +1 -1
  67. package/dist/src/index.js.map +1 -1
  68. package/dist/src/indexer/GitHubIndexer.d.ts +3 -1
  69. package/dist/src/indexer/GitHubIndexer.d.ts.map +1 -1
  70. package/dist/src/indexer/GitHubIndexer.js.map +1 -1
  71. package/dist/src/indexer/SkillParser.d.ts +20 -9
  72. package/dist/src/indexer/SkillParser.d.ts.map +1 -1
  73. package/dist/src/indexer/SkillParser.js +17 -10
  74. package/dist/src/indexer/SkillParser.js.map +1 -1
  75. package/dist/src/learning/PatternStore.d.ts.map +1 -1
  76. package/dist/src/learning/PatternStore.js +2 -9
  77. package/dist/src/learning/PatternStore.js.map +1 -1
  78. package/dist/src/repositories/IndexerRepository.d.ts.map +1 -1
  79. package/dist/src/repositories/IndexerRepository.js +5 -1
  80. package/dist/src/repositories/IndexerRepository.js.map +1 -1
  81. package/dist/src/repositories/SkillDependencyRepository.d.ts +73 -0
  82. package/dist/src/repositories/SkillDependencyRepository.d.ts.map +1 -0
  83. package/dist/src/repositories/SkillDependencyRepository.js +199 -0
  84. package/dist/src/repositories/SkillDependencyRepository.js.map +1 -0
  85. package/dist/src/routing/SONARouter.d.ts.map +1 -1
  86. package/dist/src/routing/SONARouter.js +4 -15
  87. package/dist/src/routing/SONARouter.js.map +1 -1
  88. package/dist/src/scripts/__tests__/scan-imported-skills.test.js +5 -0
  89. package/dist/src/scripts/__tests__/scan-imported-skills.test.js.map +1 -1
  90. package/dist/src/security/scanner/SecurityScanner.d.ts +4 -2
  91. package/dist/src/security/scanner/SecurityScanner.d.ts.map +1 -1
  92. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts +24 -2
  93. package/dist/src/security/scanner/SecurityScanner.helpers.d.ts.map +1 -1
  94. package/dist/src/security/scanner/SecurityScanner.helpers.js +99 -3
  95. package/dist/src/security/scanner/SecurityScanner.helpers.js.map +1 -1
  96. package/dist/src/security/scanner/SecurityScanner.js +29 -90
  97. package/dist/src/security/scanner/SecurityScanner.js.map +1 -1
  98. package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts +15 -0
  99. package/dist/src/security/scanner/SecurityScanner.ssrf.d.ts.map +1 -0
  100. package/dist/src/security/scanner/SecurityScanner.ssrf.js +76 -0
  101. package/dist/src/security/scanner/SecurityScanner.ssrf.js.map +1 -0
  102. package/dist/src/security/scanner/index.d.ts +1 -1
  103. package/dist/src/security/scanner/index.d.ts.map +1 -1
  104. package/dist/src/security/scanner/index.js +1 -1
  105. package/dist/src/security/scanner/index.js.map +1 -1
  106. package/dist/src/security/scanner/patterns.d.ts +6 -0
  107. package/dist/src/security/scanner/patterns.d.ts.map +1 -1
  108. package/dist/src/security/scanner/patterns.js +32 -0
  109. package/dist/src/security/scanner/patterns.js.map +1 -1
  110. package/dist/src/security/scanner/types.d.ts +2 -1
  111. package/dist/src/security/scanner/types.d.ts.map +1 -1
  112. package/dist/src/security/scanner/weights.d.ts.map +1 -1
  113. package/dist/src/security/scanner/weights.js +1 -0
  114. package/dist/src/security/scanner/weights.js.map +1 -1
  115. package/dist/src/services/skill-installation.helpers.d.ts +62 -0
  116. package/dist/src/services/skill-installation.helpers.d.ts.map +1 -0
  117. package/dist/src/services/skill-installation.helpers.js +335 -0
  118. package/dist/src/services/skill-installation.helpers.js.map +1 -0
  119. package/dist/src/services/skill-installation.service.d.ts +45 -0
  120. package/dist/src/services/skill-installation.service.d.ts.map +1 -0
  121. package/dist/src/services/skill-installation.service.js +383 -0
  122. package/dist/src/services/skill-installation.service.js.map +1 -0
  123. package/dist/src/services/skill-installation.types.d.ts +144 -0
  124. package/dist/src/services/skill-installation.types.d.ts.map +1 -0
  125. package/dist/src/services/skill-installation.types.js +38 -0
  126. package/dist/src/services/skill-installation.types.js.map +1 -0
  127. package/dist/src/services/skill-manifest.d.ts +20 -0
  128. package/dist/src/services/skill-manifest.d.ts.map +1 -0
  129. package/dist/src/services/skill-manifest.js +84 -0
  130. package/dist/src/services/skill-manifest.js.map +1 -0
  131. package/dist/src/session/SessionManager.helpers.d.ts +1 -27
  132. package/dist/src/session/SessionManager.helpers.d.ts.map +1 -1
  133. package/dist/src/session/SessionManager.helpers.js +0 -64
  134. package/dist/src/session/SessionManager.helpers.js.map +1 -1
  135. package/dist/src/session/SessionManager.memory.d.ts +12 -11
  136. package/dist/src/session/SessionManager.memory.d.ts.map +1 -1
  137. package/dist/src/session/SessionManager.memory.js +23 -115
  138. package/dist/src/session/SessionManager.memory.js.map +1 -1
  139. package/dist/src/session/SessionManager.types.d.ts +0 -37
  140. package/dist/src/session/SessionManager.types.d.ts.map +1 -1
  141. package/dist/src/session/SessionManager.types.js.map +1 -1
  142. package/dist/src/session/SessionRecovery.js +4 -4
  143. package/dist/src/session/SessionRecovery.js.map +1 -1
  144. package/dist/src/sources/SourceIndexer.d.ts +3 -1
  145. package/dist/src/sources/SourceIndexer.d.ts.map +1 -1
  146. package/dist/src/sources/SourceIndexer.js.map +1 -1
  147. package/dist/src/testing/MultiLLMProvider.d.ts.map +1 -1
  148. package/dist/src/testing/MultiLLMProvider.js +5 -19
  149. package/dist/src/testing/MultiLLMProvider.js.map +1 -1
  150. package/dist/src/types/dependencies.d.ts +85 -0
  151. package/dist/src/types/dependencies.d.ts.map +1 -0
  152. package/dist/src/types/dependencies.js +11 -0
  153. package/dist/src/types/dependencies.js.map +1 -0
  154. package/dist/src/types/skill.d.ts +3 -0
  155. package/dist/src/types/skill.d.ts.map +1 -1
  156. package/dist/src/types/skill.js.map +1 -1
  157. package/dist/src/types.d.ts +2 -0
  158. package/dist/src/types.d.ts.map +1 -1
  159. package/dist/tests/DailyIndexPipeline.test.js +3 -3
  160. package/dist/tests/DailyIndexPipeline.test.js.map +1 -1
  161. package/dist/tests/GitHubIndexer.test.js +4 -2
  162. package/dist/tests/GitHubIndexer.test.js.map +1 -1
  163. package/dist/tests/billing/StripeClient.test.d.ts +18 -0
  164. package/dist/tests/billing/StripeClient.test.d.ts.map +1 -0
  165. package/dist/tests/billing/StripeClient.test.js +566 -0
  166. package/dist/tests/billing/StripeClient.test.js.map +1 -0
  167. package/dist/tests/billing/StripeWebhookHandler.test.d.ts +16 -0
  168. package/dist/tests/billing/StripeWebhookHandler.test.d.ts.map +1 -0
  169. package/dist/tests/billing/StripeWebhookHandler.test.js +240 -0
  170. package/dist/tests/billing/StripeWebhookHandler.test.js.map +1 -0
  171. package/dist/tests/billing/stripe-helpers.test.d.ts +7 -0
  172. package/dist/tests/billing/stripe-helpers.test.d.ts.map +1 -0
  173. package/dist/tests/billing/stripe-helpers.test.js +91 -0
  174. package/dist/tests/billing/stripe-helpers.test.js.map +1 -0
  175. package/dist/tests/billing/webhook-handlers.test.d.ts +16 -0
  176. package/dist/tests/billing/webhook-handlers.test.d.ts.map +1 -0
  177. package/dist/tests/billing/webhook-handlers.test.js +519 -0
  178. package/dist/tests/billing/webhook-handlers.test.js.map +1 -0
  179. package/dist/tests/db/migration.test.d.ts +11 -0
  180. package/dist/tests/db/migration.test.d.ts.map +1 -0
  181. package/dist/tests/db/migration.test.js +265 -0
  182. package/dist/tests/db/migration.test.js.map +1 -0
  183. package/dist/tests/edge-cases/EdgeCases.test.js +4 -1
  184. package/dist/tests/edge-cases/EdgeCases.test.js.map +1 -1
  185. package/dist/tests/repositories/SkillDependencyRepository.test.d.ts +10 -0
  186. package/dist/tests/repositories/SkillDependencyRepository.test.d.ts.map +1 -0
  187. package/dist/tests/repositories/SkillDependencyRepository.test.js +336 -0
  188. package/dist/tests/repositories/SkillDependencyRepository.test.js.map +1 -0
  189. package/dist/tests/security/ContinuousSecurity.test.js +2 -2
  190. package/dist/tests/security/ContinuousSecurity.test.js.map +1 -1
  191. package/dist/tests/security.test.js +200 -0
  192. package/dist/tests/security.test.js.map +1 -1
  193. package/dist/tests/session/SessionManager.helpers.test.js +1 -9
  194. package/dist/tests/session/SessionManager.helpers.test.js.map +1 -1
  195. package/dist/tests/session/SessionManager.memory.test.d.ts +3 -4
  196. package/dist/tests/session/SessionManager.memory.test.d.ts.map +1 -1
  197. package/dist/tests/session/SessionManager.memory.test.js +41 -123
  198. package/dist/tests/session/SessionManager.memory.test.js.map +1 -1
  199. package/dist/tests/sources.test.js +1 -1
  200. package/dist/tests/sources.test.js.map +1 -1
  201. package/dist/tests/sync/BackgroundSyncService.test.d.ts +13 -0
  202. package/dist/tests/sync/BackgroundSyncService.test.d.ts.map +1 -0
  203. package/dist/tests/sync/BackgroundSyncService.test.js +259 -0
  204. package/dist/tests/sync/BackgroundSyncService.test.js.map +1 -0
  205. package/dist/tests/testkit.d.ts +14 -0
  206. package/dist/tests/testkit.d.ts.map +1 -0
  207. package/dist/tests/testkit.js +14 -0
  208. package/dist/tests/testkit.js.map +1 -0
  209. package/dist/tests/unit/migrations/v10-dependencies.test.d.ts +6 -0
  210. package/dist/tests/unit/migrations/v10-dependencies.test.d.ts.map +1 -0
  211. package/dist/tests/unit/migrations/v10-dependencies.test.js +166 -0
  212. package/dist/tests/unit/migrations/v10-dependencies.test.js.map +1 -0
  213. package/dist/tests/unit/services/skill-installation.service.test.d.ts +8 -0
  214. package/dist/tests/unit/services/skill-installation.service.test.d.ts.map +1 -0
  215. package/dist/tests/unit/services/skill-installation.service.test.js +732 -0
  216. package/dist/tests/unit/services/skill-installation.service.test.js.map +1 -0
  217. package/package.json +19 -7
  218. package/dist/vitest.config.d.ts +0 -3
  219. package/dist/vitest.config.d.ts.map +0 -1
  220. package/dist/vitest.config.js +0 -13
  221. package/dist/vitest.config.js.map +0 -1
@@ -0,0 +1,519 @@
1
+ /**
2
+ * SMI-3415: Webhook Handler Functions Tests
3
+ *
4
+ * Tests for individual webhook event handler functions:
5
+ * - handleSubscriptionCreated (with/without license key, email)
6
+ * - handleSubscriptionUpdated (existing sub, tier change, new sub fallback)
7
+ * - handleSubscriptionDeleted (with email, without existing sub)
8
+ * - handleInvoicePaymentSucceeded (store invoice, missing customer)
9
+ * - handleInvoicePaymentFailed (store + email, missing customer)
10
+ * - handleCheckoutSessionCompleted (logging-only)
11
+ * - storeLicenseKey / revokeLicenseKey (DB operations)
12
+ * - extractTier / extractSeatCount / getCurrentPeriodEnd / getCurrentPeriodStart
13
+ * - extractSubscriptionIdFromInvoice
14
+ */
15
+ import { describe, it, expect, vi } from 'vitest';
16
+ import { handleSubscriptionCreated, handleSubscriptionUpdated, handleSubscriptionDeleted, handleInvoicePaymentSucceeded, handleInvoicePaymentFailed, handleCheckoutSessionCompleted, storeLicenseKey, revokeLicenseKey, extractTier, extractSeatCount, getCurrentPeriodEnd, getCurrentPeriodStart, extractSubscriptionIdFromInvoice, } from '../../src/billing/webhook-handlers.js';
17
+ // ============================================================================
18
+ // Test Fixtures
19
+ // ============================================================================
20
+ function createMockDb() {
21
+ const runFn = vi.fn();
22
+ return {
23
+ prepare: vi.fn().mockReturnValue({ run: runFn, get: vi.fn(), all: vi.fn() }),
24
+ exec: vi.fn(),
25
+ close: vi.fn(),
26
+ };
27
+ }
28
+ function createMockStripeClient() {
29
+ return {
30
+ getCustomer: vi.fn(),
31
+ verifyWebhookSignature: vi.fn(),
32
+ mapSubscriptionStatus: vi.fn(),
33
+ };
34
+ }
35
+ function createMockBillingService() {
36
+ return {
37
+ upsertSubscription: vi.fn().mockReturnValue({ id: 'local_sub_1', tier: 'individual' }),
38
+ getSubscriptionByStripeId: vi.fn().mockReturnValue(null),
39
+ updateSubscriptionStatus: vi.fn(),
40
+ storeInvoice: vi.fn(),
41
+ isEventProcessed: vi.fn().mockReturnValue(false),
42
+ recordWebhookEvent: vi.fn(),
43
+ };
44
+ }
45
+ function createContext(overrides = {}) {
46
+ return {
47
+ stripe: createMockStripeClient(),
48
+ billing: createMockBillingService(),
49
+ db: createMockDb(),
50
+ ...overrides,
51
+ };
52
+ }
53
+ function makeSubscription(overrides = {}) {
54
+ return {
55
+ id: 'sub_test_1',
56
+ customer: 'cus_test_1',
57
+ status: 'active',
58
+ metadata: { tier: 'team', seatCount: '5' },
59
+ items: {
60
+ data: [
61
+ {
62
+ id: 'si_1',
63
+ price: { id: 'price_team_monthly' },
64
+ quantity: 5,
65
+ current_period_start: 1700000000,
66
+ current_period_end: 1702592000,
67
+ },
68
+ ],
69
+ },
70
+ canceled_at: null,
71
+ ...overrides,
72
+ };
73
+ }
74
+ function makeInvoice(overrides = {}) {
75
+ return {
76
+ id: 'in_test_1',
77
+ customer: 'cus_test_1',
78
+ amount_paid: 2500,
79
+ amount_due: 2500,
80
+ currency: 'usd',
81
+ number: 'INV-001',
82
+ invoice_pdf: 'https://pdf.url',
83
+ hosted_invoice_url: 'https://hosted.url',
84
+ status_transitions: { paid_at: 1700000000 },
85
+ period_start: 1700000000,
86
+ period_end: 1702592000,
87
+ parent: {
88
+ subscription_details: {
89
+ subscription: 'sub_test_1',
90
+ },
91
+ },
92
+ ...overrides,
93
+ };
94
+ }
95
+ // ============================================================================
96
+ // Pure Helper Functions
97
+ // ============================================================================
98
+ describe('extractTier', () => {
99
+ it('should extract tier from metadata', () => {
100
+ const sub = makeSubscription({ metadata: { tier: 'enterprise' } });
101
+ expect(extractTier(sub)).toBe('enterprise');
102
+ });
103
+ it('should accept all valid tiers from metadata', () => {
104
+ for (const tier of ['community', 'individual', 'team', 'enterprise']) {
105
+ const sub = makeSubscription({ metadata: { tier } });
106
+ expect(extractTier(sub)).toBe(tier);
107
+ }
108
+ });
109
+ it('should default to individual for missing metadata', () => {
110
+ const sub = makeSubscription({ metadata: {} });
111
+ expect(extractTier(sub)).toBe('individual');
112
+ });
113
+ it('should default to individual for invalid tier in metadata', () => {
114
+ const sub = makeSubscription({ metadata: { tier: 'platinum' } });
115
+ expect(extractTier(sub)).toBe('individual');
116
+ });
117
+ });
118
+ describe('extractSeatCount', () => {
119
+ it('should extract seat count from metadata', () => {
120
+ const sub = makeSubscription({ metadata: { seatCount: '10' } });
121
+ expect(extractSeatCount(sub)).toBe(10);
122
+ });
123
+ it('should fall back to item quantity when metadata missing', () => {
124
+ const sub = makeSubscription({ metadata: {} });
125
+ expect(extractSeatCount(sub)).toBe(5); // from fixture item quantity
126
+ });
127
+ it('should fall back to item quantity for non-numeric metadata', () => {
128
+ const sub = makeSubscription({ metadata: { seatCount: 'abc' } });
129
+ expect(extractSeatCount(sub)).toBe(5);
130
+ });
131
+ it('should fall back to item quantity for zero seat count', () => {
132
+ const sub = makeSubscription({ metadata: { seatCount: '0' } });
133
+ expect(extractSeatCount(sub)).toBe(5);
134
+ });
135
+ it('should fall back to item quantity for negative seat count', () => {
136
+ const sub = makeSubscription({ metadata: { seatCount: '-1' } });
137
+ expect(extractSeatCount(sub)).toBe(5);
138
+ });
139
+ it('should return 1 when no items and no metadata', () => {
140
+ const sub = makeSubscription({
141
+ metadata: {},
142
+ items: { data: [{ quantity: undefined, current_period_end: 1702592000 }] },
143
+ });
144
+ expect(extractSeatCount(sub)).toBe(1);
145
+ });
146
+ });
147
+ describe('getCurrentPeriodEnd', () => {
148
+ it('should return period end from first item', () => {
149
+ const sub = makeSubscription();
150
+ expect(getCurrentPeriodEnd(sub)).toBe(1702592000);
151
+ });
152
+ it('should return current timestamp when no items', () => {
153
+ const sub = makeSubscription({ items: { data: [] } });
154
+ const now = Math.floor(Date.now() / 1000);
155
+ const result = getCurrentPeriodEnd(sub);
156
+ // Should be within 2 seconds of now
157
+ expect(Math.abs(result - now)).toBeLessThan(2);
158
+ });
159
+ });
160
+ describe('getCurrentPeriodStart', () => {
161
+ it('should return period start from first item', () => {
162
+ const sub = makeSubscription();
163
+ expect(getCurrentPeriodStart(sub)).toBe(1700000000);
164
+ });
165
+ it('should return current timestamp when no items', () => {
166
+ const sub = makeSubscription({ items: { data: [] } });
167
+ const now = Math.floor(Date.now() / 1000);
168
+ const result = getCurrentPeriodStart(sub);
169
+ expect(Math.abs(result - now)).toBeLessThan(2);
170
+ });
171
+ });
172
+ describe('extractSubscriptionIdFromInvoice', () => {
173
+ it('should extract string subscription ID', () => {
174
+ const invoice = makeInvoice();
175
+ expect(extractSubscriptionIdFromInvoice(invoice)).toBe('sub_test_1');
176
+ });
177
+ it('should extract ID from subscription object', () => {
178
+ const invoice = makeInvoice({
179
+ parent: {
180
+ subscription_details: {
181
+ subscription: { id: 'sub_obj_1' },
182
+ },
183
+ },
184
+ });
185
+ expect(extractSubscriptionIdFromInvoice(invoice)).toBe('sub_obj_1');
186
+ });
187
+ it('should return undefined when no parent', () => {
188
+ const invoice = makeInvoice({ parent: undefined });
189
+ expect(extractSubscriptionIdFromInvoice(invoice)).toBeUndefined();
190
+ });
191
+ it('should return undefined when no subscription_details', () => {
192
+ const invoice = makeInvoice({ parent: {} });
193
+ expect(extractSubscriptionIdFromInvoice(invoice)).toBeUndefined();
194
+ });
195
+ it('should return undefined when subscription is null', () => {
196
+ const invoice = makeInvoice({
197
+ parent: { subscription_details: { subscription: null } },
198
+ });
199
+ expect(extractSubscriptionIdFromInvoice(invoice)).toBeUndefined();
200
+ });
201
+ });
202
+ // ============================================================================
203
+ // License Key DB Operations
204
+ // ============================================================================
205
+ describe('storeLicenseKey', () => {
206
+ it('should insert a license key record', () => {
207
+ const db = createMockDb();
208
+ const runFn = vi.fn();
209
+ vi.mocked(db.prepare).mockReturnValue({ run: runFn });
210
+ storeLicenseKey(db, {
211
+ subscriptionId: 'sub_1',
212
+ organizationId: 'org_1',
213
+ keyJwt: 'jwt_token_value',
214
+ keyExpiry: new Date('2026-12-31'),
215
+ });
216
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO license_keys'));
217
+ expect(runFn).toHaveBeenCalledWith(expect.any(String), // UUID
218
+ 'sub_1', 'org_1', 'jwt_token_value', expect.any(String), // SHA-256 hash
219
+ '2026-12-31T00:00:00.000Z', expect.any(String) // generated_at ISO
220
+ );
221
+ });
222
+ });
223
+ describe('revokeLicenseKey', () => {
224
+ it('should update license key to inactive', () => {
225
+ const db = createMockDb();
226
+ const runFn = vi.fn();
227
+ vi.mocked(db.prepare).mockReturnValue({ run: runFn });
228
+ revokeLicenseKey(db, 'sub_1', 'tier_change');
229
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('UPDATE license_keys'));
230
+ expect(runFn).toHaveBeenCalledWith(expect.any(String), 'tier_change', 'sub_1');
231
+ });
232
+ });
233
+ // ============================================================================
234
+ // handleSubscriptionCreated
235
+ // ============================================================================
236
+ describe('handleSubscriptionCreated', () => {
237
+ it('should create subscription record when customer found', async () => {
238
+ const ctx = createContext();
239
+ const sub = makeSubscription();
240
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
241
+ id: 'cus_test_1',
242
+ email: 'user@example.com',
243
+ deleted: false,
244
+ });
245
+ await handleSubscriptionCreated(ctx, sub);
246
+ expect(ctx.billing.upsertSubscription).toHaveBeenCalledWith(expect.objectContaining({
247
+ customerId: 'cus_test_1',
248
+ email: 'user@example.com',
249
+ stripeSubscriptionId: 'sub_test_1',
250
+ tier: 'team',
251
+ seatCount: 5,
252
+ }));
253
+ });
254
+ it('should throw when customer not found', async () => {
255
+ const ctx = createContext();
256
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue(null);
257
+ await expect(handleSubscriptionCreated(ctx, makeSubscription())).rejects.toThrow('Customer not found');
258
+ });
259
+ it('should generate and store license key for active subscription', async () => {
260
+ const onLicenseKeyNeeded = vi.fn().mockResolvedValue('jwt_license_123');
261
+ const db = createMockDb();
262
+ const runFn = vi.fn();
263
+ vi.mocked(db.prepare).mockReturnValue({ run: runFn });
264
+ const ctx = createContext({ onLicenseKeyNeeded, db });
265
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
266
+ id: 'cus_test_1',
267
+ email: 'user@example.com',
268
+ deleted: false,
269
+ });
270
+ await handleSubscriptionCreated(ctx, makeSubscription({ status: 'active' }));
271
+ expect(onLicenseKeyNeeded).toHaveBeenCalledWith(expect.objectContaining({
272
+ customerId: 'cus_test_1',
273
+ tier: 'team',
274
+ }));
275
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO license_keys'));
276
+ });
277
+ it('should send license key email when onEmailNeeded provided', async () => {
278
+ const onLicenseKeyNeeded = vi.fn().mockResolvedValue('jwt_license_456');
279
+ const onEmailNeeded = vi.fn().mockResolvedValue(undefined);
280
+ const db = createMockDb();
281
+ vi.mocked(db.prepare).mockReturnValue({ run: vi.fn() });
282
+ const ctx = createContext({ onLicenseKeyNeeded, onEmailNeeded, db });
283
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
284
+ id: 'cus_test_1',
285
+ email: 'user@example.com',
286
+ deleted: false,
287
+ });
288
+ await handleSubscriptionCreated(ctx, makeSubscription({ status: 'active' }));
289
+ expect(onEmailNeeded).toHaveBeenCalledWith(expect.objectContaining({
290
+ type: 'license_key',
291
+ email: 'user@example.com',
292
+ data: expect.objectContaining({ licenseKey: 'jwt_license_456', tier: 'team' }),
293
+ }));
294
+ });
295
+ it('should skip license key for non-active subscription', async () => {
296
+ const onLicenseKeyNeeded = vi.fn();
297
+ const ctx = createContext({ onLicenseKeyNeeded });
298
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
299
+ id: 'cus_test_1',
300
+ email: 'user@example.com',
301
+ deleted: false,
302
+ });
303
+ await handleSubscriptionCreated(ctx, makeSubscription({ status: 'trialing' }));
304
+ expect(onLicenseKeyNeeded).not.toHaveBeenCalled();
305
+ });
306
+ });
307
+ // ============================================================================
308
+ // handleSubscriptionUpdated
309
+ // ============================================================================
310
+ describe('handleSubscriptionUpdated', () => {
311
+ it('should create subscription if not found locally', async () => {
312
+ const ctx = createContext();
313
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue(null);
314
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
315
+ id: 'cus_test_1',
316
+ email: 'user@example.com',
317
+ deleted: false,
318
+ });
319
+ await handleSubscriptionUpdated(ctx, makeSubscription());
320
+ expect(ctx.billing.upsertSubscription).toHaveBeenCalled();
321
+ });
322
+ it('should update status for existing subscription', async () => {
323
+ const ctx = createContext();
324
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
325
+ id: 'local_sub_1',
326
+ tier: 'team',
327
+ });
328
+ const sub = makeSubscription({ status: 'past_due', canceled_at: null });
329
+ await handleSubscriptionUpdated(ctx, sub);
330
+ expect(ctx.billing.updateSubscriptionStatus).toHaveBeenCalledWith('sub_test_1', 'past_due', null);
331
+ });
332
+ it('should pass canceled_at date when present', async () => {
333
+ const ctx = createContext();
334
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
335
+ id: 'local_sub_1',
336
+ tier: 'team',
337
+ });
338
+ const sub = makeSubscription({ status: 'canceled', canceled_at: 1700000000 });
339
+ await handleSubscriptionUpdated(ctx, sub);
340
+ expect(ctx.billing.updateSubscriptionStatus).toHaveBeenCalledWith('sub_test_1', 'canceled', new Date(1700000000 * 1000));
341
+ });
342
+ it('should regenerate license key on tier change', async () => {
343
+ const onLicenseKeyNeeded = vi.fn().mockResolvedValue('new_jwt');
344
+ const db = createMockDb();
345
+ const runFn = vi.fn();
346
+ vi.mocked(db.prepare).mockReturnValue({ run: runFn });
347
+ const ctx = createContext({ onLicenseKeyNeeded, db });
348
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
349
+ id: 'local_sub_1',
350
+ tier: 'individual', // old tier
351
+ });
352
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
353
+ id: 'cus_test_1',
354
+ email: 'user@example.com',
355
+ });
356
+ // New tier is 'team' from metadata
357
+ await handleSubscriptionUpdated(ctx, makeSubscription({ metadata: { tier: 'team' } }));
358
+ // Should revoke old key
359
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('UPDATE license_keys'));
360
+ // Should generate new key
361
+ expect(onLicenseKeyNeeded).toHaveBeenCalledWith(expect.objectContaining({ tier: 'team' }));
362
+ // Should store new key
363
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('INSERT INTO license_keys'));
364
+ });
365
+ it('should not regenerate license key when tier unchanged', async () => {
366
+ const onLicenseKeyNeeded = vi.fn();
367
+ const ctx = createContext({ onLicenseKeyNeeded });
368
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
369
+ id: 'local_sub_1',
370
+ tier: 'team', // same as metadata
371
+ });
372
+ await handleSubscriptionUpdated(ctx, makeSubscription({ metadata: { tier: 'team' } }));
373
+ expect(onLicenseKeyNeeded).not.toHaveBeenCalled();
374
+ });
375
+ });
376
+ // ============================================================================
377
+ // handleSubscriptionDeleted
378
+ // ============================================================================
379
+ describe('handleSubscriptionDeleted', () => {
380
+ it('should cancel subscription and revoke license key', async () => {
381
+ const db = createMockDb();
382
+ const runFn = vi.fn();
383
+ vi.mocked(db.prepare).mockReturnValue({ run: runFn });
384
+ const ctx = createContext({ db });
385
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
386
+ id: 'local_sub_1',
387
+ tier: 'team',
388
+ });
389
+ await handleSubscriptionDeleted(ctx, makeSubscription());
390
+ expect(ctx.billing.updateSubscriptionStatus).toHaveBeenCalledWith('sub_test_1', 'canceled', expect.any(Date));
391
+ expect(db.prepare).toHaveBeenCalledWith(expect.stringContaining('UPDATE license_keys'));
392
+ });
393
+ it('should send cancellation email', async () => {
394
+ const onEmailNeeded = vi.fn().mockResolvedValue(undefined);
395
+ const db = createMockDb();
396
+ vi.mocked(db.prepare).mockReturnValue({ run: vi.fn() });
397
+ const ctx = createContext({ onEmailNeeded, db });
398
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue({
399
+ id: 'local_sub_1',
400
+ tier: 'team',
401
+ });
402
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
403
+ id: 'cus_test_1',
404
+ email: 'user@example.com',
405
+ });
406
+ await handleSubscriptionDeleted(ctx, makeSubscription());
407
+ expect(onEmailNeeded).toHaveBeenCalledWith(expect.objectContaining({
408
+ type: 'subscription_canceled',
409
+ email: 'user@example.com',
410
+ }));
411
+ });
412
+ it('should do nothing when subscription not found locally', async () => {
413
+ const ctx = createContext();
414
+ vi.mocked(ctx.billing.getSubscriptionByStripeId).mockReturnValue(null);
415
+ await handleSubscriptionDeleted(ctx, makeSubscription());
416
+ expect(ctx.billing.updateSubscriptionStatus).not.toHaveBeenCalled();
417
+ });
418
+ });
419
+ // ============================================================================
420
+ // handleInvoicePaymentSucceeded
421
+ // ============================================================================
422
+ describe('handleInvoicePaymentSucceeded', () => {
423
+ it('should store paid invoice', async () => {
424
+ const ctx = createContext();
425
+ const invoice = makeInvoice();
426
+ await handleInvoicePaymentSucceeded(ctx, invoice);
427
+ expect(ctx.billing.storeInvoice).toHaveBeenCalledWith(expect.objectContaining({
428
+ customerId: 'cus_test_1',
429
+ stripeInvoiceId: 'in_test_1',
430
+ status: 'paid',
431
+ amountCents: 2500,
432
+ currency: 'usd',
433
+ subscriptionId: 'sub_test_1',
434
+ }));
435
+ });
436
+ it('should handle customer as object', async () => {
437
+ const ctx = createContext();
438
+ const invoice = makeInvoice({ customer: { id: 'cus_obj_1' } });
439
+ await handleInvoicePaymentSucceeded(ctx, invoice);
440
+ expect(ctx.billing.storeInvoice).toHaveBeenCalledWith(expect.objectContaining({ customerId: 'cus_obj_1' }));
441
+ });
442
+ it('should skip when no customer ID', async () => {
443
+ const ctx = createContext();
444
+ const invoice = makeInvoice({ customer: null });
445
+ await handleInvoicePaymentSucceeded(ctx, invoice);
446
+ expect(ctx.billing.storeInvoice).not.toHaveBeenCalled();
447
+ });
448
+ it('should handle missing status_transitions.paid_at', async () => {
449
+ const ctx = createContext();
450
+ const invoice = makeInvoice({ status_transitions: {} });
451
+ await handleInvoicePaymentSucceeded(ctx, invoice);
452
+ expect(ctx.billing.storeInvoice).toHaveBeenCalledWith(expect.objectContaining({
453
+ paidAt: expect.any(Date),
454
+ }));
455
+ });
456
+ });
457
+ // ============================================================================
458
+ // handleInvoicePaymentFailed
459
+ // ============================================================================
460
+ describe('handleInvoicePaymentFailed', () => {
461
+ it('should store open invoice', async () => {
462
+ const ctx = createContext();
463
+ const invoice = makeInvoice();
464
+ await handleInvoicePaymentFailed(ctx, invoice);
465
+ expect(ctx.billing.storeInvoice).toHaveBeenCalledWith(expect.objectContaining({
466
+ customerId: 'cus_test_1',
467
+ stripeInvoiceId: 'in_test_1',
468
+ status: 'open',
469
+ amountCents: 2500,
470
+ }));
471
+ });
472
+ it('should send payment failed email', async () => {
473
+ const onEmailNeeded = vi.fn().mockResolvedValue(undefined);
474
+ const ctx = createContext({ onEmailNeeded });
475
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
476
+ id: 'cus_test_1',
477
+ email: 'user@example.com',
478
+ });
479
+ await handleInvoicePaymentFailed(ctx, makeInvoice());
480
+ expect(onEmailNeeded).toHaveBeenCalledWith(expect.objectContaining({
481
+ type: 'payment_failed',
482
+ email: 'user@example.com',
483
+ data: expect.objectContaining({
484
+ invoiceId: 'in_test_1',
485
+ amount: 2500,
486
+ }),
487
+ }));
488
+ });
489
+ it('should skip when no customer ID', async () => {
490
+ const ctx = createContext();
491
+ const invoice = makeInvoice({ customer: null });
492
+ await handleInvoicePaymentFailed(ctx, invoice);
493
+ expect(ctx.billing.storeInvoice).not.toHaveBeenCalled();
494
+ });
495
+ it('should skip email when customer has no email', async () => {
496
+ const onEmailNeeded = vi.fn();
497
+ const ctx = createContext({ onEmailNeeded });
498
+ vi.mocked(ctx.stripe.getCustomer).mockResolvedValue({
499
+ id: 'cus_test_1',
500
+ email: null,
501
+ });
502
+ await handleInvoicePaymentFailed(ctx, makeInvoice());
503
+ expect(onEmailNeeded).not.toHaveBeenCalled();
504
+ });
505
+ });
506
+ // ============================================================================
507
+ // handleCheckoutSessionCompleted
508
+ // ============================================================================
509
+ describe('handleCheckoutSessionCompleted', () => {
510
+ it('should not throw (logging-only handler)', () => {
511
+ const session = {
512
+ id: 'cs_test_1',
513
+ customer: 'cus_test_1',
514
+ subscription: 'sub_test_1',
515
+ };
516
+ expect(() => handleCheckoutSessionCompleted(session)).not.toThrow();
517
+ });
518
+ });
519
+ //# sourceMappingURL=webhook-handlers.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-handlers.test.js","sourceRoot":"","sources":["../../../tests/billing/webhook-handlers.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * SMI-3416: Database Migration Utility Tests
3
+ *
4
+ * Tests for migration.ts:
5
+ * - checkSchemaCompatibility: version detection and compatibility
6
+ * - ensureSchemaCompatibility: auto-upgrade/warning/error
7
+ * - mergeSkillDatabases: three-way skill merge with strategies
8
+ * - getSyncStatus / updateSyncStatus / recordSyncRun / getSyncHistory
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=migration.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration.test.d.ts","sourceRoot":"","sources":["../../../tests/db/migration.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}