emulate 0.4.1 → 0.6.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.
- package/README.md +198 -27
- package/dist/api.d.ts +2 -1
- package/dist/api.js +675 -103
- package/dist/api.js.map +1 -1
- package/dist/chunk-WVQMFHQM.js +83 -0
- package/dist/chunk-WVQMFHQM.js.map +1 -0
- package/dist/{dist-B674PYKV.js → dist-2ZZGNPJI.js} +22 -43
- package/dist/dist-2ZZGNPJI.js.map +1 -0
- package/dist/{dist-RDFBZ5O6.js → dist-CXRPM6BK.js} +211 -48
- package/dist/dist-CXRPM6BK.js.map +1 -0
- package/dist/{dist-VVXVP5EZ.js → dist-DSJSF3GY.js} +551 -91
- package/dist/dist-DSJSF3GY.js.map +1 -0
- package/dist/{dist-RMK3BS5M.js → dist-IFULY5LE.js} +196 -33
- package/dist/dist-IFULY5LE.js.map +1 -0
- package/dist/dist-IRUBHCZU.js +1898 -0
- package/dist/dist-IRUBHCZU.js.map +1 -0
- package/dist/{dist-YOVM5HEY.js → dist-NJJLJT2N.js} +520 -61
- package/dist/dist-NJJLJT2N.js.map +1 -0
- package/dist/dist-OGSAVJ25.js +4874 -0
- package/dist/dist-OGSAVJ25.js.map +1 -0
- package/dist/{dist-H6JYGQM4.js → dist-PO4CL5SJ.js} +271 -158
- package/dist/dist-PO4CL5SJ.js.map +1 -0
- package/dist/{dist-QMOJM6DV.js → dist-R3TNKUIE.js} +238 -55
- package/dist/dist-R3TNKUIE.js.map +1 -0
- package/dist/{dist-6JFNJPUU.js → dist-WACHAAVU.js} +171 -22
- package/dist/dist-WACHAAVU.js.map +1 -0
- package/dist/{dist-OTJZRQ3Q.js → dist-XWWZVLQQ.js} +216 -75
- package/dist/dist-XWWZVLQQ.js.map +1 -0
- package/dist/{dist-6EW7SSOZ.js → dist-ZY5SZSJ2.js} +397 -223
- package/dist/dist-ZY5SZSJ2.js.map +1 -0
- package/dist/fonts/favicon.ico +0 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js +17 -0
- package/dist/helpers-LXLP3DFE-LBOTATT5.js.map +1 -0
- package/dist/index.js +812 -117
- package/dist/index.js.map +1 -1
- package/package.json +17 -15
- package/dist/chunk-TEPNEZ63.js +0 -2143
- package/dist/chunk-TEPNEZ63.js.map +0 -1
- package/dist/dist-6EW7SSOZ.js.map +0 -1
- package/dist/dist-6JFNJPUU.js.map +0 -1
- package/dist/dist-B674PYKV.js.map +0 -1
- package/dist/dist-G7WQPZ3Y.js +0 -1287
- package/dist/dist-G7WQPZ3Y.js.map +0 -1
- package/dist/dist-H6JYGQM4.js.map +0 -1
- package/dist/dist-OTJZRQ3Q.js.map +0 -1
- package/dist/dist-QMOJM6DV.js.map +0 -1
- package/dist/dist-RDFBZ5O6.js.map +0 -1
- package/dist/dist-RMK3BS5M.js.map +0 -1
- package/dist/dist-VVXVP5EZ.js.map +0 -1
- package/dist/dist-YOVM5HEY.js.map +0 -1
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import "./chunk-TEPNEZ63.js";
|
|
2
|
-
|
|
3
1
|
// ../@emulators/stripe/dist/index.js
|
|
4
2
|
import { randomBytes } from "crypto";
|
|
5
3
|
import { readFileSync } from "fs";
|
|
@@ -190,12 +188,26 @@ function customerRoutes({ app, store, webhooks }) {
|
|
|
190
188
|
});
|
|
191
189
|
app.get("/v1/customers/:id", (c) => {
|
|
192
190
|
const customer = ss.customers.findOneBy("stripe_id", c.req.param("id"));
|
|
193
|
-
if (!customer)
|
|
191
|
+
if (!customer)
|
|
192
|
+
return stripeError(
|
|
193
|
+
c,
|
|
194
|
+
404,
|
|
195
|
+
"invalid_request_error",
|
|
196
|
+
`No such customer: '${c.req.param("id")}'`,
|
|
197
|
+
"resource_missing"
|
|
198
|
+
);
|
|
194
199
|
return c.json(formatCustomer(customer));
|
|
195
200
|
});
|
|
196
201
|
app.post("/v1/customers/:id", async (c) => {
|
|
197
202
|
const customer = ss.customers.findOneBy("stripe_id", c.req.param("id"));
|
|
198
|
-
if (!customer)
|
|
203
|
+
if (!customer)
|
|
204
|
+
return stripeError(
|
|
205
|
+
c,
|
|
206
|
+
404,
|
|
207
|
+
"invalid_request_error",
|
|
208
|
+
`No such customer: '${c.req.param("id")}'`,
|
|
209
|
+
"resource_missing"
|
|
210
|
+
);
|
|
199
211
|
const body = await parseStripeBody(c);
|
|
200
212
|
const updated = ss.customers.update(customer.id, {
|
|
201
213
|
...body.email !== void 0 && { email: body.email },
|
|
@@ -213,7 +225,14 @@ function customerRoutes({ app, store, webhooks }) {
|
|
|
213
225
|
});
|
|
214
226
|
app.delete("/v1/customers/:id", async (c) => {
|
|
215
227
|
const customer = ss.customers.findOneBy("stripe_id", c.req.param("id"));
|
|
216
|
-
if (!customer)
|
|
228
|
+
if (!customer)
|
|
229
|
+
return stripeError(
|
|
230
|
+
c,
|
|
231
|
+
404,
|
|
232
|
+
"invalid_request_error",
|
|
233
|
+
`No such customer: '${c.req.param("id")}'`,
|
|
234
|
+
"resource_missing"
|
|
235
|
+
);
|
|
217
236
|
for (const pi of ss.paymentIntents.findBy("customer_id", customer.stripe_id)) {
|
|
218
237
|
ss.paymentIntents.update(pi.id, { customer_id: null });
|
|
219
238
|
}
|
|
@@ -250,10 +269,24 @@ function paymentIntentRoutes({ app, store, webhooks }) {
|
|
|
250
269
|
app.post("/v1/payment_intents", async (c) => {
|
|
251
270
|
const body = await parseStripeBody(c);
|
|
252
271
|
if (!body.amount || !body.currency) {
|
|
253
|
-
return stripeError(
|
|
272
|
+
return stripeError(
|
|
273
|
+
c,
|
|
274
|
+
400,
|
|
275
|
+
"invalid_request_error",
|
|
276
|
+
"Missing required param: amount and currency are required.",
|
|
277
|
+
void 0,
|
|
278
|
+
"amount"
|
|
279
|
+
);
|
|
254
280
|
}
|
|
255
281
|
if (body.customer && !ss.customers.findOneBy("stripe_id", body.customer)) {
|
|
256
|
-
return stripeError(
|
|
282
|
+
return stripeError(
|
|
283
|
+
c,
|
|
284
|
+
400,
|
|
285
|
+
"invalid_request_error",
|
|
286
|
+
`No such customer: '${body.customer}'`,
|
|
287
|
+
"resource_missing",
|
|
288
|
+
"customer"
|
|
289
|
+
);
|
|
257
290
|
}
|
|
258
291
|
const status = body.payment_method ? "requires_confirmation" : "requires_payment_method";
|
|
259
292
|
const pi = ss.paymentIntents.insert({
|
|
@@ -276,14 +309,28 @@ function paymentIntentRoutes({ app, store, webhooks }) {
|
|
|
276
309
|
});
|
|
277
310
|
app.get("/v1/payment_intents/:id", (c) => {
|
|
278
311
|
const pi = ss.paymentIntents.findOneBy("stripe_id", c.req.param("id"));
|
|
279
|
-
if (!pi)
|
|
312
|
+
if (!pi)
|
|
313
|
+
return stripeError(
|
|
314
|
+
c,
|
|
315
|
+
404,
|
|
316
|
+
"invalid_request_error",
|
|
317
|
+
`No such payment_intent: '${c.req.param("id")}'`,
|
|
318
|
+
"resource_missing"
|
|
319
|
+
);
|
|
280
320
|
const expand = parseExpand(c);
|
|
281
321
|
const result = applyExpand(formatPaymentIntent(pi), expand, expandResolvers);
|
|
282
322
|
return c.json(result);
|
|
283
323
|
});
|
|
284
324
|
app.post("/v1/payment_intents/:id", async (c) => {
|
|
285
325
|
const pi = ss.paymentIntents.findOneBy("stripe_id", c.req.param("id"));
|
|
286
|
-
if (!pi)
|
|
326
|
+
if (!pi)
|
|
327
|
+
return stripeError(
|
|
328
|
+
c,
|
|
329
|
+
404,
|
|
330
|
+
"invalid_request_error",
|
|
331
|
+
`No such payment_intent: '${c.req.param("id")}'`,
|
|
332
|
+
"resource_missing"
|
|
333
|
+
);
|
|
287
334
|
const body = await parseStripeBody(c);
|
|
288
335
|
const updates = {};
|
|
289
336
|
if (body.amount !== void 0) updates.amount = body.amount;
|
|
@@ -301,10 +348,23 @@ function paymentIntentRoutes({ app, store, webhooks }) {
|
|
|
301
348
|
});
|
|
302
349
|
app.post("/v1/payment_intents/:id/confirm", async (c) => {
|
|
303
350
|
const pi = ss.paymentIntents.findOneBy("stripe_id", c.req.param("id"));
|
|
304
|
-
if (!pi)
|
|
351
|
+
if (!pi)
|
|
352
|
+
return stripeError(
|
|
353
|
+
c,
|
|
354
|
+
404,
|
|
355
|
+
"invalid_request_error",
|
|
356
|
+
`No such payment_intent: '${c.req.param("id")}'`,
|
|
357
|
+
"resource_missing"
|
|
358
|
+
);
|
|
305
359
|
const body = await parseStripeBody(c);
|
|
306
360
|
if (pi.status !== "requires_confirmation" && pi.status !== "requires_payment_method") {
|
|
307
|
-
return stripeError(
|
|
361
|
+
return stripeError(
|
|
362
|
+
c,
|
|
363
|
+
400,
|
|
364
|
+
"invalid_request_error",
|
|
365
|
+
`This PaymentIntent's status is ${pi.status}, which does not allow confirmation.`,
|
|
366
|
+
"payment_intent_unexpected_state"
|
|
367
|
+
);
|
|
308
368
|
}
|
|
309
369
|
if (body.payment_method) {
|
|
310
370
|
ss.paymentIntents.update(pi.id, { payment_method: body.payment_method });
|
|
@@ -329,16 +389,40 @@ function paymentIntentRoutes({ app, store, webhooks }) {
|
|
|
329
389
|
await webhooks.dispatch(
|
|
330
390
|
"charge.succeeded",
|
|
331
391
|
void 0,
|
|
332
|
-
{
|
|
392
|
+
{
|
|
393
|
+
type: "charge.succeeded",
|
|
394
|
+
data: {
|
|
395
|
+
object: {
|
|
396
|
+
id: charge.stripe_id,
|
|
397
|
+
object: "charge",
|
|
398
|
+
amount: charge.amount,
|
|
399
|
+
currency: charge.currency,
|
|
400
|
+
status: charge.status
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
},
|
|
333
404
|
"stripe"
|
|
334
405
|
);
|
|
335
406
|
return c.json(formatPaymentIntent(updated));
|
|
336
407
|
});
|
|
337
408
|
app.post("/v1/payment_intents/:id/cancel", async (c) => {
|
|
338
409
|
const pi = ss.paymentIntents.findOneBy("stripe_id", c.req.param("id"));
|
|
339
|
-
if (!pi)
|
|
410
|
+
if (!pi)
|
|
411
|
+
return stripeError(
|
|
412
|
+
c,
|
|
413
|
+
404,
|
|
414
|
+
"invalid_request_error",
|
|
415
|
+
`No such payment_intent: '${c.req.param("id")}'`,
|
|
416
|
+
"resource_missing"
|
|
417
|
+
);
|
|
340
418
|
if (pi.status === "succeeded" || pi.status === "canceled") {
|
|
341
|
-
return stripeError(
|
|
419
|
+
return stripeError(
|
|
420
|
+
c,
|
|
421
|
+
400,
|
|
422
|
+
"invalid_request_error",
|
|
423
|
+
`This PaymentIntent's status is ${pi.status}, which does not allow cancellation.`,
|
|
424
|
+
"payment_intent_unexpected_state"
|
|
425
|
+
);
|
|
342
426
|
}
|
|
343
427
|
const updated = ss.paymentIntents.update(pi.id, { status: "canceled" });
|
|
344
428
|
await webhooks.dispatch(
|
|
@@ -358,6 +442,31 @@ function paymentIntentRoutes({ app, store, webhooks }) {
|
|
|
358
442
|
return stripeList(c, items, "/v1/payment_intents", formatPaymentIntent);
|
|
359
443
|
});
|
|
360
444
|
}
|
|
445
|
+
function paymentMethodRoutes({ app, store }) {
|
|
446
|
+
const ss = getStripeStore(store);
|
|
447
|
+
app.get("/v1/payment_methods", (c) => {
|
|
448
|
+
const customerId = c.req.query("customer");
|
|
449
|
+
if (customerId && !ss.customers.findOneBy("stripe_id", customerId)) {
|
|
450
|
+
return stripeError(
|
|
451
|
+
c,
|
|
452
|
+
400,
|
|
453
|
+
"invalid_request_error",
|
|
454
|
+
`No such customer: '${customerId}'`,
|
|
455
|
+
"resource_missing",
|
|
456
|
+
"customer"
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
return c.json(
|
|
460
|
+
{
|
|
461
|
+
object: "list",
|
|
462
|
+
url: "/v1/payment_methods",
|
|
463
|
+
has_more: false,
|
|
464
|
+
data: []
|
|
465
|
+
},
|
|
466
|
+
200
|
|
467
|
+
);
|
|
468
|
+
});
|
|
469
|
+
}
|
|
361
470
|
function formatCharge(ch) {
|
|
362
471
|
return {
|
|
363
472
|
id: ch.stripe_id,
|
|
@@ -387,7 +496,8 @@ function chargeRoutes({ app, store }) {
|
|
|
387
496
|
};
|
|
388
497
|
app.get("/v1/charges/:id", (c) => {
|
|
389
498
|
const charge = ss.charges.findOneBy("stripe_id", c.req.param("id"));
|
|
390
|
-
if (!charge)
|
|
499
|
+
if (!charge)
|
|
500
|
+
return stripeError(c, 404, "invalid_request_error", `No such charge: '${c.req.param("id")}'`, "resource_missing");
|
|
391
501
|
const expand = parseExpand(c);
|
|
392
502
|
const result = applyExpand(formatCharge(charge), expand, expandResolvers);
|
|
393
503
|
return c.json(result);
|
|
@@ -417,7 +527,8 @@ function productRoutes({ app, store, webhooks }) {
|
|
|
417
527
|
const ss = getStripeStore(store);
|
|
418
528
|
app.post("/v1/products", async (c) => {
|
|
419
529
|
const body = await parseStripeBody(c);
|
|
420
|
-
if (!body.name)
|
|
530
|
+
if (!body.name)
|
|
531
|
+
return stripeError(c, 400, "invalid_request_error", "Missing required param: name.", void 0, "name");
|
|
421
532
|
const product = ss.products.insert({
|
|
422
533
|
stripe_id: stripeId("prod"),
|
|
423
534
|
name: body.name,
|
|
@@ -435,7 +546,14 @@ function productRoutes({ app, store, webhooks }) {
|
|
|
435
546
|
});
|
|
436
547
|
app.get("/v1/products/:id", (c) => {
|
|
437
548
|
const product = ss.products.findOneBy("stripe_id", c.req.param("id"));
|
|
438
|
-
if (!product)
|
|
549
|
+
if (!product)
|
|
550
|
+
return stripeError(
|
|
551
|
+
c,
|
|
552
|
+
404,
|
|
553
|
+
"invalid_request_error",
|
|
554
|
+
`No such product: '${c.req.param("id")}'`,
|
|
555
|
+
"resource_missing"
|
|
556
|
+
);
|
|
439
557
|
return c.json(formatProduct(product));
|
|
440
558
|
});
|
|
441
559
|
app.get("/v1/products", (c) => {
|
|
@@ -460,7 +578,14 @@ function formatPrice(p) {
|
|
|
460
578
|
};
|
|
461
579
|
}
|
|
462
580
|
function formatProduct2(p) {
|
|
463
|
-
return {
|
|
581
|
+
return {
|
|
582
|
+
id: p.stripe_id,
|
|
583
|
+
object: "product",
|
|
584
|
+
name: p.name,
|
|
585
|
+
active: p.active,
|
|
586
|
+
created: toUnixTimestamp(p.created_at),
|
|
587
|
+
livemode: false
|
|
588
|
+
};
|
|
464
589
|
}
|
|
465
590
|
function priceRoutes({ app, store, webhooks }) {
|
|
466
591
|
const ss = getStripeStore(store);
|
|
@@ -473,10 +598,24 @@ function priceRoutes({ app, store, webhooks }) {
|
|
|
473
598
|
app.post("/v1/prices", async (c) => {
|
|
474
599
|
const body = await parseStripeBody(c);
|
|
475
600
|
if (!body.currency || !body.product) {
|
|
476
|
-
return stripeError(
|
|
601
|
+
return stripeError(
|
|
602
|
+
c,
|
|
603
|
+
400,
|
|
604
|
+
"invalid_request_error",
|
|
605
|
+
"Missing required param: currency and product are required.",
|
|
606
|
+
void 0,
|
|
607
|
+
"currency"
|
|
608
|
+
);
|
|
477
609
|
}
|
|
478
610
|
if (!ss.products.findOneBy("stripe_id", body.product)) {
|
|
479
|
-
return stripeError(
|
|
611
|
+
return stripeError(
|
|
612
|
+
c,
|
|
613
|
+
400,
|
|
614
|
+
"invalid_request_error",
|
|
615
|
+
`No such product: '${body.product}'`,
|
|
616
|
+
"resource_missing",
|
|
617
|
+
"product"
|
|
618
|
+
);
|
|
480
619
|
}
|
|
481
620
|
const price = ss.prices.insert({
|
|
482
621
|
stripe_id: stripeId("price"),
|
|
@@ -497,7 +636,8 @@ function priceRoutes({ app, store, webhooks }) {
|
|
|
497
636
|
});
|
|
498
637
|
app.get("/v1/prices/:id", (c) => {
|
|
499
638
|
const price = ss.prices.findOneBy("stripe_id", c.req.param("id"));
|
|
500
|
-
if (!price)
|
|
639
|
+
if (!price)
|
|
640
|
+
return stripeError(c, 404, "invalid_request_error", `No such price: '${c.req.param("id")}'`, "resource_missing");
|
|
501
641
|
const expand = parseExpand(c);
|
|
502
642
|
const result = applyExpand(formatPrice(price), expand, expandResolvers);
|
|
503
643
|
return c.json(result);
|
|
@@ -526,6 +666,7 @@ var FONTS = {
|
|
|
526
666
|
"geist-sans.woff2": readFileSync(join(__dirname, "fonts", "geist-sans.woff2")),
|
|
527
667
|
"GeistPixel-Square.woff2": readFileSync(join(__dirname, "fonts", "GeistPixel-Square.woff2"))
|
|
528
668
|
};
|
|
669
|
+
var FAVICON = readFileSync(join(__dirname, "fonts", "favicon.ico"));
|
|
529
670
|
function escapeHtml(s) {
|
|
530
671
|
return s.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
531
672
|
}
|
|
@@ -677,6 +818,132 @@ body{
|
|
|
677
818
|
.app-link-name{font-weight:600;font-size:.875rem;color:#33ff00;}
|
|
678
819
|
.app-link-scopes{font-size:.6875rem;color:#1a8c00;margin-top:1px;}
|
|
679
820
|
.empty{color:#1a8c00;text-align:center;padding:28px 0;font-size:.875rem;}
|
|
821
|
+
|
|
822
|
+
.inspector-layout{max-width:960px;margin:0 auto;padding:28px 20px;}
|
|
823
|
+
.inspector-tabs{display:flex;gap:4px;margin-bottom:20px;}
|
|
824
|
+
.inspector-tabs a{
|
|
825
|
+
padding:7px 16px;border-radius:6px;text-decoration:none;
|
|
826
|
+
font-size:.8125rem;color:#1a8c00;border:1px solid transparent;
|
|
827
|
+
transition:color .15s,border-color .15s;
|
|
828
|
+
}
|
|
829
|
+
.inspector-tabs a:hover{color:#33ff00;}
|
|
830
|
+
.inspector-tabs a.active{color:#33ff00;font-weight:600;border-color:#0a3300;background:#0a3300;}
|
|
831
|
+
.inspector-section{margin-bottom:24px;}
|
|
832
|
+
.inspector-section h2{
|
|
833
|
+
font-family:'Geist Pixel',monospace;
|
|
834
|
+
font-size:1rem;font-weight:600;color:#33ff00;margin-bottom:10px;
|
|
835
|
+
}
|
|
836
|
+
.inspector-section h3{
|
|
837
|
+
font-family:'Geist Pixel',monospace;
|
|
838
|
+
font-size:.875rem;font-weight:600;color:#1a8c00;margin:16px 0 8px;
|
|
839
|
+
}
|
|
840
|
+
.inspector-table{width:100%;border-collapse:collapse;margin-bottom:12px;}
|
|
841
|
+
.inspector-table th,.inspector-table td{
|
|
842
|
+
text-align:left;padding:8px 12px;border-bottom:1px solid #0a3300;
|
|
843
|
+
font-size:.8125rem;
|
|
844
|
+
}
|
|
845
|
+
.inspector-table th{color:#1a8c00;font-weight:600;font-size:.75rem;text-transform:uppercase;letter-spacing:.04em;}
|
|
846
|
+
.inspector-table td{color:#33ff00;}
|
|
847
|
+
.inspector-table tbody tr{transition:background .1s;}
|
|
848
|
+
.inspector-table tbody tr:hover{background:#0a3300;}
|
|
849
|
+
.inspector-empty{color:#1a8c00;text-align:center;padding:20px 0;font-size:.8125rem;}
|
|
850
|
+
|
|
851
|
+
.checkout-layout{
|
|
852
|
+
display:flex;min-height:calc(100vh - 42px);
|
|
853
|
+
}
|
|
854
|
+
.checkout-summary{
|
|
855
|
+
flex:1;background:#020;padding:48px 40px 48px 10%;
|
|
856
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
857
|
+
border-right:1px solid #0a3300;
|
|
858
|
+
}
|
|
859
|
+
.checkout-form-side{
|
|
860
|
+
flex:1;background:#000;padding:48px 10% 48px 40px;
|
|
861
|
+
display:flex;flex-direction:column;justify-content:center;
|
|
862
|
+
}
|
|
863
|
+
.checkout-merchant{
|
|
864
|
+
display:flex;align-items:center;gap:10px;margin-bottom:6px;
|
|
865
|
+
}
|
|
866
|
+
.checkout-merchant-name{
|
|
867
|
+
font-family:'Geist Pixel',monospace;
|
|
868
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
869
|
+
}
|
|
870
|
+
.checkout-test-badge{
|
|
871
|
+
font-size:.625rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase;
|
|
872
|
+
background:#0a3300;color:#1a8c00;padding:2px 8px;border-radius:4px;
|
|
873
|
+
}
|
|
874
|
+
.checkout-total{
|
|
875
|
+
font-family:'Geist Pixel',monospace;
|
|
876
|
+
font-size:2rem;font-weight:700;color:#33ff00;margin:8px 0 28px;
|
|
877
|
+
}
|
|
878
|
+
.checkout-line-item{
|
|
879
|
+
display:flex;align-items:center;gap:14px;padding:14px 0;
|
|
880
|
+
border-bottom:1px solid #0a3300;
|
|
881
|
+
}
|
|
882
|
+
.checkout-line-item:first-child{border-top:1px solid #0a3300;}
|
|
883
|
+
.checkout-item-icon{
|
|
884
|
+
width:42px;height:42px;border-radius:6px;background:#0a3300;
|
|
885
|
+
display:flex;align-items:center;justify-content:center;flex-shrink:0;
|
|
886
|
+
font-family:'Geist Pixel',monospace;font-size:.875rem;font-weight:700;color:#116600;
|
|
887
|
+
}
|
|
888
|
+
.checkout-item-details{flex:1;min-width:0;}
|
|
889
|
+
.checkout-item-name{font-size:.875rem;font-weight:600;color:#33ff00;}
|
|
890
|
+
.checkout-item-qty{font-size:.75rem;color:#1a8c00;margin-top:2px;}
|
|
891
|
+
.checkout-item-price{
|
|
892
|
+
font-size:.875rem;font-weight:600;color:#33ff00;text-align:right;white-space:nowrap;
|
|
893
|
+
}
|
|
894
|
+
.checkout-item-unit{font-size:.6875rem;color:#1a8c00;text-align:right;margin-top:2px;}
|
|
895
|
+
.checkout-totals{margin-top:20px;}
|
|
896
|
+
.checkout-totals-row{
|
|
897
|
+
display:flex;justify-content:space-between;padding:6px 0;
|
|
898
|
+
font-size:.8125rem;color:#1a8c00;
|
|
899
|
+
}
|
|
900
|
+
.checkout-totals-row.total{
|
|
901
|
+
border-top:1px solid #0a3300;margin-top:8px;padding-top:14px;
|
|
902
|
+
font-size:.9375rem;font-weight:600;color:#33ff00;
|
|
903
|
+
}
|
|
904
|
+
.checkout-form-section{margin-bottom:24px;}
|
|
905
|
+
.checkout-form-label{
|
|
906
|
+
font-size:.8125rem;font-weight:600;color:#33ff00;margin-bottom:8px;display:block;
|
|
907
|
+
}
|
|
908
|
+
.checkout-input{
|
|
909
|
+
width:100%;padding:10px 12px;border:1px solid #0a3300;border-radius:6px;
|
|
910
|
+
background:#020;color:#33ff00;font:inherit;font-size:.875rem;
|
|
911
|
+
transition:border-color .15s;outline:none;
|
|
912
|
+
}
|
|
913
|
+
.checkout-input:focus{border-color:#33ff00;}
|
|
914
|
+
.checkout-input::placeholder{color:#116600;}
|
|
915
|
+
.checkout-card-box{
|
|
916
|
+
border:1px solid #0a3300;border-radius:6px;padding:14px;
|
|
917
|
+
background:#020;
|
|
918
|
+
}
|
|
919
|
+
.checkout-card-row{
|
|
920
|
+
display:flex;gap:12px;margin-top:10px;
|
|
921
|
+
}
|
|
922
|
+
.checkout-card-row .checkout-input{flex:1;}
|
|
923
|
+
.checkout-sim-note{
|
|
924
|
+
font-size:.6875rem;color:#1a8c00;margin-top:10px;text-align:center;
|
|
925
|
+
font-style:italic;
|
|
926
|
+
}
|
|
927
|
+
.checkout-pay-btn{
|
|
928
|
+
width:100%;padding:14px;border:none;border-radius:8px;
|
|
929
|
+
background:#33ff00;color:#000;font:inherit;font-size:.9375rem;font-weight:700;
|
|
930
|
+
cursor:pointer;transition:background .15s;
|
|
931
|
+
font-family:'Geist Pixel',monospace;
|
|
932
|
+
}
|
|
933
|
+
.checkout-pay-btn:hover{background:#44ff22;}
|
|
934
|
+
.checkout-cancel{
|
|
935
|
+
text-align:center;margin-top:14px;
|
|
936
|
+
}
|
|
937
|
+
.checkout-cancel a{
|
|
938
|
+
color:#1a8c00;text-decoration:none;font-size:.8125rem;
|
|
939
|
+
transition:color .15s;
|
|
940
|
+
}
|
|
941
|
+
.checkout-cancel a:hover{color:#33ff00;}
|
|
942
|
+
@media(max-width:768px){
|
|
943
|
+
.checkout-layout{flex-direction:column;}
|
|
944
|
+
.checkout-summary{padding:32px 20px;border-right:none;border-bottom:1px solid #0a3300;}
|
|
945
|
+
.checkout-form-side{padding:32px 20px;}
|
|
946
|
+
}
|
|
680
947
|
`;
|
|
681
948
|
var POWERED_BY = `<div class="powered-by">Powered by <a href="https://emulate.dev" target="_blank" rel="noopener">emulate</a></div>`;
|
|
682
949
|
function emuBar(service) {
|
|
@@ -696,6 +963,7 @@ function head(title) {
|
|
|
696
963
|
<head>
|
|
697
964
|
<meta charset="utf-8"/>
|
|
698
965
|
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
|
966
|
+
<link rel="icon" href="/_emulate/favicon.ico"/>
|
|
699
967
|
<title>${escapeHtml(title)} | emulate</title>
|
|
700
968
|
<style>${CSS}</style>
|
|
701
969
|
</head>`;
|
|
@@ -714,6 +982,72 @@ ${emuBar(service)}
|
|
|
714
982
|
${POWERED_BY}
|
|
715
983
|
</body></html>`;
|
|
716
984
|
}
|
|
985
|
+
function renderCheckoutPage(opts, service) {
|
|
986
|
+
const fmt = (cents, cur) => `$${(cents / 100).toFixed(2)} ${cur.toUpperCase()}`;
|
|
987
|
+
const fmtShort = (cents) => `$${(cents / 100).toFixed(2)}`;
|
|
988
|
+
const itemsHtml = opts.lineItems.length > 0 ? opts.lineItems.map((li) => {
|
|
989
|
+
const initial = li.name.charAt(0).toUpperCase();
|
|
990
|
+
const unitNote = li.quantity > 1 ? `<div class="checkout-item-unit">${fmtShort(li.unitPrice)} each</div>` : "";
|
|
991
|
+
return `<div class="checkout-line-item">
|
|
992
|
+
<div class="checkout-item-icon">${escapeHtml(initial)}</div>
|
|
993
|
+
<div class="checkout-item-details">
|
|
994
|
+
<div class="checkout-item-name">${escapeHtml(li.name)}</div>
|
|
995
|
+
<div class="checkout-item-qty">Qty ${li.quantity}</div>
|
|
996
|
+
</div>
|
|
997
|
+
<div>
|
|
998
|
+
<div class="checkout-item-price">${fmtShort(li.totalPrice)}</div>
|
|
999
|
+
${unitNote}
|
|
1000
|
+
</div>
|
|
1001
|
+
</div>`;
|
|
1002
|
+
}).join("") : '<p class="empty">No line items</p>';
|
|
1003
|
+
const totalsHtml = `<div class="checkout-totals">
|
|
1004
|
+
<div class="checkout-totals-row">
|
|
1005
|
+
<span>Subtotal</span><span>${fmtShort(opts.subtotal)}</span>
|
|
1006
|
+
</div>
|
|
1007
|
+
<div class="checkout-totals-row total">
|
|
1008
|
+
<span>Total due</span><span>${fmt(opts.total, opts.currency)}</span>
|
|
1009
|
+
</div>
|
|
1010
|
+
</div>`;
|
|
1011
|
+
const cancelHtml = opts.cancelUrl ? `<div class="checkout-cancel"><a href="${escapeAttr(opts.cancelUrl)}">Cancel</a></div>` : "";
|
|
1012
|
+
const merchant = opts.merchantName ? escapeHtml(opts.merchantName) : "Checkout";
|
|
1013
|
+
return `${head("Checkout")}
|
|
1014
|
+
<body>
|
|
1015
|
+
${emuBar(service)}
|
|
1016
|
+
<div class="checkout-layout">
|
|
1017
|
+
<div class="checkout-summary">
|
|
1018
|
+
<div class="checkout-merchant">
|
|
1019
|
+
<span class="checkout-merchant-name">${merchant}</span>
|
|
1020
|
+
<span class="checkout-test-badge">Test Mode</span>
|
|
1021
|
+
</div>
|
|
1022
|
+
<div class="checkout-total">${fmtShort(opts.total)}</div>
|
|
1023
|
+
${itemsHtml}
|
|
1024
|
+
${totalsHtml}
|
|
1025
|
+
</div>
|
|
1026
|
+
<div class="checkout-form-side">
|
|
1027
|
+
<form method="post" action="/checkout/${escapeAttr(opts.sessionId)}/complete">
|
|
1028
|
+
<div class="checkout-form-section">
|
|
1029
|
+
<label class="checkout-form-label">Email</label>
|
|
1030
|
+
<input type="email" name="email" class="checkout-input" placeholder="you@example.com"/>
|
|
1031
|
+
</div>
|
|
1032
|
+
<div class="checkout-form-section">
|
|
1033
|
+
<label class="checkout-form-label">Card information</label>
|
|
1034
|
+
<div class="checkout-card-box">
|
|
1035
|
+
<input type="text" class="checkout-input" placeholder="1234 1234 1234 1234" disabled/>
|
|
1036
|
+
<div class="checkout-card-row">
|
|
1037
|
+
<input type="text" class="checkout-input" placeholder="MM / YY" disabled/>
|
|
1038
|
+
<input type="text" class="checkout-input" placeholder="CVC" disabled/>
|
|
1039
|
+
</div>
|
|
1040
|
+
</div>
|
|
1041
|
+
<div class="checkout-sim-note">Card fields are simulated. Payment will be auto-approved.</div>
|
|
1042
|
+
</div>
|
|
1043
|
+
<button type="submit" class="checkout-pay-btn">Pay ${fmtShort(opts.total)}</button>
|
|
1044
|
+
</form>
|
|
1045
|
+
${cancelHtml}
|
|
1046
|
+
</div>
|
|
1047
|
+
</div>
|
|
1048
|
+
${POWERED_BY}
|
|
1049
|
+
</body></html>`;
|
|
1050
|
+
}
|
|
717
1051
|
var SERVICE_LABEL = "Stripe";
|
|
718
1052
|
function formatSession(s, baseUrl) {
|
|
719
1053
|
return {
|
|
@@ -735,9 +1069,17 @@ function checkoutSessionRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
735
1069
|
const ss = getStripeStore(store);
|
|
736
1070
|
app.post("/v1/checkout/sessions", async (c) => {
|
|
737
1071
|
const body = await parseStripeBody(c);
|
|
738
|
-
if (!body.mode)
|
|
1072
|
+
if (!body.mode)
|
|
1073
|
+
return stripeError(c, 400, "invalid_request_error", "Missing required param: mode.", void 0, "mode");
|
|
739
1074
|
if (body.customer && !ss.customers.findOneBy("stripe_id", body.customer)) {
|
|
740
|
-
return stripeError(
|
|
1075
|
+
return stripeError(
|
|
1076
|
+
c,
|
|
1077
|
+
400,
|
|
1078
|
+
"invalid_request_error",
|
|
1079
|
+
`No such customer: '${body.customer}'`,
|
|
1080
|
+
"resource_missing",
|
|
1081
|
+
"customer"
|
|
1082
|
+
);
|
|
741
1083
|
}
|
|
742
1084
|
const lineItems = [];
|
|
743
1085
|
if (body.line_items) {
|
|
@@ -747,17 +1089,45 @@ function checkoutSessionRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
747
1089
|
for (let i = 0; i < body.line_items.length; i++) {
|
|
748
1090
|
const li = body.line_items[i];
|
|
749
1091
|
if (!li || typeof li !== "object") {
|
|
750
|
-
return stripeError(
|
|
1092
|
+
return stripeError(
|
|
1093
|
+
c,
|
|
1094
|
+
400,
|
|
1095
|
+
"invalid_request_error",
|
|
1096
|
+
`Invalid line_items[${i}]: must be an object.`,
|
|
1097
|
+
void 0,
|
|
1098
|
+
`line_items[${i}]`
|
|
1099
|
+
);
|
|
751
1100
|
}
|
|
752
1101
|
if (!li.price || typeof li.price !== "string") {
|
|
753
|
-
return stripeError(
|
|
1102
|
+
return stripeError(
|
|
1103
|
+
c,
|
|
1104
|
+
400,
|
|
1105
|
+
"invalid_request_error",
|
|
1106
|
+
`Missing required param: line_items[${i}][price].`,
|
|
1107
|
+
void 0,
|
|
1108
|
+
`line_items[${i}][price]`
|
|
1109
|
+
);
|
|
754
1110
|
}
|
|
755
1111
|
if (!ss.prices.findOneBy("stripe_id", li.price)) {
|
|
756
|
-
return stripeError(
|
|
1112
|
+
return stripeError(
|
|
1113
|
+
c,
|
|
1114
|
+
400,
|
|
1115
|
+
"invalid_request_error",
|
|
1116
|
+
`No such price: '${li.price}'`,
|
|
1117
|
+
"resource_missing",
|
|
1118
|
+
`line_items[${i}][price]`
|
|
1119
|
+
);
|
|
757
1120
|
}
|
|
758
1121
|
const qty = typeof li.quantity === "number" ? li.quantity : parseInt(li.quantity, 10);
|
|
759
1122
|
if (!Number.isFinite(qty) || qty < 1) {
|
|
760
|
-
return stripeError(
|
|
1123
|
+
return stripeError(
|
|
1124
|
+
c,
|
|
1125
|
+
400,
|
|
1126
|
+
"invalid_request_error",
|
|
1127
|
+
`Invalid line_items[${i}][quantity]: must be a positive integer.`,
|
|
1128
|
+
void 0,
|
|
1129
|
+
`line_items[${i}][quantity]`
|
|
1130
|
+
);
|
|
761
1131
|
}
|
|
762
1132
|
lineItems.push({ price: li.price, quantity: qty });
|
|
763
1133
|
}
|
|
@@ -777,14 +1147,34 @@ function checkoutSessionRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
777
1147
|
});
|
|
778
1148
|
app.get("/v1/checkout/sessions/:id", (c) => {
|
|
779
1149
|
const session = ss.checkoutSessions.findOneBy("stripe_id", c.req.param("id"));
|
|
780
|
-
if (!session)
|
|
1150
|
+
if (!session)
|
|
1151
|
+
return stripeError(
|
|
1152
|
+
c,
|
|
1153
|
+
404,
|
|
1154
|
+
"invalid_request_error",
|
|
1155
|
+
`No such checkout session: '${c.req.param("id")}'`,
|
|
1156
|
+
"resource_missing"
|
|
1157
|
+
);
|
|
781
1158
|
return c.json(formatSession(session, baseUrl));
|
|
782
1159
|
});
|
|
783
1160
|
app.post("/v1/checkout/sessions/:id/expire", async (c) => {
|
|
784
1161
|
const session = ss.checkoutSessions.findOneBy("stripe_id", c.req.param("id"));
|
|
785
|
-
if (!session)
|
|
1162
|
+
if (!session)
|
|
1163
|
+
return stripeError(
|
|
1164
|
+
c,
|
|
1165
|
+
404,
|
|
1166
|
+
"invalid_request_error",
|
|
1167
|
+
`No such checkout session: '${c.req.param("id")}'`,
|
|
1168
|
+
"resource_missing"
|
|
1169
|
+
);
|
|
786
1170
|
if (session.status !== "open") {
|
|
787
|
-
return stripeError(
|
|
1171
|
+
return stripeError(
|
|
1172
|
+
c,
|
|
1173
|
+
400,
|
|
1174
|
+
"invalid_request_error",
|
|
1175
|
+
"Only open sessions can be expired.",
|
|
1176
|
+
"checkout_session_not_open"
|
|
1177
|
+
);
|
|
788
1178
|
}
|
|
789
1179
|
const updated = ss.checkoutSessions.update(session.id, { status: "expired" });
|
|
790
1180
|
await webhooks.dispatch(
|
|
@@ -808,35 +1198,53 @@ function checkoutSessionRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
808
1198
|
app.get("/checkout/:id", (c) => {
|
|
809
1199
|
const session = ss.checkoutSessions.findOneBy("stripe_id", c.req.param("id"));
|
|
810
1200
|
if (!session) {
|
|
811
|
-
return c.html(
|
|
1201
|
+
return c.html(
|
|
1202
|
+
renderCardPage(
|
|
1203
|
+
"Session Not Found",
|
|
1204
|
+
"This checkout session does not exist.",
|
|
1205
|
+
'<p class="empty">The session ID is invalid or has been removed.</p>',
|
|
1206
|
+
SERVICE_LABEL
|
|
1207
|
+
),
|
|
1208
|
+
404
|
|
1209
|
+
);
|
|
812
1210
|
}
|
|
813
1211
|
if (session.status !== "open") {
|
|
814
|
-
return c.html(
|
|
1212
|
+
return c.html(
|
|
1213
|
+
renderCardPage(
|
|
1214
|
+
"Session Expired",
|
|
1215
|
+
"This checkout session is no longer available.",
|
|
1216
|
+
`<p class="empty">Status: ${escapeHtml(session.status)}</p>`,
|
|
1217
|
+
SERVICE_LABEL
|
|
1218
|
+
)
|
|
1219
|
+
);
|
|
815
1220
|
}
|
|
816
|
-
const
|
|
1221
|
+
const lineItems = session.line_items.map((li) => {
|
|
817
1222
|
const priceObj = ss.prices.findOneBy("stripe_id", li.price);
|
|
818
1223
|
const product = priceObj ? ss.products.findOneBy("stripe_id", priceObj.product_id) : null;
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
1224
|
+
const unitPrice = priceObj?.unit_amount ?? 0;
|
|
1225
|
+
return {
|
|
1226
|
+
name: product?.name ?? li.price,
|
|
1227
|
+
quantity: li.quantity,
|
|
1228
|
+
unitPrice,
|
|
1229
|
+
totalPrice: unitPrice * li.quantity,
|
|
1230
|
+
currency: priceObj?.currency ?? "usd"
|
|
1231
|
+
};
|
|
1232
|
+
});
|
|
1233
|
+
const subtotal = lineItems.reduce((sum, li) => sum + li.totalPrice, 0);
|
|
1234
|
+
const currency = lineItems.length > 0 ? lineItems[0].currency : "usd";
|
|
1235
|
+
return c.html(
|
|
1236
|
+
renderCheckoutPage(
|
|
1237
|
+
{
|
|
1238
|
+
lineItems,
|
|
1239
|
+
subtotal,
|
|
1240
|
+
total: subtotal,
|
|
1241
|
+
currency,
|
|
1242
|
+
sessionId: session.stripe_id,
|
|
1243
|
+
cancelUrl: session.cancel_url
|
|
1244
|
+
},
|
|
1245
|
+
SERVICE_LABEL
|
|
1246
|
+
)
|
|
1247
|
+
);
|
|
840
1248
|
});
|
|
841
1249
|
app.post("/checkout/:id/complete", async (c) => {
|
|
842
1250
|
const session = ss.checkoutSessions.findOneBy("stripe_id", c.req.param("id"));
|
|
@@ -851,9 +1259,47 @@ function checkoutSessionRoutes({ app, store, webhooks, baseUrl }) {
|
|
|
851
1259
|
"stripe"
|
|
852
1260
|
);
|
|
853
1261
|
if (session.success_url) {
|
|
854
|
-
|
|
1262
|
+
const url = session.success_url.replace("{CHECKOUT_SESSION_ID}", updated.stripe_id);
|
|
1263
|
+
return c.redirect(url);
|
|
855
1264
|
}
|
|
856
|
-
return c.html(
|
|
1265
|
+
return c.html(
|
|
1266
|
+
renderCardPage(
|
|
1267
|
+
"Payment Complete",
|
|
1268
|
+
"Your payment was successful.",
|
|
1269
|
+
'<p class="empty check">Payment received</p>',
|
|
1270
|
+
SERVICE_LABEL
|
|
1271
|
+
)
|
|
1272
|
+
);
|
|
1273
|
+
});
|
|
1274
|
+
}
|
|
1275
|
+
function customerSessionRoutes({ app, store }) {
|
|
1276
|
+
const ss = getStripeStore(store);
|
|
1277
|
+
app.post("/v1/customer_sessions", async (c) => {
|
|
1278
|
+
const body = await parseStripeBody(c);
|
|
1279
|
+
if (!body.customer)
|
|
1280
|
+
return stripeError(c, 400, "invalid_request_error", "Missing required param: customer.", void 0, "customer");
|
|
1281
|
+
const customer = ss.customers.findOneBy("stripe_id", body.customer);
|
|
1282
|
+
if (!customer)
|
|
1283
|
+
return stripeError(
|
|
1284
|
+
c,
|
|
1285
|
+
400,
|
|
1286
|
+
"invalid_request_error",
|
|
1287
|
+
`No such customer: '${body.customer}'`,
|
|
1288
|
+
"resource_missing",
|
|
1289
|
+
"customer"
|
|
1290
|
+
);
|
|
1291
|
+
return c.json(
|
|
1292
|
+
{
|
|
1293
|
+
object: "customer_session",
|
|
1294
|
+
client_secret: stripeId("cuss_secret"),
|
|
1295
|
+
components: body.components ?? {},
|
|
1296
|
+
created: Math.floor(Date.now() / 1e3),
|
|
1297
|
+
customer: customer.stripe_id,
|
|
1298
|
+
expires_at: Math.floor(Date.now() / 1e3) + 1800,
|
|
1299
|
+
livemode: false
|
|
1300
|
+
},
|
|
1301
|
+
200
|
|
1302
|
+
);
|
|
857
1303
|
});
|
|
858
1304
|
}
|
|
859
1305
|
function seedDefaults(store, _baseUrl) {
|
|
@@ -866,7 +1312,7 @@ function seedDefaults(store, _baseUrl) {
|
|
|
866
1312
|
metadata: {}
|
|
867
1313
|
});
|
|
868
1314
|
}
|
|
869
|
-
function seedFromConfig(store, _baseUrl, config) {
|
|
1315
|
+
function seedFromConfig(store, _baseUrl, config, webhooks) {
|
|
870
1316
|
const ss = getStripeStore(store);
|
|
871
1317
|
if (config.customers) {
|
|
872
1318
|
for (const c of config.customers) {
|
|
@@ -875,7 +1321,7 @@ function seedFromConfig(store, _baseUrl, config) {
|
|
|
875
1321
|
if (existing) continue;
|
|
876
1322
|
}
|
|
877
1323
|
ss.customers.insert({
|
|
878
|
-
stripe_id: stripeId("cus"),
|
|
1324
|
+
stripe_id: c.id ?? stripeId("cus"),
|
|
879
1325
|
email: c.email ?? null,
|
|
880
1326
|
name: c.name ?? null,
|
|
881
1327
|
description: c.description ?? null,
|
|
@@ -886,7 +1332,7 @@ function seedFromConfig(store, _baseUrl, config) {
|
|
|
886
1332
|
if (config.products) {
|
|
887
1333
|
for (const p of config.products) {
|
|
888
1334
|
const product = ss.products.insert({
|
|
889
|
-
stripe_id: stripeId("prod"),
|
|
1335
|
+
stripe_id: p.id ?? stripeId("prod"),
|
|
890
1336
|
name: p.name,
|
|
891
1337
|
description: p.description ?? null,
|
|
892
1338
|
active: true,
|
|
@@ -895,7 +1341,7 @@ function seedFromConfig(store, _baseUrl, config) {
|
|
|
895
1341
|
const matchingPrices = config.prices?.filter((pr) => pr.product_name === p.name) ?? [];
|
|
896
1342
|
for (const pr of matchingPrices) {
|
|
897
1343
|
ss.prices.insert({
|
|
898
|
-
stripe_id: stripeId("price"),
|
|
1344
|
+
stripe_id: pr.id ?? stripeId("price"),
|
|
899
1345
|
product_id: product.stripe_id,
|
|
900
1346
|
currency: pr.currency.toLowerCase(),
|
|
901
1347
|
unit_amount: pr.unit_amount,
|
|
@@ -906,17 +1352,30 @@ function seedFromConfig(store, _baseUrl, config) {
|
|
|
906
1352
|
}
|
|
907
1353
|
}
|
|
908
1354
|
}
|
|
1355
|
+
if (config.webhooks && webhooks) {
|
|
1356
|
+
for (const wh of config.webhooks) {
|
|
1357
|
+
webhooks.register({
|
|
1358
|
+
url: wh.url,
|
|
1359
|
+
events: wh.events,
|
|
1360
|
+
active: true,
|
|
1361
|
+
secret: wh.secret,
|
|
1362
|
+
owner: "stripe"
|
|
1363
|
+
});
|
|
1364
|
+
}
|
|
1365
|
+
}
|
|
909
1366
|
}
|
|
910
1367
|
var stripePlugin = {
|
|
911
1368
|
name: "stripe",
|
|
912
1369
|
register(app, store, webhooks, baseUrl, tokenMap) {
|
|
913
1370
|
const ctx = { app, store, webhooks, baseUrl, tokenMap };
|
|
914
1371
|
customerRoutes(ctx);
|
|
1372
|
+
paymentMethodRoutes(ctx);
|
|
915
1373
|
paymentIntentRoutes(ctx);
|
|
916
1374
|
chargeRoutes(ctx);
|
|
917
1375
|
productRoutes(ctx);
|
|
918
1376
|
priceRoutes(ctx);
|
|
919
1377
|
checkoutSessionRoutes(ctx);
|
|
1378
|
+
customerSessionRoutes(ctx);
|
|
920
1379
|
},
|
|
921
1380
|
seed(store, baseUrl) {
|
|
922
1381
|
seedDefaults(store, baseUrl);
|
|
@@ -929,4 +1388,4 @@ export {
|
|
|
929
1388
|
seedFromConfig,
|
|
930
1389
|
stripePlugin
|
|
931
1390
|
};
|
|
932
|
-
//# sourceMappingURL=dist-
|
|
1391
|
+
//# sourceMappingURL=dist-NJJLJT2N.js.map
|