paddle-checkout-accelerator 2.5.0 → 2.7.0
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.
|
@@ -118,6 +118,331 @@ function appendEnvSafe(values) {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
function readEnvFile() {
|
|
122
|
+
const envPath =
|
|
123
|
+
path.join(cwd, ".env.local");
|
|
124
|
+
|
|
125
|
+
if (!fs.existsSync(envPath)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return fs.readFileSync(envPath, "utf8");
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function hasEnvValue(env, key) {
|
|
133
|
+
if (!env) return false;
|
|
134
|
+
|
|
135
|
+
const line =
|
|
136
|
+
env
|
|
137
|
+
.split("\n")
|
|
138
|
+
.find((entry) =>
|
|
139
|
+
entry.startsWith(`${key}=`)
|
|
140
|
+
);
|
|
141
|
+
|
|
142
|
+
if (!line) return false;
|
|
143
|
+
|
|
144
|
+
const value =
|
|
145
|
+
line.slice(key.length + 1).trim();
|
|
146
|
+
|
|
147
|
+
return value.length > 0;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function runDoctor() {
|
|
151
|
+
const env =
|
|
152
|
+
readEnvFile();
|
|
153
|
+
|
|
154
|
+
const checks = [
|
|
155
|
+
{
|
|
156
|
+
label: ".env.local exists",
|
|
157
|
+
pass: Boolean(env),
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
label: "PADDLE_API_KEY set",
|
|
161
|
+
pass: hasEnvValue(env, "PADDLE_API_KEY"),
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
label: "PADDLE_WEBHOOK_SECRET set",
|
|
165
|
+
pass: hasEnvValue(env, "PADDLE_WEBHOOK_SECRET"),
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
label: "NEXT_PUBLIC_PADDLE_CLIENT_TOKEN set",
|
|
169
|
+
pass: hasEnvValue(env, "NEXT_PUBLIC_PADDLE_CLIENT_TOKEN"),
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
label: "billing config exists",
|
|
173
|
+
pass: exists("src/lib/billing.ts"),
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
label: "webhook route exists",
|
|
177
|
+
pass: exists("src/app/api/paddle/webhook/route.ts"),
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
label: "portal route exists",
|
|
181
|
+
pass: exists("src/app/api/paddle/portal-session/route.ts"),
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
label: "refresh route exists",
|
|
185
|
+
pass: exists("src/app/api/paddle/refresh-subscription/route.ts"),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
label: "repair route exists",
|
|
189
|
+
pass: exists("src/app/api/paddle/repair-by-email/route.ts"),
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
label: "pricing page exists",
|
|
193
|
+
pass: exists("src/app/billing/pricing/page.tsx"),
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
label: "billing dashboard exists",
|
|
197
|
+
pass: exists("src/app/billing/dashboard/page.tsx"),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
label: "customer repair page exists",
|
|
201
|
+
pass: exists("src/app/billing/customer-repair/page.tsx"),
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
|
|
205
|
+
console.log("");
|
|
206
|
+
console.log("Paddle Checkout Accelerator Doctor");
|
|
207
|
+
console.log("");
|
|
208
|
+
|
|
209
|
+
let failed = 0;
|
|
210
|
+
|
|
211
|
+
for (const check of checks) {
|
|
212
|
+
if (check.pass) {
|
|
213
|
+
console.log(`✅ ${check.label}`);
|
|
214
|
+
} else {
|
|
215
|
+
failed += 1;
|
|
216
|
+
console.log(`❌ ${check.label}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
console.log("");
|
|
221
|
+
|
|
222
|
+
if (failed === 0) {
|
|
223
|
+
console.log("All checks passed.");
|
|
224
|
+
process.exit(0);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
console.log(`${failed} check(s) failed.`);
|
|
228
|
+
console.log("");
|
|
229
|
+
console.log("Fix the missing items above, then run:");
|
|
230
|
+
console.log(" npx paddle-checkout-accelerator doctor
|
|
231
|
+
npx paddle-checkout-accelerator verify");
|
|
232
|
+
|
|
233
|
+
process.exit(1);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function parseEnv(env) {
|
|
237
|
+
const values = {};
|
|
238
|
+
|
|
239
|
+
if (!env) return values;
|
|
240
|
+
|
|
241
|
+
for (const line of env.split("\n")) {
|
|
242
|
+
if (!line || line.trim().startsWith("#")) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const index = line.indexOf("=");
|
|
247
|
+
|
|
248
|
+
if (index === -1) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
const key = line.slice(0, index).trim();
|
|
253
|
+
const value = line.slice(index + 1).trim();
|
|
254
|
+
|
|
255
|
+
values[key] = value;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return values;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function paddleRequest(pathname, apiKey) {
|
|
262
|
+
const response = await fetch(
|
|
263
|
+
`https://api.paddle.com${pathname}`,
|
|
264
|
+
{
|
|
265
|
+
headers: {
|
|
266
|
+
Authorization: `Bearer ${apiKey}`,
|
|
267
|
+
},
|
|
268
|
+
}
|
|
269
|
+
);
|
|
270
|
+
|
|
271
|
+
return response;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
async function runVerify() {
|
|
275
|
+
const env =
|
|
276
|
+
readEnvFile();
|
|
277
|
+
|
|
278
|
+
const values =
|
|
279
|
+
parseEnv(env);
|
|
280
|
+
|
|
281
|
+
const apiKey =
|
|
282
|
+
values.PADDLE_API_KEY;
|
|
283
|
+
|
|
284
|
+
const checks = [];
|
|
285
|
+
|
|
286
|
+
function add(label, pass, details = "") {
|
|
287
|
+
checks.push({
|
|
288
|
+
label,
|
|
289
|
+
pass,
|
|
290
|
+
details,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
add(
|
|
295
|
+
".env.local exists",
|
|
296
|
+
Boolean(env)
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
add(
|
|
300
|
+
"PADDLE_API_KEY present",
|
|
301
|
+
Boolean(apiKey)
|
|
302
|
+
);
|
|
303
|
+
|
|
304
|
+
add(
|
|
305
|
+
"PADDLE_WEBHOOK_SECRET present",
|
|
306
|
+
Boolean(values.PADDLE_WEBHOOK_SECRET)
|
|
307
|
+
);
|
|
308
|
+
|
|
309
|
+
add(
|
|
310
|
+
"NEXT_PUBLIC_PADDLE_CLIENT_TOKEN present",
|
|
311
|
+
Boolean(values.NEXT_PUBLIC_PADDLE_CLIENT_TOKEN)
|
|
312
|
+
);
|
|
313
|
+
|
|
314
|
+
add(
|
|
315
|
+
"billing config exists",
|
|
316
|
+
exists("src/lib/billing.ts")
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
add(
|
|
320
|
+
"webhook route exists",
|
|
321
|
+
exists("src/app/api/paddle/webhook/route.ts")
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
if (apiKey) {
|
|
325
|
+
try {
|
|
326
|
+
const productsResponse =
|
|
327
|
+
await paddleRequest(
|
|
328
|
+
"/products",
|
|
329
|
+
apiKey
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
add(
|
|
333
|
+
"Paddle API reachable",
|
|
334
|
+
productsResponse.ok,
|
|
335
|
+
productsResponse.ok
|
|
336
|
+
? ""
|
|
337
|
+
: `status ${productsResponse.status}`
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
if (productsResponse.ok) {
|
|
341
|
+
const products =
|
|
342
|
+
await productsResponse.json();
|
|
343
|
+
|
|
344
|
+
const count =
|
|
345
|
+
Array.isArray(products?.data)
|
|
346
|
+
? products.data.length
|
|
347
|
+
: 0;
|
|
348
|
+
|
|
349
|
+
add(
|
|
350
|
+
"Paddle products found",
|
|
351
|
+
count > 0,
|
|
352
|
+
`${count} product(s)`
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const pricesResponse =
|
|
357
|
+
await paddleRequest(
|
|
358
|
+
"/prices",
|
|
359
|
+
apiKey
|
|
360
|
+
);
|
|
361
|
+
|
|
362
|
+
if (pricesResponse.ok) {
|
|
363
|
+
const prices =
|
|
364
|
+
await pricesResponse.json();
|
|
365
|
+
|
|
366
|
+
const count =
|
|
367
|
+
Array.isArray(prices?.data)
|
|
368
|
+
? prices.data.length
|
|
369
|
+
: 0;
|
|
370
|
+
|
|
371
|
+
add(
|
|
372
|
+
"Paddle prices found",
|
|
373
|
+
count > 0,
|
|
374
|
+
`${count} price(s)`
|
|
375
|
+
);
|
|
376
|
+
} else {
|
|
377
|
+
add(
|
|
378
|
+
"Paddle prices found",
|
|
379
|
+
false,
|
|
380
|
+
`status ${pricesResponse.status}`
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
} catch (error) {
|
|
384
|
+
add(
|
|
385
|
+
"Paddle API reachable",
|
|
386
|
+
false,
|
|
387
|
+
error instanceof Error
|
|
388
|
+
? error.message
|
|
389
|
+
: "unknown error"
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
} else {
|
|
393
|
+
add(
|
|
394
|
+
"Paddle API reachable",
|
|
395
|
+
false,
|
|
396
|
+
"missing PADDLE_API_KEY"
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
add(
|
|
400
|
+
"Paddle products found",
|
|
401
|
+
false,
|
|
402
|
+
"missing PADDLE_API_KEY"
|
|
403
|
+
);
|
|
404
|
+
|
|
405
|
+
add(
|
|
406
|
+
"Paddle prices found",
|
|
407
|
+
false,
|
|
408
|
+
"missing PADDLE_API_KEY"
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
console.log("");
|
|
413
|
+
console.log("Paddle Checkout Accelerator Verify");
|
|
414
|
+
console.log("");
|
|
415
|
+
|
|
416
|
+
let passed = 0;
|
|
417
|
+
|
|
418
|
+
for (const check of checks) {
|
|
419
|
+
if (check.pass) {
|
|
420
|
+
passed += 1;
|
|
421
|
+
console.log(
|
|
422
|
+
`✅ ${check.label}${check.details ? ` — ${check.details}` : ""}`
|
|
423
|
+
);
|
|
424
|
+
} else {
|
|
425
|
+
console.log(
|
|
426
|
+
`❌ ${check.label}${check.details ? ` — ${check.details}` : ""}`
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const score =
|
|
432
|
+
Math.round(
|
|
433
|
+
(passed / checks.length) * 100
|
|
434
|
+
);
|
|
435
|
+
|
|
436
|
+
console.log("");
|
|
437
|
+
console.log(`Readiness Score: ${score}%`);
|
|
438
|
+
|
|
439
|
+
if (score < 100) {
|
|
440
|
+
process.exit(1);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
process.exit(0);
|
|
444
|
+
}
|
|
445
|
+
|
|
121
446
|
async function getConfig() {
|
|
122
447
|
const detectedAdapter =
|
|
123
448
|
detectAdapter();
|
|
@@ -647,11 +972,21 @@ Usage:
|
|
|
647
972
|
npx paddle-checkout-accelerator init
|
|
648
973
|
npx paddle-checkout-accelerator init --interactive
|
|
649
974
|
npx paddle-checkout-accelerator init --force
|
|
975
|
+
npx paddle-checkout-accelerator doctor
|
|
976
|
+
npx paddle-checkout-accelerator verify
|
|
650
977
|
npx paddle-checkout-accelerator init --minimal
|
|
651
978
|
`);
|
|
652
979
|
process.exit(0);
|
|
653
980
|
}
|
|
654
981
|
|
|
982
|
+
if (command === "doctor") {
|
|
983
|
+
runDoctor();
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
if (command === "verify") {
|
|
987
|
+
await runVerify();
|
|
988
|
+
}
|
|
989
|
+
|
|
655
990
|
if (command !== "init") {
|
|
656
991
|
console.error(
|
|
657
992
|
`Unknown command: ${command}`
|