fresh-squeezy 1.0.20 → 1.0.47

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.

Potentially problematic release.


This version of fresh-squeezy might be problematic. Click here for more details.

Files changed (229) hide show
  1. package/README.md +176 -108
  2. package/dist/src/cli/cli.js +1 -1
  3. package/dist/src/cli/cli.js.map +1 -1
  4. package/dist/src/cli/paths.d.ts +4 -0
  5. package/dist/src/cli/paths.d.ts.map +1 -0
  6. package/dist/src/cli/paths.js +7 -0
  7. package/dist/src/cli/paths.js.map +1 -0
  8. package/dist/src/core/cache.d.ts.map +1 -1
  9. package/dist/src/core/cache.js +1 -1
  10. package/dist/src/core/cache.js.map +1 -1
  11. package/dist/src/core/licenses.d.ts.map +1 -1
  12. package/dist/src/core/licenses.js +55 -21
  13. package/dist/src/core/licenses.js.map +1 -1
  14. package/dist/src/core/paths.d.ts +6 -0
  15. package/dist/src/core/paths.d.ts.map +1 -0
  16. package/dist/src/core/paths.js +6 -0
  17. package/dist/src/core/paths.js.map +1 -0
  18. package/dist/src/core/webhook.d.ts.map +1 -1
  19. package/dist/src/core/webhook.js +19 -39
  20. package/dist/src/core/webhook.js.map +1 -1
  21. package/dist/src/types/billing/billing.d.ts +4 -1
  22. package/dist/src/types/billing/billing.d.ts.map +1 -1
  23. package/dist/src/types/billing/types.d.ts +3 -9
  24. package/dist/src/types/billing/types.d.ts.map +1 -1
  25. package/dist/src/types/config/types.d.ts +2 -96
  26. package/dist/src/types/config/types.d.ts.map +1 -1
  27. package/dist/src/types/license/types.d.ts +14 -2
  28. package/dist/src/types/license/types.d.ts.map +1 -1
  29. package/dist/src/types/management/types.d.ts +4 -1
  30. package/dist/src/types/management/types.d.ts.map +1 -1
  31. package/dist/src/types/subscription/types.d.ts +2 -0
  32. package/dist/src/types/subscription/types.d.ts.map +1 -1
  33. package/dist/src/wizard/components/banner.d.ts +2 -0
  34. package/dist/src/wizard/components/banner.d.ts.map +1 -0
  35. package/dist/src/wizard/components/banner.js +6 -0
  36. package/dist/src/wizard/components/banner.js.map +1 -0
  37. package/dist/src/wizard/components/loading.d.ts +9 -0
  38. package/dist/src/wizard/components/loading.d.ts.map +1 -0
  39. package/dist/src/wizard/components/loading.js +31 -0
  40. package/dist/src/wizard/components/loading.js.map +1 -0
  41. package/dist/src/wizard/index.d.ts +2 -0
  42. package/dist/src/wizard/index.d.ts.map +1 -0
  43. package/dist/src/wizard/index.js +2 -0
  44. package/dist/src/wizard/index.js.map +1 -0
  45. package/dist/src/wizard/main.d.ts +6 -0
  46. package/dist/src/wizard/main.d.ts.map +1 -0
  47. package/dist/src/wizard/main.js +98 -0
  48. package/dist/src/wizard/main.js.map +1 -0
  49. package/dist/src/wizard/state.d.ts +15 -0
  50. package/dist/src/wizard/state.d.ts.map +1 -0
  51. package/dist/src/wizard/state.js +2 -0
  52. package/dist/src/wizard/state.js.map +1 -0
  53. package/dist/src/wizard/steps/api-key.d.ts +9 -0
  54. package/dist/src/wizard/steps/api-key.d.ts.map +1 -0
  55. package/dist/src/wizard/steps/api-key.js +91 -0
  56. package/dist/src/wizard/steps/api-key.js.map +1 -0
  57. package/dist/src/wizard/steps/checkout-optional.d.ts +2 -0
  58. package/dist/src/wizard/steps/checkout-optional.d.ts.map +1 -0
  59. package/dist/src/wizard/steps/checkout-optional.js +63 -0
  60. package/dist/src/wizard/steps/checkout-optional.js.map +1 -0
  61. package/dist/src/wizard/steps/configuration.d.ts +10 -0
  62. package/dist/src/wizard/steps/configuration.d.ts.map +1 -0
  63. package/dist/src/wizard/steps/configuration.js +33 -0
  64. package/dist/src/wizard/steps/configuration.js.map +1 -0
  65. package/dist/src/wizard/steps/generate-files.d.ts +4 -0
  66. package/dist/src/wizard/steps/generate-files.d.ts.map +1 -0
  67. package/dist/src/wizard/steps/generate-files.js +48 -0
  68. package/dist/src/wizard/steps/generate-files.js.map +1 -0
  69. package/dist/src/wizard/steps/product-selection.d.ts +7 -0
  70. package/dist/src/wizard/steps/product-selection.d.ts.map +1 -0
  71. package/dist/src/wizard/steps/product-selection.js +54 -0
  72. package/dist/src/wizard/steps/product-selection.js.map +1 -0
  73. package/dist/src/wizard/steps/store-selection.d.ts +3 -0
  74. package/dist/src/wizard/steps/store-selection.d.ts.map +1 -0
  75. package/dist/src/wizard/steps/store-selection.js +33 -0
  76. package/dist/src/wizard/steps/store-selection.js.map +1 -0
  77. package/dist/src/wizard/steps/webhook-setup.d.ts +5 -0
  78. package/dist/src/wizard/steps/webhook-setup.d.ts.map +1 -0
  79. package/dist/src/wizard/steps/webhook-setup.js +70 -0
  80. package/dist/src/wizard/steps/webhook-setup.js.map +1 -0
  81. package/dist/src/wizard/test-runner/config.d.ts +15 -0
  82. package/dist/src/wizard/test-runner/config.d.ts.map +1 -0
  83. package/dist/src/wizard/test-runner/config.js +2 -0
  84. package/dist/src/wizard/test-runner/config.js.map +1 -0
  85. package/dist/src/wizard/test-runner/logger.d.ts +3 -0
  86. package/dist/src/wizard/test-runner/logger.d.ts.map +1 -0
  87. package/dist/src/wizard/test-runner/logger.js +25 -0
  88. package/dist/src/wizard/test-runner/logger.js.map +1 -0
  89. package/dist/src/wizard/test-runner/phase-customer.d.ts +4 -0
  90. package/dist/src/wizard/test-runner/phase-customer.d.ts.map +1 -0
  91. package/dist/src/wizard/test-runner/phase-customer.js +66 -0
  92. package/dist/src/wizard/test-runner/phase-customer.js.map +1 -0
  93. package/dist/src/wizard/test-runner/phase-license.d.ts +4 -0
  94. package/dist/src/wizard/test-runner/phase-license.d.ts.map +1 -0
  95. package/dist/src/wizard/test-runner/phase-license.js +53 -0
  96. package/dist/src/wizard/test-runner/phase-license.js.map +1 -0
  97. package/dist/src/wizard/test-runner/phase-order.d.ts +4 -0
  98. package/dist/src/wizard/test-runner/phase-order.d.ts.map +1 -0
  99. package/dist/src/wizard/test-runner/phase-order.js +24 -0
  100. package/dist/src/wizard/test-runner/phase-order.js.map +1 -0
  101. package/dist/src/wizard/test-runner/phase-resolution.d.ts +4 -0
  102. package/dist/src/wizard/test-runner/phase-resolution.d.ts.map +1 -0
  103. package/dist/src/wizard/test-runner/phase-resolution.js +24 -0
  104. package/dist/src/wizard/test-runner/phase-resolution.js.map +1 -0
  105. package/dist/src/wizard/test-runner/phase-setup.d.ts +4 -0
  106. package/dist/src/wizard/test-runner/phase-setup.d.ts.map +1 -0
  107. package/dist/src/wizard/test-runner/phase-setup.js +61 -0
  108. package/dist/src/wizard/test-runner/phase-setup.js.map +1 -0
  109. package/dist/src/wizard/test-runner/phase-subscription.d.ts +4 -0
  110. package/dist/src/wizard/test-runner/phase-subscription.d.ts.map +1 -0
  111. package/dist/src/wizard/test-runner/phase-subscription.js +31 -0
  112. package/dist/src/wizard/test-runner/phase-subscription.js.map +1 -0
  113. package/dist/src/wizard/test-runner/phases.d.ts +4 -0
  114. package/dist/src/wizard/test-runner/phases.d.ts.map +1 -0
  115. package/dist/src/wizard/test-runner/phases.js +35 -0
  116. package/dist/src/wizard/test-runner/phases.js.map +1 -0
  117. package/dist/src/wizard/utils/config-content.d.ts +3 -0
  118. package/dist/src/wizard/utils/config-content.d.ts.map +1 -0
  119. package/dist/src/wizard/utils/config-content.js +44 -0
  120. package/dist/src/wizard/utils/config-content.js.map +1 -0
  121. package/dist/src/wizard/utils/example-content.d.ts +3 -0
  122. package/dist/src/wizard/utils/example-content.d.ts.map +1 -0
  123. package/dist/src/wizard/utils/example-content.js +53 -0
  124. package/dist/src/wizard/utils/example-content.js.map +1 -0
  125. package/dist/src/wizard/utils/validation.d.ts +3 -0
  126. package/dist/src/wizard/utils/validation.d.ts.map +1 -0
  127. package/dist/src/wizard/utils/validation.js +37 -0
  128. package/dist/src/wizard/utils/validation.js.map +1 -0
  129. package/package.json +22 -23
  130. package/dist/.cursor/skills/wizard/utils/validation.d.ts +0 -3
  131. package/dist/.cursor/skills/wizard/utils/validation.d.ts.map +0 -1
  132. package/dist/.cursor/skills/wizard/utils/validation.js +0 -113
  133. package/dist/.cursor/skills/wizard/utils/validation.js.map +0 -1
  134. package/dist/billing-config.d.ts +0 -3
  135. package/dist/billing-config.d.ts.map +0 -1
  136. package/dist/billing-config.js +0 -37
  137. package/dist/billing-config.js.map +0 -1
  138. package/dist/bootstrap.d.ts +0 -8
  139. package/dist/bootstrap.d.ts.map +0 -1
  140. package/dist/bootstrap.js +0 -42
  141. package/dist/bootstrap.js.map +0 -1
  142. package/dist/cache.d.ts +0 -5
  143. package/dist/cache.d.ts.map +0 -1
  144. package/dist/cache.js +0 -27
  145. package/dist/cache.js.map +0 -1
  146. package/dist/checkout.d.ts +0 -3
  147. package/dist/checkout.d.ts.map +0 -1
  148. package/dist/checkout.js +0 -42
  149. package/dist/checkout.js.map +0 -1
  150. package/dist/cli-validate.d.ts +0 -2
  151. package/dist/cli-validate.d.ts.map +0 -1
  152. package/dist/cli-validate.js +0 -206
  153. package/dist/cli-validate.js.map +0 -1
  154. package/dist/cli.d.ts +0 -3
  155. package/dist/cli.d.ts.map +0 -1
  156. package/dist/cli.js +0 -40
  157. package/dist/cli.js.map +0 -1
  158. package/dist/createBilling.d.ts +0 -3
  159. package/dist/createBilling.d.ts.map +0 -1
  160. package/dist/createBilling.js +0 -82
  161. package/dist/createBilling.js.map +0 -1
  162. package/dist/customers.d.ts +0 -3
  163. package/dist/customers.d.ts.map +0 -1
  164. package/dist/customers.js +0 -57
  165. package/dist/customers.js.map +0 -1
  166. package/dist/dedup.d.ts +0 -60
  167. package/dist/dedup.d.ts.map +0 -1
  168. package/dist/dedup.js +0 -74
  169. package/dist/dedup.js.map +0 -1
  170. package/dist/express.d.ts +0 -13
  171. package/dist/express.d.ts.map +0 -1
  172. package/dist/express.js +0 -70
  173. package/dist/express.js.map +0 -1
  174. package/dist/health.d.ts +0 -3
  175. package/dist/health.d.ts.map +0 -1
  176. package/dist/health.js +0 -38
  177. package/dist/health.js.map +0 -1
  178. package/dist/index.d.ts +0 -9
  179. package/dist/index.d.ts.map +0 -1
  180. package/dist/index.js +0 -9
  181. package/dist/index.js.map +0 -1
  182. package/dist/licenses.d.ts +0 -3
  183. package/dist/licenses.d.ts.map +0 -1
  184. package/dist/licenses.js +0 -70
  185. package/dist/licenses.js.map +0 -1
  186. package/dist/logger.d.ts +0 -4
  187. package/dist/logger.d.ts.map +0 -1
  188. package/dist/logger.js +0 -75
  189. package/dist/logger.js.map +0 -1
  190. package/dist/plans.d.ts +0 -5
  191. package/dist/plans.d.ts.map +0 -1
  192. package/dist/plans.js +0 -72
  193. package/dist/plans.js.map +0 -1
  194. package/dist/portal.d.ts +0 -2
  195. package/dist/portal.d.ts.map +0 -1
  196. package/dist/portal.js +0 -15
  197. package/dist/portal.js.map +0 -1
  198. package/dist/retry.d.ts +0 -2
  199. package/dist/retry.d.ts.map +0 -1
  200. package/dist/retry.js +0 -35
  201. package/dist/retry.js.map +0 -1
  202. package/dist/src/billing-config.d.ts +0 -3
  203. package/dist/src/billing-config.d.ts.map +0 -1
  204. package/dist/src/billing-config.js +0 -34
  205. package/dist/src/billing-config.js.map +0 -1
  206. package/dist/src/wizard.d.ts +0 -22
  207. package/dist/src/wizard.d.ts.map +0 -1
  208. package/dist/src/wizard.js +0 -628
  209. package/dist/src/wizard.js.map +0 -1
  210. package/dist/subscriptions.d.ts +0 -3
  211. package/dist/subscriptions.d.ts.map +0 -1
  212. package/dist/subscriptions.js +0 -46
  213. package/dist/subscriptions.js.map +0 -1
  214. package/dist/types.d.ts +0 -286
  215. package/dist/types.d.ts.map +0 -1
  216. package/dist/types.js +0 -2
  217. package/dist/types.js.map +0 -1
  218. package/dist/webhook.d.ts +0 -7
  219. package/dist/webhook.d.ts.map +0 -1
  220. package/dist/webhook.js +0 -227
  221. package/dist/webhook.js.map +0 -1
  222. package/dist/webhooks.d.ts +0 -3
  223. package/dist/webhooks.d.ts.map +0 -1
  224. package/dist/webhooks.js +0 -28
  225. package/dist/webhooks.js.map +0 -1
  226. package/dist/wizard.d.ts +0 -22
  227. package/dist/wizard.d.ts.map +0 -1
  228. package/dist/wizard.js +0 -615
  229. package/dist/wizard.js.map +0 -1
