fresh-squeezy 1.0.20

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 (247) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/dist/.cursor/skills/wizard/utils/validation.d.ts +3 -0
  4. package/dist/.cursor/skills/wizard/utils/validation.d.ts.map +1 -0
  5. package/dist/.cursor/skills/wizard/utils/validation.js +113 -0
  6. package/dist/.cursor/skills/wizard/utils/validation.js.map +1 -0
  7. package/dist/billing-config.d.ts +3 -0
  8. package/dist/billing-config.d.ts.map +1 -0
  9. package/dist/billing-config.js +37 -0
  10. package/dist/billing-config.js.map +1 -0
  11. package/dist/bootstrap.d.ts +8 -0
  12. package/dist/bootstrap.d.ts.map +1 -0
  13. package/dist/bootstrap.js +42 -0
  14. package/dist/bootstrap.js.map +1 -0
  15. package/dist/cache.d.ts +5 -0
  16. package/dist/cache.d.ts.map +1 -0
  17. package/dist/cache.js +27 -0
  18. package/dist/cache.js.map +1 -0
  19. package/dist/checkout.d.ts +3 -0
  20. package/dist/checkout.d.ts.map +1 -0
  21. package/dist/checkout.js +42 -0
  22. package/dist/checkout.js.map +1 -0
  23. package/dist/cli-validate.d.ts +2 -0
  24. package/dist/cli-validate.d.ts.map +1 -0
  25. package/dist/cli-validate.js +206 -0
  26. package/dist/cli-validate.js.map +1 -0
  27. package/dist/cli.d.ts +3 -0
  28. package/dist/cli.d.ts.map +1 -0
  29. package/dist/cli.js +40 -0
  30. package/dist/cli.js.map +1 -0
  31. package/dist/createBilling.d.ts +3 -0
  32. package/dist/createBilling.d.ts.map +1 -0
  33. package/dist/createBilling.js +82 -0
  34. package/dist/createBilling.js.map +1 -0
  35. package/dist/customers.d.ts +3 -0
  36. package/dist/customers.d.ts.map +1 -0
  37. package/dist/customers.js +57 -0
  38. package/dist/customers.js.map +1 -0
  39. package/dist/dedup.d.ts +60 -0
  40. package/dist/dedup.d.ts.map +1 -0
  41. package/dist/dedup.js +74 -0
  42. package/dist/dedup.js.map +1 -0
  43. package/dist/express.d.ts +13 -0
  44. package/dist/express.d.ts.map +1 -0
  45. package/dist/express.js +70 -0
  46. package/dist/express.js.map +1 -0
  47. package/dist/health.d.ts +3 -0
  48. package/dist/health.d.ts.map +1 -0
  49. package/dist/health.js +38 -0
  50. package/dist/health.js.map +1 -0
  51. package/dist/index.d.ts +9 -0
  52. package/dist/index.d.ts.map +1 -0
  53. package/dist/index.js +9 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/licenses.d.ts +3 -0
  56. package/dist/licenses.d.ts.map +1 -0
  57. package/dist/licenses.js +70 -0
  58. package/dist/licenses.js.map +1 -0
  59. package/dist/logger.d.ts +4 -0
  60. package/dist/logger.d.ts.map +1 -0
  61. package/dist/logger.js +75 -0
  62. package/dist/logger.js.map +1 -0
  63. package/dist/plans.d.ts +5 -0
  64. package/dist/plans.d.ts.map +1 -0
  65. package/dist/plans.js +72 -0
  66. package/dist/plans.js.map +1 -0
  67. package/dist/portal.d.ts +2 -0
  68. package/dist/portal.d.ts.map +1 -0
  69. package/dist/portal.js +15 -0
  70. package/dist/portal.js.map +1 -0
  71. package/dist/retry.d.ts +2 -0
  72. package/dist/retry.d.ts.map +1 -0
  73. package/dist/retry.js +35 -0
  74. package/dist/retry.js.map +1 -0
  75. package/dist/src/billing-config.d.ts +3 -0
  76. package/dist/src/billing-config.d.ts.map +1 -0
  77. package/dist/src/billing-config.js +34 -0
  78. package/dist/src/billing-config.js.map +1 -0
  79. package/dist/src/cli/cli-validate.d.ts +2 -0
  80. package/dist/src/cli/cli-validate.d.ts.map +1 -0
  81. package/dist/src/cli/cli-validate.js +206 -0
  82. package/dist/src/cli/cli-validate.js.map +1 -0
  83. package/dist/src/cli/cli.d.ts +3 -0
  84. package/dist/src/cli/cli.d.ts.map +1 -0
  85. package/dist/src/cli/cli.js +40 -0
  86. package/dist/src/cli/cli.js.map +1 -0
  87. package/dist/src/core/bootstrap.d.ts +8 -0
  88. package/dist/src/core/bootstrap.d.ts.map +1 -0
  89. package/dist/src/core/bootstrap.js +42 -0
  90. package/dist/src/core/bootstrap.js.map +1 -0
  91. package/dist/src/core/cache.d.ts +5 -0
  92. package/dist/src/core/cache.d.ts.map +1 -0
  93. package/dist/src/core/cache.js +27 -0
  94. package/dist/src/core/cache.js.map +1 -0
  95. package/dist/src/core/checkout.d.ts +3 -0
  96. package/dist/src/core/checkout.d.ts.map +1 -0
  97. package/dist/src/core/checkout.js +42 -0
  98. package/dist/src/core/checkout.js.map +1 -0
  99. package/dist/src/core/createBilling.d.ts +3 -0
  100. package/dist/src/core/createBilling.d.ts.map +1 -0
  101. package/dist/src/core/createBilling.js +82 -0
  102. package/dist/src/core/createBilling.js.map +1 -0
  103. package/dist/src/core/customers.d.ts +3 -0
  104. package/dist/src/core/customers.d.ts.map +1 -0
  105. package/dist/src/core/customers.js +57 -0
  106. package/dist/src/core/customers.js.map +1 -0
  107. package/dist/src/core/dedup.d.ts +60 -0
  108. package/dist/src/core/dedup.d.ts.map +1 -0
  109. package/dist/src/core/dedup.js +74 -0
  110. package/dist/src/core/dedup.js.map +1 -0
  111. package/dist/src/core/express.d.ts +13 -0
  112. package/dist/src/core/express.d.ts.map +1 -0
  113. package/dist/src/core/express.js +70 -0
  114. package/dist/src/core/express.js.map +1 -0
  115. package/dist/src/core/health.d.ts +3 -0
  116. package/dist/src/core/health.d.ts.map +1 -0
  117. package/dist/src/core/health.js +38 -0
  118. package/dist/src/core/health.js.map +1 -0
  119. package/dist/src/core/index.d.ts +9 -0
  120. package/dist/src/core/index.d.ts.map +1 -0
  121. package/dist/src/core/index.js +9 -0
  122. package/dist/src/core/index.js.map +1 -0
  123. package/dist/src/core/licenses.d.ts +3 -0
  124. package/dist/src/core/licenses.d.ts.map +1 -0
  125. package/dist/src/core/licenses.js +70 -0
  126. package/dist/src/core/licenses.js.map +1 -0
  127. package/dist/src/core/logger.d.ts +4 -0
  128. package/dist/src/core/logger.d.ts.map +1 -0
  129. package/dist/src/core/logger.js +150 -0
  130. package/dist/src/core/logger.js.map +1 -0
  131. package/dist/src/core/plans.d.ts +5 -0
  132. package/dist/src/core/plans.d.ts.map +1 -0
  133. package/dist/src/core/plans.js +72 -0
  134. package/dist/src/core/plans.js.map +1 -0
  135. package/dist/src/core/portal.d.ts +2 -0
  136. package/dist/src/core/portal.d.ts.map +1 -0
  137. package/dist/src/core/portal.js +15 -0
  138. package/dist/src/core/portal.js.map +1 -0
  139. package/dist/src/core/retry.d.ts +2 -0
  140. package/dist/src/core/retry.d.ts.map +1 -0
  141. package/dist/src/core/retry.js +35 -0
  142. package/dist/src/core/retry.js.map +1 -0
  143. package/dist/src/core/subscriptions.d.ts +3 -0
  144. package/dist/src/core/subscriptions.d.ts.map +1 -0
  145. package/dist/src/core/subscriptions.js +46 -0
  146. package/dist/src/core/subscriptions.js.map +1 -0
  147. package/dist/src/core/webhook.d.ts +7 -0
  148. package/dist/src/core/webhook.d.ts.map +1 -0
  149. package/dist/src/core/webhook.js +233 -0
  150. package/dist/src/core/webhook.js.map +1 -0
  151. package/dist/src/core/webhooks.d.ts +3 -0
  152. package/dist/src/core/webhooks.d.ts.map +1 -0
  153. package/dist/src/core/webhooks.js +28 -0
  154. package/dist/src/core/webhooks.js.map +1 -0
  155. package/dist/src/types/billing/billing.d.ts +36 -0
  156. package/dist/src/types/billing/billing.d.ts.map +1 -0
  157. package/dist/src/types/billing/billing.js +2 -0
  158. package/dist/src/types/billing/billing.js.map +1 -0
  159. package/dist/src/types/billing/index.d.ts +2 -0
  160. package/dist/src/types/billing/index.d.ts.map +1 -0
  161. package/dist/src/types/billing/index.js +2 -0
  162. package/dist/src/types/billing/index.js.map +1 -0
  163. package/dist/src/types/billing/types.d.ts +50 -0
  164. package/dist/src/types/billing/types.d.ts.map +1 -0
  165. package/dist/src/types/billing/types.js +2 -0
  166. package/dist/src/types/billing/types.js.map +1 -0
  167. package/dist/src/types/cache/index.d.ts +2 -0
  168. package/dist/src/types/cache/index.d.ts.map +1 -0
  169. package/dist/src/types/cache/index.js +2 -0
  170. package/dist/src/types/cache/index.js.map +1 -0
  171. package/dist/src/types/cache/types.d.ts +62 -0
  172. package/dist/src/types/cache/types.d.ts.map +1 -0
  173. package/dist/src/types/cache/types.js +2 -0
  174. package/dist/src/types/cache/types.js.map +1 -0
  175. package/dist/src/types/config/index.d.ts +2 -0
  176. package/dist/src/types/config/index.d.ts.map +1 -0
  177. package/dist/src/types/config/index.js +2 -0
  178. package/dist/src/types/config/index.js.map +1 -0
  179. package/dist/src/types/config/types.d.ts +138 -0
  180. package/dist/src/types/config/types.d.ts.map +1 -0
  181. package/dist/src/types/config/types.js +2 -0
  182. package/dist/src/types/config/types.js.map +1 -0
  183. package/dist/src/types/index.d.ts +9 -0
  184. package/dist/src/types/index.d.ts.map +1 -0
  185. package/dist/src/types/index.js +9 -0
  186. package/dist/src/types/index.js.map +1 -0
  187. package/dist/src/types/license/index.d.ts +2 -0
  188. package/dist/src/types/license/index.d.ts.map +1 -0
  189. package/dist/src/types/license/index.js +2 -0
  190. package/dist/src/types/license/index.js.map +1 -0
  191. package/dist/src/types/license/types.d.ts +32 -0
  192. package/dist/src/types/license/types.d.ts.map +1 -0
  193. package/dist/src/types/license/types.js +2 -0
  194. package/dist/src/types/license/types.js.map +1 -0
  195. package/dist/src/types/management/index.d.ts +2 -0
  196. package/dist/src/types/management/index.d.ts.map +1 -0
  197. package/dist/src/types/management/index.js +2 -0
  198. package/dist/src/types/management/index.js.map +1 -0
  199. package/dist/src/types/management/types.d.ts +37 -0
  200. package/dist/src/types/management/types.d.ts.map +1 -0
  201. package/dist/src/types/management/types.js +2 -0
  202. package/dist/src/types/management/types.js.map +1 -0
  203. package/dist/src/types/subscription/index.d.ts +2 -0
  204. package/dist/src/types/subscription/index.d.ts.map +1 -0
  205. package/dist/src/types/subscription/index.js +2 -0
  206. package/dist/src/types/subscription/index.js.map +1 -0
  207. package/dist/src/types/subscription/types.d.ts +46 -0
  208. package/dist/src/types/subscription/types.d.ts.map +1 -0
  209. package/dist/src/types/subscription/types.js +2 -0
  210. package/dist/src/types/subscription/types.js.map +1 -0
  211. package/dist/src/types/types.d.ts +2 -0
  212. package/dist/src/types/types.d.ts.map +1 -0
  213. package/dist/src/types/types.js +2 -0
  214. package/dist/src/types/types.js.map +1 -0
  215. package/dist/src/types/webhook/index.d.ts +2 -0
  216. package/dist/src/types/webhook/index.d.ts.map +1 -0
  217. package/dist/src/types/webhook/index.js +2 -0
  218. package/dist/src/types/webhook/index.js.map +1 -0
  219. package/dist/src/types/webhook/types.d.ts +14 -0
  220. package/dist/src/types/webhook/types.d.ts.map +1 -0
  221. package/dist/src/types/webhook/types.js +2 -0
  222. package/dist/src/types/webhook/types.js.map +1 -0
  223. package/dist/src/wizard.d.ts +22 -0
  224. package/dist/src/wizard.d.ts.map +1 -0
  225. package/dist/src/wizard.js +628 -0
  226. package/dist/src/wizard.js.map +1 -0
  227. package/dist/subscriptions.d.ts +3 -0
  228. package/dist/subscriptions.d.ts.map +1 -0
  229. package/dist/subscriptions.js +46 -0
  230. package/dist/subscriptions.js.map +1 -0
  231. package/dist/types.d.ts +286 -0
  232. package/dist/types.d.ts.map +1 -0
  233. package/dist/types.js +2 -0
  234. package/dist/types.js.map +1 -0
  235. package/dist/webhook.d.ts +7 -0
  236. package/dist/webhook.d.ts.map +1 -0
  237. package/dist/webhook.js +227 -0
  238. package/dist/webhook.js.map +1 -0
  239. package/dist/webhooks.d.ts +3 -0
  240. package/dist/webhooks.d.ts.map +1 -0
  241. package/dist/webhooks.js +28 -0
  242. package/dist/webhooks.js.map +1 -0
  243. package/dist/wizard.d.ts +22 -0
  244. package/dist/wizard.d.ts.map +1 -0
  245. package/dist/wizard.js +615 -0
  246. package/dist/wizard.js.map +1 -0
  247. package/package.json +88 -0
