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