package/README.md CHANGED
@@ -1,114 +1,182 @@
1
- # Project Refactoring Summary
2
-
3
- ## Overview
4
-
5
- Successfully completed the refactoring of the `src/wizard.ts` file and reorganized the project structure to enable better modularity and maintainability.
6
-
7
- ## Changes Made
8
-
9
- ### 1. Created Skills Folder Structure
10
-
11
- - **Root Skills Directory**: `/skills/`
12
- - **Wizard Skill**: `/skills/wizard/` - Interactive setup wizard functionality
13
- - `components/` - Reusable UI components (banner, loading animations)
14
- - `steps/` - Individual wizard steps (API key, store selection, etc.)
15
- - `utils/` - Wizard-specific utilities (validation, file generation)
16
- - `types.ts` - Wizard-specific type definitions
17
- - **CLI Skill**: `/skills/cli/` - Command-line interface functionality
18
- - `commands/` - Individual CLI command implementations
19
- - `utils/` - CLI utilities and helpers
20
- - **Validation Skill**: `/skills/validation/` - Testing and validation functionality
21
- - `tests/` - Validation test implementations
22
- - `utils/` - Validation utilities and helpers
23
-
24
- ### 2. Reorganized Source Code Structure
25
-
26
- - **Core Directory**: `/src/core/` - Core billing functionality
27
- - Moved all core billing logic from root src/ directory
28
- - Updated all import paths to use new structure
29
- - **CLI Directory**: `/src/cli/` - CLI-related files
30
- - `cli.ts` - Main CLI entry point
31
- - `cli-validate.ts` - Validation functionality
32
- - **Types Directory**: `/src/types/` - Type definitions
33
- - `types.ts` - Main types export
34
- - Existing type subdirectories preserved
35
- - **Utils Directory**: `/src/utils/` - Utility files (created but empty for now)
36
-
37
- ### 3. Split Wizard.ts into Modular Components
38
-
39
- The original monolithic `wizard.ts` (~1000 lines) was split into:
40
-
41
- - **Main Wizard Class**: `/skills/wizard/main.ts`
42
- - **Type Definitions**: `/skills/wizard/types.ts`
43
- - **UI Components**:
44
- - `/skills/wizard/components/banner.ts`
45
- - `/skills/wizard/components/loading.ts`
46
- - **Wizard Steps**:
47
- - `/skills/wizard/steps/api-key.ts`
48
- - `/skills/wizard/steps/store-selection.ts`
49
- - `/skills/wizard/steps/product-selection.ts`
50
- - `/skills/wizard/steps/webhook-setup.ts`
51
- - `/skills/wizard/steps/configuration.ts`
52
- - `/skills/wizard/steps/generate-files.ts`
53
- - **Utilities**:
54
- - `/skills/wizard/utils/file-generation.ts`
55
- - `/skills/wizard/utils/validation.ts`
56
- - `/skills/wizard/utils/real-cycle.ts`
57
-
58
- ### 4. Updated Import Paths
59
-
60
- - Updated all import statements throughout the project to use the new directory structure
61
- - Fixed TypeScript compilation issues
62
- - Ensured all modules can find their dependencies
63
-
64
- ### 5. Created Comprehensive Documentation
65
-
66
- - **Root README**: This summary document
67
- - **Skills README**: Architecture overview and usage instructions
68
- - **Wizard README**: Detailed wizard functionality documentation
69
- - **CLI README**: CLI command documentation
70
- - **Validation README**: Testing and validation documentation
71
-
72
- ## Benefits Achieved
73
-
74
- 1. **Improved Modularity**: Each wizard step is now a separate, testable module
75
- 2. **Better Maintainability**: Clear separation of concerns makes code easier to understand and modify
76
- 3. **Enhanced Reusability**: Components can be reused across different parts of the system
77
- 4. **Cleaner Architecture**: Logical grouping of related functionality
78
- 5. **Easier Testing**: Individual modules can be tested independently
79
- 6. **Better Developer Experience**: Clear documentation and organized structure
80
-
81
- ## Project Structure
1
+ # fresh-squeezy
82
2
 