@@ -0,0 +1,206 @@
1
+ import { createBilling } from "./index.js";
2
+ import { createHmac } from "node:crypto";
3
+ import { readFileSync, unlinkSync } from "node:fs";
4
+ const WEBHOOK_SECRET = process.env.LS_WEBHOOK_SECRET ?? "test-webhook-secret";
5
+ function pass(label) {
6
+ console.log(` \u2705 ${label}`);
7
+ }
8
+ function fail(label, error) {
9
+ console.log(` \u274c ${label}: ${error}`);
10
+ }
11
+ function cleanup(cachePath, logPath) {
12
+ try {
13
+ unlinkSync(cachePath);
14
+ }
15
+ catch { }
16
+ try {
17
+ unlinkSync(logPath);
18
+ }
19
+ catch { }
20
+ }
21
+ export async function runValidate() {
22
+ const CACHE_PATH = "/tmp/lemonsqueezy-billing-validate-cache.json";
23
+ const LOG_PATH = "/tmp/lemonsqueezy-billing-validate.log";
24
+ const API_KEY = process.env.LS_API_KEY;
25
+ console.log("\ud83c\udf4b lemonsqueezy-billing \u2014 Validation Suite\n");
26
+ console.log("=".repeat(50));
27
+ await validateOffline(CACHE_PATH, LOG_PATH);
28
+ await validateLive(API_KEY, CACHE_PATH, LOG_PATH);
29
+ console.log("\n" + "=".repeat(50));
30
+ console.log("\n\u2728 Validation complete\n");
31
+ console.log('\n📁 Validation files location:');
32
+ console.log(` Cache file: ${CACHE_PATH}`);
33
+ console.log(` Log file: ${LOG_PATH}`);
34
+ }
35
+ async function validateOffline(cachePath, logPath) {
36
+ console.log("\n\ud83d\udce6 Offline Validation (no API key needed)\n");
37
+ const { readCache, writeCache, isCacheValid } = await import("./cache.js");
38
+ const { createWebhookVerifier, createWebhookHandler } = await import("./webhook.js");
39
+ const { createLogger, withLogger } = await import("./logger.js");
40
+ const { withRetry } = await import("./retry.js");
41
+ const testCache = {
42
+ generatedAt: new Date().toISOString(),
43
+ store: { id: "test-store", name: "Test Store", slug: "test", currency: "USD" },
44
+ products: [{
45
+ id: "prod-1",
46
+ name: "Test Product",
47
+ description: "Test",
48
+ status: "published",
49
+ variants: [{
50
+ id: "var-1",
51
+ name: "Default",
52
+ price: 499,
53
+ priceFormatted: "$4.99",
54
+ isSubscription: false,
55
+ status: "published",
56
+ }],
57
+ }],
58
+ };
59
+ writeCache(testCache, cachePath);
60
+ const loaded = readCache(cachePath);
61
+ if (loaded?.store.name === "Test Store")
62
+ pass("Cache write + read");
63
+ else
64
+ fail("Cache write + read", "Data mismatch");
65
+ if (isCacheValid(loaded, 3_600_000))
66
+ pass("Cache TTL (fresh)");
67
+ else
68
+ fail("Cache TTL", "Fresh cache rejected");
69
+ const oldCache = { ...testCache, generatedAt: new Date(Date.now() - 7_200_000).toISOString() };
70
+ writeCache(oldCache, cachePath);
71
+ if (!isCacheValid(readCache(cachePath), 3_600_000))
72
+ pass("Cache TTL (expired rejected)");
73
+ else
74
+ fail("Cache TTL", "Expired cache accepted");
75
+ const verifier = createWebhookVerifier(WEBHOOK_SECRET);
76
+ const body = '{"test":true}';
77
+ const validSig = createHmac("sha256", WEBHOOK_SECRET).update(body).digest("hex");
78
+ if (verifier(body, validSig))
79
+ pass("Webhook signature (valid accepted)");
80
+ else
81
+ fail("Webhook signature", "Valid sig rejected");
82
+ if (!verifier(body, "invalid-signature"))
83
+ pass("Webhook signature (invalid rejected)");
84
+ else
85
+ fail("Webhook signature", "Invalid sig accepted");
86
+ if (!verifier(body + "tampered", validSig))
87
+ pass("Webhook signature (tampered rejected)");
88
+ else
89
+ fail("Webhook signature", "Tampered body accepted");
90
+ let purchaseCount = 0;
91
+ const handler = createWebhookHandler({
92
+ onPurchase: async () => { purchaseCount++; },
93
+ });
94
+ const orderPayload = {
95
+ meta: { event_name: "order_created", test_mode: false, custom_data: { user_id: "usr_1" } },
96
+ data: { id: "ord_1", type: "orders", attributes: { user_email: "test@test.com", customer_id: 1, variant_id: "v1", product_name: "Pro", total: 499 } },
97
+ };
98
+ await handler(orderPayload);
99
+ if (purchaseCount === 1)
100
+ pass("Webhook dispatch (order_created)");
101
+ else
102
+ fail("Webhook dispatch", `Expected 1 call, got ${purchaseCount}`);
103
+ const dup = await handler(orderPayload);
104
+ if (dup.skipped && purchaseCount === 1)
105
+ pass("Webhook deduplication");
106
+ else
107
+ fail("Webhook dedup", "Duplicate not skipped");
108
+ const logger = createLogger({ filePath: logPath });
109
+ if (logger)
110
+ pass("File logger created");
111
+ else
112
+ fail("File logger", "createLogger returned undefined");
113
+ if (logger) {
114
+ const wrapped = withLogger(logger, "testOp", async (args) => ({ ok: true }));
115
+ await wrapped({ email: "secret@test.com", apiKey: "ls_live_abcdef123456" });
116
+ const logContent = readFileSync(logPath, "utf-8").trim();
117
+ const logLines = logContent.split("\n").filter(line => line.trim());
118
+ if (logLines.length > 0) {
119
+ try {
120
+ const entry = JSON.parse(logLines[0]);
121
+ if (entry.op === "testOp" && entry.input.email.includes("*") && entry.input.apiKey.includes("...")) {
122
+ pass("Logger masking (email + apiKey)");
123
+ }
124
+ else {
125
+ fail("Logger masking", "Sensitive fields not masked");
126
+ }
127
+ }
128
+ catch {
129
+ fail("Logger masking", "Failed to parse log entry");
130
+ }
131
+ }
132
+ else {
133
+ fail("Logger masking", "No log entries found");
134
+ }
135
+ }
136
+ let retryAttempts = 0;
137
+ try {
138
+ await withRetry(async () => {
139
+ retryAttempts++;
140
+ const err = new Error("client error");
141
+ err.status = 422;
142
+ throw err;
143
+ }, "retryTest", 3);
144
+ }
145
+ catch { }
146
+ if (retryAttempts === 1)
147
+ pass("Retry (4xx not retried)");
148
+ else
149
+ fail("Retry", `Expected 1 attempt, got ${retryAttempts}`);
150
+ writeCache(testCache, cachePath);
151
+ const billing = await createBilling({
152
+ apiKey: "dummy-key-cache-hit",
153
+ storeId: "test-store",
154
+ webhookSecret: WEBHOOK_SECRET,
155
+ cachePath: cachePath,
156
+ cacheTtlMs: 3_600_000,
157
+ callbacks: { onPurchase: async () => { } },
158
+ });
159
+ if (billing.stores.length > 0 && billing.plans.length === 1 && billing.plans[0].price === 499) {
160
+ pass("createBilling from cache");
161
+ }
162
+ else {
163
+ fail("createBilling from cache", "Unexpected plans/stores");
164
+ }
165
+ if (billing.verifyWebhook(body, validSig))
166
+ pass("billing.verifyWebhook");
167
+ else
168
+ fail("billing.verifyWebhook", "Valid sig rejected");
169
+ }
170
+ async function validateLive(apiKey, cachePath, logPath) {
171
+ if (!apiKey) {
172
+ console.log("\n\ud83c\udf10 Live Validation\n");
173
+ console.log(" \u23ed\ufe0f Skipped \u2014 set LS_API_KEY env var to run live tests");
174
+ return;
175
+ }
176
+ console.log("\n\ud83c\udf10 Live Validation (real API calls)\n");
177
+ cleanup(cachePath, logPath);
178
+ const liveCachePath = "/tmp/lemonsqueezy-billing-live-cache.json";
179
+ const billing = await createBilling({
180
+ apiKey: apiKey,
181
+ webhookSecret: WEBHOOK_SECRET,
182
+ cachePath: liveCachePath,
183
+ cacheTtlMs: 0,
184
+ logger: { filePath: logPath },
185
+ callbacks: {
186
+ onPurchase: async () => { },
187
+ onRefund: async () => { },
188
+ },
189
+ });
190
+ if (billing.stores.length > 0) {
191
+ pass(`Store discovered: ${billing.stores[0].name} (${billing.stores[0].id})`);
192
+ }
193
+ else {
194
+ fail("Store discovery", "No stores found");
195
+ }
196
+ if (billing.plans.length > 0) {
197
+ for (const plan of billing.plans) {
198
+ pass(`Plan: ${plan.name} / ${plan.variantName} \u2014 ${plan.priceFormatted}`);
199
+ }
200
+ }
201
+ else {
202
+ fail("Plans", "No published products found");
203
+ }
204
+ cleanup(cachePath, logPath);
205
+ }
206
+ //# sourceMappingURL=cli-validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-validate.js","sourceRoot":"","sources":["../src/cli-validate.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env node
2
+ import { runWizard } from "./wizard.js";
3
+ import { runValidate } from "./cli-validate.js";
4
+ function printHelp() {
5
+ console.log(`
6
+ Lemon Squeezy Billing CLI
7
+
8
+ Usage: lemonsqueezy-billing <command>
9
+
10
+ Commands:
11
+ wizard Run interactive setup wizard
12
+ validate Validate billing configuration
13
+ help Show this help message
14
+
15
+ Examples:
16
+ npx lemonsqueezy-billing wizard
17
+ npx lemonsqueezy-billing validate
18
+ `);
19
+ }
20
+ async function main() {
21
+ const args = process.argv.slice(2);
22
+ const command = args[0] || "help";
23
+ switch (command) {
24
+ case "wizard":
25
+ await runWizard();
26
+ break;
27
+ case "validate":
28
+ await runValidate();
29
+ break;
30
+ case "help":
31
+ default:
32
+ printHelp();
33
+ process.exit(command === "help" ? 0 : 1);
34
+ }
35
+ }
36
+ main().catch((error) => {
37
+ console.error("Error:", error.message);
38
+ process.exit(1);
39
+ });
40
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,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,3 @@
1
+ import type { Billing, BillingConfig } from "./types.js";
2
+ export declare function createBilling(config: BillingConfig): Promise<Billing>;
3
+ //# sourceMappingURL=createBilling.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createBilling.d.ts","sourceRoot":"","sources":["../src/createBilling.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,aAAa,EAAwD,MAAM,YAAY,CAAC;AAgB/G,wBAAsB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CA4G3E"}
@@ -0,0 +1,82 @@
1
+ import { bootstrap } from "./bootstrap.js";
2
+ import { createCheckoutFactory } from "./checkout.js";
3
+ import { createWebhookVerifier, createWebhookHandler } from "./webhook.js";
4
+ import { createLogger, withLogger } from "./logger.js";
5
+ import { createExpressRouter } from "./express.js";
6
+ import { getCustomerPortalUrl } from "./portal.js";
7
+ import { fetchProducts, flattenPlans } from "./plans.js";
8
+ import { writeCache } from "./cache.js";
9
+ import { createSubscriptionManagement } from "./subscriptions.js";
10
+ import { createLicenseKeyManagement } from "./licenses.js";
11
+ import { createCustomerManagement } from "./customers.js";
12
+ import { createWebhookManagement } from "./webhooks.js";
13
+ import { createDedupBackend } from "./dedup.js";
14
+ import { healthCheck } from "./health.js";
15
+ export async function createBilling(config) {
16
+ const logger = createLogger(config.logger);
17
+ const doBootstrap = async () => {
18
+ return bootstrap(config);
19
+ };
20
+ const loggedBootstrap = withLogger(logger, "bootstrap", async (_args) => doBootstrap());
21
+ const { stores, plans: initialPlans, cache } = await loggedBootstrap({});
22
+ let currentPlans = initialPlans;
23
+ const storeId = cache.store.id;
24
+ const rawCreateCheckout = createCheckoutFactory(storeId, config.checkoutExpiresInMs);
25
+ const loggedCheckout = withLogger(logger, "createCheckout", async (args) => rawCreateCheckout(args), (url) => ({ checkoutUrl: typeof url === "string" ? `${url.slice(0, 50)}...` : "" }));
26
+ const verifyWebhook = config.webhookSecret
27
+ ? createWebhookVerifier(config.webhookSecret)
28
+ : () => { throw new Error("webhookSecret is required for webhook verification"); };
29
+ const rawHandleWebhook = createWebhookHandler(config.callbacks);
30
+ const loggedHandleWebhook = withLogger(logger, "handleWebhook", async (args) => rawHandleWebhook(args), (result) => ({ dispatched: result.dispatched, skipped: result.skipped }));
31
+ const refreshPlans = async () => {
32
+ const products = await fetchProducts(storeId);
33
+ currentPlans = flattenPlans(products);
34
+ writeCache({ generatedAt: new Date().toISOString(), store: cache.store, products }, config.cachePath);
35
+ };
36
+ const loggedGetPortal = withLogger(logger, "getCustomerPortal", async (args) => getCustomerPortalUrl(args.customerId), (url) => ({ portalUrl: typeof url === "string" ? `${url.slice(0, 50)}...` : "" }));
37
+ const subscriptionManagement = createSubscriptionManagement();
38
+ const licenseKeyManagement = createLicenseKeyManagement();
39
+ const customerManagement = createCustomerManagement();
40
+ const webhookManagement = createWebhookManagement(storeId);
41
+ const dedupBackend = createDedupBackend(config.dedup);
42
+ const billing = {
43
+ stores,
44
+ get plans() { return currentPlans; },
45
+ createCheckout: (params) => loggedCheckout(params),
46
+ verifyWebhook: (rawBody, signature) => verifyWebhook(rawBody, signature),
47
+ handleWebhook: async (payload) => {
48
+ await loggedHandleWebhook(payload);
49
+ },
50
+ refreshPlans,
51
+ getCustomerPortal: (customerId) => loggedGetPortal({ customerId }),
52
+ getExpressRouter: (options) => createExpressRouter({
53
+ plans: currentPlans,
54
+ createCheckout: rawCreateCheckout,
55
+ verifyWebhook,
56
+ handleWebhook: rawHandleWebhook,
57
+ }, options),
58
+ // Subscription Management
59
+ pauseSubscription: subscriptionManagement.pauseSubscription,
60
+ resumeSubscription: subscriptionManagement.resumeSubscription,
61
+ cancelSubscription: subscriptionManagement.cancelSubscription,
62
+ changeSubscriptionVariant: subscriptionManagement.changeSubscriptionVariant,
63
+ resumeCancelledSubscription: subscriptionManagement.resumeCancelledSubscription,
64
+ // License Key Management
65
+ validateLicense: licenseKeyManagement.validateLicense,
66
+ getLicenseDetails: licenseKeyManagement.getLicenseDetails,
67
+ activateLicense: licenseKeyManagement.activateLicense,
68
+ deactivateLicense: licenseKeyManagement.deactivateLicense,
69
+ // Customer Management
70
+ getCustomerByEmail: customerManagement.getCustomerByEmail,
71
+ getSubscriptionsForUser: customerManagement.getSubscriptionsForUser,
72
+ // Webhook Management
73
+ createWebhook: webhookManagement.createWebhook,
74
+ deleteWebhook: webhookManagement.deleteWebhook,
75
+ // Deduplication
76
+ dedupBackend,
77
+ // Health Check
78
+ healthCheck,
79
+ };
80
+ return billing;
81
+ }
82
+ //# sourceMappingURL=createBilling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"createBilling.js","sourceRoot":"","sources":["../src/createBilling.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { CustomerManagement } from "./types.js";
2
+ export declare function createCustomerManagement(): CustomerManagement;
3
+ //# sourceMappingURL=customers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.d.ts","sourceRoot":"","sources":["../src/customers.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAkB,MAAM,YAAY,CAAC;AAGrE,wBAAgB,wBAAwB,IAAI,kBAAkB,CAgF7D"}
@@ -0,0 +1,57 @@
1
+ import { listCustomers } from "@lemonsqueezy/lemonsqueezy.js";
2
+ import { withRetry } from "./retry.js";
3
+ export function createCustomerManagement() {
4
+ const getCustomerByEmail = async (email) => {
5
+ const response = await withRetry(() => listCustomers({ filter: { email } }), "listCustomers");
6
+ if (response.error || !response.data?.data || response.data.data.length === 0) {
7
+ return null;
8
+ }
9
+ const customer = response.data.data[0];
10
+ const attrs = customer.attributes;
11
+ // Get subscriptions for this customer
12
+ const subscriptionsResponse = await withRetry(() => listCustomers({ filter: { email }, include: ["subscriptions"] }), "listCustomersWithSubscriptions");
13
+ const subscriptions = subscriptionsResponse.data?.included
14
+ ?.filter(item => item.type === "subscription")
15
+ .map(item => ({
16
+ id: item.id,
17
+ status: String(item.attributes.status ?? ""),
18
+ variantId: String(item.attributes.variant_id ?? ""),
19
+ productId: String(item.attributes.product_id ?? ""),
20
+ price: Number(item.attributes.renews_at_price ?? 0),
21
+ nextBillingDate: String(item.attributes.renews_at ?? ""),
22
+ endsAt: String(item.attributes.ends_at ?? ""),
23
+ })) || [];
24
+ const billingAddress = attrs.billing_address ? {
25
+ name: attrs.billing_address.name || attrs.name || "",
26
+ address1: attrs.billing_address.address || "",
27
+ address2: attrs.billing_address.address2 || undefined,
28
+ city: attrs.billing_address.city || "",
29
+ country: attrs.billing_address.country || "",
30
+ zip: attrs.billing_address.zip || "",
31
+ state: attrs.billing_address.state || undefined,
32
+ } : undefined;
33
+ return {
34
+ id: customer.id,
35
+ email: attrs.email,
36
+ name: attrs.name,
37
+ billingAddress,
38
+ subscriptions,
39
+ };
40
+ };
41
+ const getSubscriptionsForUser = async (userId) => {
42
+ // This would typically require storing the userId in custom_data
43
+ // For now, we'll search by email if userId is an email
44
+ if (userId.includes('@')) {
45
+ const customer = await getCustomerByEmail(userId);
46
+ return customer?.subscriptions || [];
47
+ }
48
+ // If userId is not an email, you would need to implement
49
+ // a lookup mechanism based on your user database
50
+ return [];
51
+ };
52
+ return {
53
+ getCustomerByEmail,
54
+ getSubscriptionsForUser,
55
+ };
56
+ }
57
+ //# sourceMappingURL=customers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customers.js","sourceRoot":"","sources":["../src/customers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,60 @@
1
+ import type { DedupBackend, DedupConfig } from "./types.js";
2
+ export interface RedisClient {
3
+ exists(key: string): Promise<number>;
4
+ setex(key: string, ttlSeconds: number, value: string): Promise<void>;
5
+ }
6
+ export interface DatabaseClient {
7
+ webhookDedup: {
8
+ findUnique: (args: {
9
+ where: {
10
+ key: string;
11
+ };
12
+ select: {
13
+ expiresAt: true;
14
+ };
15
+ }) => Promise<{
16
+ expiresAt: Date;
17
+ } | null>;
18
+ delete: (args: {
19
+ where: {
20
+ key: string;
21
+ };
22
+ }) => Promise<void>;
23
+ upsert: (args: {
24
+ where: {
25
+ key: string;
26
+ };
27
+ update: {
28
+ expiresAt: Date;
29
+ };
30
+ create: {
31
+ key: string;
32
+ expiresAt: Date;
33
+ };
34
+ }) => Promise<void>;
35
+ };
36
+ }
37
+ export declare class InMemoryDedupBackend implements DedupBackend {
38
+ private ttlMs;
39
+ private seen;
40
+ constructor(ttlMs?: number);
41
+ private cleanup;
42
+ isDuplicate(key: string): Promise<boolean>;
43
+ markDuplicate(key: string, _ttlMs: number): Promise<void>;
44
+ }
45
+ export declare class RedisDedupBackend implements DedupBackend {
46
+ private defaultTtlMs;
47
+ private redis;
48
+ constructor(redisClient: RedisClient, defaultTtlMs?: number);
49
+ isDuplicate(key: string): Promise<boolean>;
50
+ markDuplicate(key: string, ttlMs: number): Promise<void>;
51
+ }
52
+ export declare class DatabaseDedupBackend implements DedupBackend {
53
+ private defaultTtlMs;
54
+ private db;
55
+ constructor(databaseClient: DatabaseClient, defaultTtlMs?: number);
56
+ isDuplicate(key: string): Promise<boolean>;
57
+ markDuplicate(key: string, ttlMs: number): Promise<void>;
58
+ }
59
+ export declare function createDedupBackend(config?: DedupConfig): DedupBackend;
60
+ //# sourceMappingURL=dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtE;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE;QACZ,UAAU,EAAE,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,SAAS,EAAE,IAAI,CAAA;aAAE,CAAA;SAAE,KAAK,OAAO,CAAC;YAAE,SAAS,EAAE,IAAI,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;QACnH,MAAM,EAAE,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAA;aAAE,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,EAAE,CAAC,IAAI,EAAE;YAAE,KAAK,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,SAAS,EAAE,IAAI,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE;gBAAE,GAAG,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,IAAI,CAAA;aAAE,CAAA;SAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACpI,CAAC;CACH;AAED,qBAAa,oBAAqB,YAAW,YAAY;IAG3C,OAAO,CAAC,KAAK;IAFzB,OAAO,CAAC,IAAI,CAA6B;gBAErB,KAAK,GAAE,MAAkB;IAE7C,OAAO,CAAC,OAAO;IAOT,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhE;AAED,qBAAa,iBAAkB,YAAW,YAAY;IAGd,OAAO,CAAC,YAAY;IAF1D,OAAO,CAAC,KAAK,CAAc;gBAEf,WAAW,EAAE,WAAW,EAAU,YAAY,GAAE,MAAkB;IAIxE,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAK1C,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAI/D;AAED,qBAAa,oBAAqB,YAAW,YAAY;IAGX,OAAO,CAAC,YAAY;IAFhE,OAAO,CAAC,EAAE,CAAiB;gBAEf,cAAc,EAAE,cAAc,EAAU,YAAY,GAAE,MAAkB;IAI9E,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgB1C,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAU/D;AAED,wBAAgB,kBAAkB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,YAAY,CAMrE"}
package/dist/dedup.js ADDED
@@ -0,0 +1,74 @@
1
+ export class InMemoryDedupBackend {
2
+ ttlMs;
3
+ seen = new Map();
4
+ constructor(ttlMs = 3_600_000) {
5
+ this.ttlMs = ttlMs;
6
+ }
7
+ cleanup() {
8
+ const now = Date.now();
9
+ for (const [key, timestamp] of this.seen) {
10
+ if (now - timestamp > this.ttlMs)
11
+ this.seen.delete(key);
12
+ }
13
+ }
14
+ async isDuplicate(key) {
15
+ this.cleanup();
16
+ return this.seen.has(key);
17
+ }
18
+ async markDuplicate(key, _ttlMs) {
19
+ this.seen.set(key, Date.now());
20
+ }
21
+ }
22
+ export class RedisDedupBackend {
23
+ defaultTtlMs;
24
+ redis;
25
+ constructor(redisClient, defaultTtlMs = 3_600_000) {
26
+ this.defaultTtlMs = defaultTtlMs;
27
+ this.redis = redisClient;
28
+ }
29
+ async isDuplicate(key) {
30
+ const exists = await this.redis.exists(key);
31
+ return exists === 1;
32
+ }
33
+ async markDuplicate(key, ttlMs) {
34
+ const ttlSeconds = Math.ceil((ttlMs || this.defaultTtlMs) / 1000);
35
+ await this.redis.setex(key, ttlSeconds, "1");
36
+ }
37
+ }
38
+ export class DatabaseDedupBackend {
39
+ defaultTtlMs;
40
+ db;
41
+ constructor(databaseClient, defaultTtlMs = 3_600_000) {
42
+ this.defaultTtlMs = defaultTtlMs;
43
+ this.db = databaseClient;
44
+ }
45
+ async isDuplicate(key) {
46
+ const record = await this.db.webhookDedup.findUnique({
47
+ where: { key },
48
+ select: { expiresAt: true }
49
+ });
50
+ if (!record)
51
+ return false;
52
+ if (new Date() > record.expiresAt) {
53
+ await this.db.webhookDedup.delete({ where: { key } });
54
+ return false;
55
+ }
56
+ return true;
57
+ }
58
+ async markDuplicate(key, ttlMs) {
59
+ const ttl = ttlMs || this.defaultTtlMs;
60
+ const expiresAt = new Date(Date.now() + ttl);
61
+ await this.db.webhookDedup.upsert({
62
+ where: { key },
63
+ update: { expiresAt },
64
+ create: { key, expiresAt }
65
+ });
66
+ }
67
+ }
68
+ export function createDedupBackend(config) {
69
+ if (config?.backend) {
70
+ return config.backend;
71
+ }
72
+ return new InMemoryDedupBackend(config?.ttlMs);
73
+ }
74
+ //# sourceMappingURL=dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dedup.js","sourceRoot":"","sources":["../src/dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import type { ExpressRouterOptions, Plan, CheckoutParams, WebhookPayload } from "./types.js";
2
+ interface RouterDeps {
3
+ plans: Plan[];
4
+ createCheckout: (params: CheckoutParams) => Promise<string>;
5
+ verifyWebhook: (rawBody: string, signature: string) => boolean;
6
+ handleWebhook: (payload: WebhookPayload) => Promise<{
7
+ dispatched: string | null;
8
+ skipped: boolean;
9
+ }>;
10
+ }
11
+ export declare function createExpressRouter(deps: RouterDeps, options: ExpressRouterOptions): unknown;
12
+ export {};
13
+ //# sourceMappingURL=express.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"express.d.ts","sourceRoot":"","sources":["../src/express.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,IAAI,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE7F,UAAU,UAAU;IAClB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,cAAc,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5D,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,KAAK,OAAO,CAAC;IAC/D,aAAa,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC;QAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CACtG;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,oBAAoB,GAAG,OAAO,CA8F5F"}