3
+ > The missing billing layer for Lemon Squeezy — auto-discover, checkout, webhooks, subscriptions, and licenses in one function call.
4
+
5
+ [![npm](https://img.shields.io/npm/v/fresh-squeezy)](https://www.npmjs.com/package/fresh-squeezy)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install fresh-squeezy
12
+ # peer deps
13
+ npm install @lemonsqueezy/lemonsqueezy.js
14
+ ```
15
+
16
+ ## Quick Start
17
+
18
+ ```ts
19
+ import { createBilling } from "fresh-squeezy";
20
+
21
+ const billing = await createBilling({
22
+ apiKey: process.env.LS_API_KEY!,
23
+ webhookSecret: process.env.LS_WEBHOOK_SECRET!,
24
+ callbacks: {
25
+ onPurchase: async ({ userId, email, orderId, productName, price }) => {
26
+ await db.grantAccess(userId);
27
+ },
28
+ onSubscription: async (event, method) => {
29
+ if (method === "cancelled") await db.revokeAccess(event.userId);
30
+ },
31
+ onSubscriptionPayment: async (event, method) => {
32
+ if (method === "success") await db.extendAccess(event.userId);
33
+ },
34
+ },
35
+ });
36
+
37
+ // Create a checkout URL
38
+ const url = await billing.createCheckout({
39
+ variantId: "123456",
40
+ email: "user@example.com",
41
+ userId: "user_abc",
42
+ });
43
+
44
+ // Verify + handle a webhook (Express example)
45
+ app.post("/webhook", express.raw({ type: "application/json" }), async (req, res) => {
46
+ const sig = req.headers["x-signature"] as string;
47
+ if (!billing.verifyWebhook(req.body.toString(), sig)) return res.sendStatus(401);
48
+ await billing.handleWebhook(JSON.parse(req.body.toString()));
49
+ res.json({ ok: true });
50
+ });
51
+ ```
52
+
53
+ ## Setup Wizard
54
+
55
+ Run the interactive wizard to generate a `billing-config.ts` for your project:
56
+
57
+ ```bash
58
+ pnpm wizard
59
+ # or after installing the package globally:
60
+ npx fresh-squeezy-billing wizard
61
+ ```
62
+
63
+ The wizard:
64
+ - Validates your API key against Lemon Squeezy
65
+ - Lets you select stores, products, and webhook events
66
+ - Generates `billing-config.ts` and `example.ts` in your project root
67
+ - Optionally runs all 6 API lifecycle test phases (setup → customer → order → subscription → license → cleanup)
68
+
69
+ ## Configuration
70
+
71
+ ```ts
72
+ interface BillingConfig {
73
+ apiKey: string;
74
+ storeId?: string;
75
+ webhookSecret?: string;
76
+ cachePath?: string; // default: "./billing-cache.json"
77
+ cacheTtlMs?: number; // default: 3 600 000 (1 hour)
78
+ checkoutExpiresInMs?: number | null;
79
+ logger?: { filePath: string } | { custom: BillingLogger };
80
+ callbacks: BillingCallbacks;
81
+ dedup?: DedupConfig;
82
+ }
83
83
  ```
84
- fresh-squeezy/
85
- ├── skills/ # Modular skills system
86
- │ ├── wizard/ # Interactive setup wizard
87
- │ │ ├── components/ # UI components
88
- │ │ ├── steps/ # Wizard steps
89
- │ │ ├── utils/ # Wizard utilities
90
- │ │ ├── types.ts # Wizard types
91
- │ │ └── main.ts # Main wizard class
92
- │ ├── cli/ # CLI functionality
93
- │ │ ├── commands/ # CLI commands
94
- │ │ └── utils/ # CLI utilities
95
- │ └── validation/ # Testing and validation
96
- │ ├── tests/ # Validation tests
97
- │ └── utils/ # Validation utilities
98
- ├── src/ # Source code
99
- │ ├── core/ # Core billing functionality
100
- │ ├── cli/ # CLI-related files
101
- │ ├── types/ # Type definitions
102
- │ └── utils/ # Utility files
103
- └── README.md # This documentation
84
+
85
+ ## Callbacks
86
+
87
+ ```ts
88
+ interface BillingCallbacks {
89
+ onPurchase: (event: PurchaseEvent) => Promise<void>;
90
+ onRefund?: (event: RefundEvent) => Promise<void>;
91
+ onSubscription?: (event: AnySubscriptionEvent, method: SubscriptionMethod) => Promise<void>;
92
+ // method: 'created' | 'updated' | 'cancelled' | 'expired' | 'paused' | 'resumed'
93
+ onSubscriptionPayment?: (event: SubscriptionPaymentSuccessEvent | SubscriptionPaymentRecoveredEvent, method: 'success' | 'recovered') => Promise<void>;
94
+ onPaymentFailed?: (event: PaymentFailedEvent) => Promise<void>;
95
+ onLicenseKey?: (method: 'created' | 'updated', event: LicenseKeyEvent) => Promise<void>;
96
+ onWebhook?: (eventType: string, event: unknown) => Promise<void>;
97
+ }
98
+ ```
99
+
100
+ ## Billing API
101
+
102
+ ```ts
103
+ billing.stores // StoreInfo[]
104
+ billing.plans // Plan[] (auto-refreshed from cache)
105
+ billing.createCheckout(params) // Promise<string> — checkout URL
106
+ billing.verifyWebhook(rawBody, sig) // boolean
107
+ billing.handleWebhook(payload) // Promise<void>
108
+ billing.refreshPlans() // Promise<void>
109
+ billing.getCustomerPortal(customerId) // Promise<string> — portal URL
110
+ billing.getExpressRouter(options) // Express Router
111
+
112
+ // Subscriptions
113
+ billing.pauseSubscription(id, reason?)
114
+ billing.resumeSubscription(id)
115
+ billing.cancelSubscription(id, immediately?)
116
+ billing.changeSubscriptionVariant(id, variantId)
117
+ billing.resumeCancelledSubscription(id)
118
+
119
+ // Licenses
120
+ billing.validateLicense(key) // Promise<{ valid: boolean; details? }>
121
+ billing.getLicenseDetails(key) // Promise<LicenseKeyEvent | null>
122
+ billing.activateLicense(key, instanceName) // Promise<{ activated: boolean; instanceId? }>
123
+ billing.deactivateLicense(key, instanceId) // Promise<boolean>
124
+
125
+ // Customers
126
+ billing.getCustomerByEmail(email)
127
+ billing.getSubscriptionsForUser(userId)
128
+
129
+ // Webhooks
130
+ billing.createWebhook(url, events, secret?)
131
+ billing.deleteWebhook(webhookId)
132
+
133
+ // Other
134
+ billing.healthCheck()
135
+ billing.dedupBackend
104
136
  ```
105
137
 
106
- ## Testing Status
138
+ ## Express Router
139
+
140
+ ```ts
141
+ import express from "express";
142
+
143
+ const app = express();
144
+ app.use("/billing", billing.getExpressRouter({
145
+ webhookPath: "/webhook",
146
+ checkoutPath: "/checkout",
147
+ }));
148
+ ```
149
+
150
+ ## Deduplication
151
+
152
+ By default, webhook deduplication is in-memory and process-local. Swap in Redis or a database backend:
153
+
154
+ ```ts
155
+ import { RedisDedupBackend } from "fresh-squeezy";
156
+
157
+ const billing = await createBilling({
158
+ // ...
159
+ dedup: {
160
+ backend: new RedisDedupBackend(redisClient),
161
+ ttlMs: 86_400_000,
162
+ },
163
+ });
164
+ ```
165
+
166
+ ## CLI
167
+
168
+ ```bash
169
+ npx fresh-squeezy-billing wizard # interactive setup
170
+ npx fresh-squeezy-billing validate # run validation suite
171
+ npx fresh-squeezy-billing help
172
+ ```
173
+
174
+ ## Requirements
175
+
176
+ - Node.js ≥ 20
177
+ - `@lemonsqueezy/lemonsqueezy.js` ≥ 3.2.0
178
+ - Express ≥ 4.18 (optional, only if using `getExpressRouter`)
107
179
 
108
- - ✅ TypeScript compilation passes
109
- - ✅ Build process completes successfully
110
- - ✅ All import paths updated and working
111
- - ✅ Modular structure implemented
112
- - ✅ Documentation created
180
+ ## License
113
181
 
114
- The refactoring is complete and the project is ready for continued development with the new modular structure.
182
+ MIT
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { runWizard } from "../wizard.js";
2
+ import { runWizard } from "../wizard/index.js";
3
3
  import { runValidate } from "./cli-validate.js";
4
4
  function printHelp() {
5
5
  console.log(`
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAab,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAa,IAAI,CAAC,CAAC,CAAa,IAAI,MAAM,CAAC;IAExD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ;YACE,SAAS,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../../../src/cli/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAIhD,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAab,CAAC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnC,MAAM,OAAO,GAAa,IAAI,CAAC,CAAC,CAAa,IAAI,MAAM,CAAC;IAExD,QAAQ,OAAO,EAAE,CAAC;QAChB,KAAK,QAAQ;YACX,MAAM,SAAS,EAAE,CAAC;YAClB,MAAM;QACR,KAAK,UAAU;YACb,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACR,KAAK,MAAM,CAAC;QACZ;YACE,SAAS,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAY,EAAE,EAAE;IAC5B,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare const VALIDATE_CACHE_PATH: string;
2
+ export declare const VALIDATE_LOG_PATH: string;
3
+ export declare const VALIDATE_LIVE_CACHE_PATH: string;
4
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAKA,eAAO,MAAM,mBAAmB,QAAkD,CAAC;AACnF,eAAO,MAAM,iBAAiB,QAA2C,CAAC;AAC1E,eAAO,MAAM,wBAAwB,QAA8C,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { tmpdir } from "node:os";
2
+ import { join } from "node:path";
3
+ const PREFIX = "lemonsqueezy-billing";
4
+ export const VALIDATE_CACHE_PATH = join(tmpdir(), `${PREFIX}-validate-cache.json`);
5
+ export const VALIDATE_LOG_PATH = join(tmpdir(), `${PREFIX}-validate.log`);
6
+ export const VALIDATE_LIVE_CACHE_PATH = join(tmpdir(), `${PREFIX}-live-cache.json`);
7
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/cli/paths.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,MAAM,GAAG,sBAAsB,CAAC;AAEtC,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,sBAAsB,CAAC,CAAC;AACnF,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,eAAe,CAAC,CAAC;AAC1E,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,GAAG,MAAM,kBAAkB,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/core/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAKtD,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAQtE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAIxE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAKrF"}
1
+ {"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../../src/core/cache.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,wBAAgB,SAAS,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAQtE;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAIxE;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAKrF"}
@@ -1,6 +1,6 @@
1
1
  import { readFileSync, writeFileSync, mkdirSync } from "node:fs";
2
2
  import { dirname } from "node:path";
3
- const DEFAULT_CACHE_PATH = "./billing-cache.json";
3
+ import { DEFAULT_CACHE_PATH } from "./paths.js";
4
4
  const DEFAULT_TTL_MS = 3_600_000;
5
5
  export function readCache(cachePath) {
6
6
  const path = cachePath ?? DEFAULT_CACHE_PATH;
@@ -1 +1 @@
1
- {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/core/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC,MAAM,kBAAkB,GAAG,sBAAsB,CAAC;AAClD,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC,MAAM,UAAU,SAAS,CAAC,SAAkB;IAC1C,MAAM,IAAI,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,SAAkB;IAChE,MAAM,IAAI,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC7C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA+B,EAAE,KAAc;IAC1E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,GAAG,GAAG,KAAK,IAAI,cAAc,CAAC;IACpC,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;IAC1D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,GAAG,GAAG,CAAC;AACxC,CAAC"}
1
+ {"version":3,"file":"cache.js","sourceRoot":"","sources":["../../../src/core/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,MAAM,cAAc,GAAG,SAAS,CAAC;AAEjC,MAAM,UAAU,SAAS,CAAC,SAAkB;IAC1C,MAAM,IAAI,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC7C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAiB,CAAC;IACzC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAmB,EAAE,SAAkB;IAChE,MAAM,IAAI,GAAG,SAAS,IAAI,kBAAkB,CAAC;IAC7C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,OAAO,CAAC,CAAC;AACtE,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAA+B,EAAE,KAAc;IAC1E,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,GAAG,GAAG,KAAK,IAAI,cAAc,CAAC;IACpC,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;IAC1D,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,WAAW,GAAG,GAAG,CAAC;AACxC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"licenses.d.ts","sourceRoot":"","sources":["../../../src/core/licenses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAqD,MAAM,mBAAmB,CAAC;AAqBjH,wBAAgB,0BAA0B,IAAI,oBAAoB,CAiFjE"}
1
+ {"version":3,"file":"licenses.d.ts","sourceRoot":"","sources":["../../../src/core/licenses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EAKrB,MAAM,mBAAmB,CAAC;AAuB3B,wBAAgB,0BAA0B,IAAI,oBAAoB,CAiHjE"}
@@ -1,5 +1,6 @@
1
1
  import { getLicenseKey } from "@lemonsqueezy/lemonsqueezy.js";
2
2
  import { withRetry } from "./retry.js";
3
+ const LS_LICENSE_API_BASE = "https://api.lemonsqueezy.com/v1/licenses";
3
4
  function mapAttributesToLicenseKeyEvent(attrs, licenseKeyId, key) {
4
5
  return {
5
6
  userId: attrs.user_email,
@@ -26,7 +27,7 @@ export function createLicenseKeyManagement() {
26
27
  const attrs = response.data.data.attributes;
27
28
  const details = mapAttributesToLicenseKeyEvent(attrs, response.data.data.id, attrs.key);
28
29
  const valid = details.status === "active" &&
29
- details.activationCount < details.maxActivations;
30
+ (details.maxActivations === null || details.activationCount <= details.maxActivations);
30
31
  return { valid, details };
31
32
  }
32
33
  catch {
@@ -34,31 +35,64 @@ export function createLicenseKeyManagement() {
34
35
  }
35
36
  };
36
37
  const getLicenseDetails = async (key) => {
37
- const response = await withRetry(() => getLicenseKey(key), "getLicenseKey");
38
- if (response.error || !response.data?.data) {
38
+ try {
39
+ const response = await withRetry(() => getLicenseKey(key), "getLicenseKey");
40
+ if (response.error || !response.data?.data) {
41
+ return null;
42
+ }
43
+ const attrs = response.data.data.attributes;
44
+ return mapAttributesToLicenseKeyEvent(attrs, response.data.data.id, attrs.key);
45
+ }
46
+ catch {
39
47
  return null;
40
48
  }
41
- const attrs = response.data.data.attributes;
42
- return mapAttributesToLicenseKeyEvent(attrs, response.data.data.id, attrs.key);
43
49
  };
44
- const activateLicense = async (key, _instanceId) => {
45
- // Note: Lemon Squeezy doesn't have a direct activation API
46
- // This would typically be handled by your application logic
47
- // based on the license key details and activation limits
48
- const validation = await validateLicense(key);
49
- if (!validation.valid || !validation.details) {
50
- return false;
50
+ // Note: License API is a direct HTTP call; retries are intentionally omitted (callers should retry at the application level)
51
+ const activateLicense = async (key, instanceName) => {
52
+ const resolvedName = instanceName ?? "default";
53
+ const body = new URLSearchParams({ license_key: key, instance_name: resolvedName });
54
+ try {
55
+ const response = await fetch(`${LS_LICENSE_API_BASE}/activate`, {
56
+ method: "POST",
57
+ headers: {
58
+ Accept: "application/json",
59
+ "Content-Type": "application/x-www-form-urlencoded",
60
+ },
61
+ body: body.toString(),
62
+ });
63
+ if (!response.ok) {
64
+ return { activated: false };
65
+ }
66
+ const data = (await response.json());
67
+ return { activated: data.activated === true, instanceId: data.instance?.id };
68
+ }
69
+ catch {
70
+ return { activated: false };
51
71
  }
52
- // Here you would typically:
53
- // 1. Check if this instanceId is already activated
54
- // 2. Increment activation count in your database
55
- // 3. Return success/failure based on your business logic
56
- return true; // Placeholder - implement based on your needs
57
72
  };
58
- const deactivateLicense = async (_key, _instanceId) => {
59
- // Similar to activateLicense, this would be handled by your application logic
60
- // based on your activation tracking system
61
- return true; // Placeholder - implement based on your needs
73
+ const deactivateLicense = async (key, instanceId) => {
74
+ if (!instanceId) {
75
+ return false;
76
+ }
77
+ const body = new URLSearchParams({ license_key: key, instance_id: instanceId });
78
+ try {
79
+ const response = await fetch(`${LS_LICENSE_API_BASE}/deactivate`, {
80
+ method: "POST",
81
+ headers: {
82
+ Accept: "application/json",
83
+ "Content-Type": "application/x-www-form-urlencoded",
84
+ },
85
+ body: body.toString(),
86
+ });
87
+ if (!response.ok) {
88
+ return false;
89
+ }
90
+ const data = (await response.json());
91
+ return data.deactivated === true;
92
+ }
93
+ catch {
94
+ return false;
95
+ }
62
96
  };
63
97
  return {
64
98
  validateLicense,
@@ -1 +1 @@
1
- {"version":3,"file":"licenses.js","sourceRoot":"","sources":["../../../src/core/licenses.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"licenses.js","sourceRoot":"","sources":["../../../src/core/licenses.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare const BILLING_DIR = ".billing";
2
+ export declare const DEFAULT_CACHE_PATH = ".billing/cache.json";
3
+ export declare const DEFAULT_LOG_PATH = ".billing/billing.log";
4
+ export declare const WIZARD_CONFIG_FILE = ".billing/billing-config.ts";
5
+ export declare const WIZARD_EXAMPLE_FILE = ".billing/example.ts";
6
+ //# sourceMappingURL=paths.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/core/paths.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,aAAa,CAAC;AAEtC,eAAO,MAAM,kBAAkB,wBAA8B,CAAC;AAC9D,eAAO,MAAM,gBAAgB,yBAA+B,CAAC;AAE7D,eAAO,MAAM,kBAAkB,+BAAqC,CAAC;AACrE,eAAO,MAAM,mBAAmB,wBAA8B,CAAC"}
@@ -0,0 +1,6 @@
1
+ export const BILLING_DIR = ".billing";
2
+ export const DEFAULT_CACHE_PATH = `${BILLING_DIR}/cache.json`;
3
+ export const DEFAULT_LOG_PATH = `${BILLING_DIR}/billing.log`;
4
+ export const WIZARD_CONFIG_FILE = `${BILLING_DIR}/billing-config.ts`;
5
+ export const WIZARD_EXAMPLE_FILE = `${BILLING_DIR}/example.ts`;
6
+ //# sourceMappingURL=paths.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"paths.js","sourceRoot":"","sources":["../../../src/core/paths.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,WAAW,GAAG,UAAU,CAAC;AAEtC,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,WAAW,aAAa,CAAC;AAC9D,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,WAAW,cAAc,CAAC;AAE7D,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,WAAW,oBAAoB,CAAC;AACrE,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,WAAW,aAAa,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/core/webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EAaf,MAAM,mBAAmB,CAAC;AAI3B,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,IAC1C,SAAS,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAQrD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM,IAyBrE,SAAS,cAAc,KAAG,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAgMjG"}
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/core/webhook.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,cAAc,EAef,MAAM,mBAAmB,CAAC;AAI3B,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,IAC1C,SAAS,MAAM,EAAE,WAAW,MAAM,KAAG,OAAO,CAQrD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,gBAAgB,EAAE,UAAU,CAAC,EAAE,MAAM,IAyBrE,SAAS,cAAc,KAAG,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAyKjG"}
@@ -66,37 +66,17 @@ export function createWebhookHandler(callbacks, dedupTtlMs) {
66
66
  await dispatchWebhook(eventName, event);
67
67
  return { dispatched: callbacks.onRefund ? "onRefund" : null, skipped: false };
68
68
  }
69
- case "subscription_created": {
70
- const event = buildSubscriptionEvent(userId, email, dataId, attrs);
71
- if (callbacks.onSubscriptionCreated) {
72
- await callbacks.onSubscriptionCreated(event);
73
- }
74
- await dispatchWebhook(eventName, event);
75
- return { dispatched: callbacks.onSubscriptionCreated ? "onSubscriptionCreated" : null, skipped: false };
76
- }
77
- case "subscription_updated": {
78
- const event = buildSubscriptionEvent(userId, email, dataId, attrs);
79
- if (callbacks.onSubscriptionUpdated) {
80
- await callbacks.onSubscriptionUpdated(event);
81
- }
82
- await dispatchWebhook(eventName, event);
83
- return { dispatched: callbacks.onSubscriptionUpdated ? "onSubscriptionUpdated" : null, skipped: false };
84
- }
85
- case "subscription_cancelled": {
86
- const event = buildSubscriptionEvent(userId, email, dataId, attrs);
87
- if (callbacks.onSubscriptionCancelled) {
88
- await callbacks.onSubscriptionCancelled(event);
89
- }
90
- await dispatchWebhook(eventName, event);
91
- return { dispatched: callbacks.onSubscriptionCancelled ? "onSubscriptionCancelled" : null, skipped: false };
92
- }
69
+ case "subscription_created":
70
+ case "subscription_updated":
71
+ case "subscription_cancelled":
93
72
  case "subscription_expired": {
73
+ const method = eventName.replace("subscription_", "");
94
74
  const event = buildSubscriptionEvent(userId, email, dataId, attrs);
95
- if (callbacks.onSubscriptionExpired) {
96
- await callbacks.onSubscriptionExpired(event);
75
+ if (callbacks.onSubscription) {
76
+ await callbacks.onSubscription(event, method);
97
77
  }
98
78
  await dispatchWebhook(eventName, event);
99
- return { dispatched: callbacks.onSubscriptionExpired ? "onSubscriptionExpired" : null, skipped: false };
79
+ return { dispatched: callbacks.onSubscription ? `onSubscription:${method}` : null, skipped: false };
100
80
  }
101
81
  case "subscription_payment_failed": {
102
82
  const event = {
@@ -120,11 +100,11 @@ export function createWebhookHandler(callbacks, dedupTtlMs) {
120
100
  customerId: String(attrs.customer_id ?? ""),
121
101
  reason: String(attrs.pause_reason ?? ""),
122
102
  };
123
- if (callbacks.onSubscriptionPaused) {
124
- await callbacks.onSubscriptionPaused(event);
103
+ if (callbacks.onSubscription) {
104
+ await callbacks.onSubscription(event, "paused");
125
105
  }
126
106
  await dispatchWebhook(eventName, event);
127
- return { dispatched: callbacks.onSubscriptionPaused ? "onSubscriptionPaused" : null, skipped: false };
107
+ return { dispatched: callbacks.onSubscription ? "onSubscription:paused" : null, skipped: false };
128
108
  }
129
109
  case "subscription_resumed":
130
110
  case "subscription_unpaused": {
@@ -134,11 +114,11 @@ export function createWebhookHandler(callbacks, dedupTtlMs) {
134
114
  subscriptionId: dataId,
135
115
  customerId: String(attrs.customer_id ?? ""),
136
116
  };
137
- if (callbacks.onSubscriptionResumed) {
138
- await callbacks.onSubscriptionResumed(event);
117
+ if (callbacks.onSubscription) {
118
+ await callbacks.onSubscription(event, "resumed");
139
119
  }
140
120
  await dispatchWebhook(eventName, event);
141
- return { dispatched: callbacks.onSubscriptionResumed ? "onSubscriptionResumed" : null, skipped: false };
121
+ return { dispatched: callbacks.onSubscription ? "onSubscription:resumed" : null, skipped: false };
142
122
  }
143
123
  case "subscription_payment_success": {
144
124
  const event = {
@@ -149,11 +129,11 @@ export function createWebhookHandler(callbacks, dedupTtlMs) {
149
129
  orderId: String(attrs.order_id ?? ""),
150
130
  amount: Number(attrs.total ?? 0),
151
131
  };
152
- if (callbacks.onSubscriptionPaymentSuccess) {
153
- await callbacks.onSubscriptionPaymentSuccess(event);
132
+ if (callbacks.onSubscriptionPayment) {
133
+ await callbacks.onSubscriptionPayment(event, "success");
154
134
  }
155
135
  await dispatchWebhook(eventName, event);
156
- return { dispatched: callbacks.onSubscriptionPaymentSuccess ? "onSubscriptionPaymentSuccess" : null, skipped: false };
136
+ return { dispatched: callbacks.onSubscriptionPayment ? "onSubscriptionPayment:success" : null, skipped: false };
157
137
  }
158
138
  case "subscription_payment_recovered": {
159
139
  const event = {
@@ -164,11 +144,11 @@ export function createWebhookHandler(callbacks, dedupTtlMs) {
164
144
  orderId: String(attrs.order_id ?? ""),
165
145
  amount: Number(attrs.total ?? 0),
166
146
  };
167
- if (callbacks.onSubscriptionPaymentRecovered) {
168
- await callbacks.onSubscriptionPaymentRecovered(event);
147
+ if (callbacks.onSubscriptionPayment) {
148
+ await callbacks.onSubscriptionPayment(event, "recovered");
169
149
  }
170
150
  await dispatchWebhook(eventName, event);
171
- return { dispatched: callbacks.onSubscriptionPaymentRecovered ? "onSubscriptionPaymentRecovered" : null, skipped: false };
151
+ return { dispatched: callbacks.onSubscriptionPayment ? "onSubscriptionPayment:recovered" : null, skipped: false };
172
152
  }
173
153
  case "license_key_created": {
174
154
  const event = {