@develemit/commerce-server 0.3.0 → 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 +51 -8
- package/dist/index.d.ts +464 -2
- package/dist/index.js +1045 -144
- package/dist/index.js.map +1 -1
- package/docs/admin.md +30 -2
- package/docs/payments.md +29 -1
- package/migrations/0007_discounts.sql +40 -0
- package/migrations/meta/0007_snapshot.json +1028 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -51,6 +51,11 @@ const sweeper = startHoldSweeper(db, { intervalMs: 60_000 });
|
|
|
51
51
|
app.addHook('onClose', async () => sweeper.stop());
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
+
`resolvePayment(process.env)` picks Stripe or the fake gateway from the
|
|
55
|
+
environment (it refuses the fake gateway when `NODE_ENV=production` and
|
|
56
|
+
half-configured Stripe keys), and `checkoutUrls(webUrl)` builds the `urls`
|
|
57
|
+
option; use them instead of hand-writing both.
|
|
58
|
+
|
|
54
59
|
`payment` and `urls` go together. Omit both (`commercePlugin({ db, currency })`)
|
|
55
60
|
for a catalog-only mount: the checkout, webhook, and order routes aren't
|
|
56
61
|
registered, so `/checkout` returns 404.
|
|
@@ -105,6 +110,28 @@ matters.
|
|
|
105
110
|
The package never reads `process.env`; pass everything in. Load products with
|
|
106
111
|
`seedProducts(db, products)`, an idempotent upsert on `slug`.
|
|
107
112
|
|
|
113
|
+
## Order emails
|
|
114
|
+
|
|
115
|
+
`orderEmailLines(order, { locale, labels })` builds the money and address
|
|
116
|
+
pieces of an order email from the `OrderDetail` a hook receives. You write the
|
|
117
|
+
layout and copy.
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
onOrderPaid: async (order) => {
|
|
121
|
+
const lines = orderEmailLines(order);
|
|
122
|
+
await mailer.send({
|
|
123
|
+
to: order.email,
|
|
124
|
+
text: `${lines.text.items}\n${lines.text.totals}\n\n${lines.text.address}`,
|
|
125
|
+
html: `<table>${lines.html.items}${lines.html.totals}</table>${lines.html.address}`,
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
The result also has structured `items`, `subtotal`, `discount` (absent when
|
|
131
|
+
no discount applied), `shipping`, `total` and `address` (absent for pickup).
|
|
132
|
+
HTML output is `<tr>` / `<p>` fragments with `& < > " '` escaped. Override
|
|
133
|
+
copy with `labels`.
|
|
134
|
+
|
|
108
135
|
## Running a shop
|
|
109
136
|
|
|
110
137
|
The order lifecycle, from the host's side:
|
|
@@ -161,20 +188,36 @@ app root before `commercePlugin`, so its `onSend` runs after the catalog's.
|
|
|
161
188
|
Webhook raw-body parsing is request-side and unaffected by compression.
|
|
162
189
|
- **Retries:** refunds require an `Idempotency-Key`; reuse it when retrying so
|
|
163
190
|
a refund can't be issued twice.
|
|
191
|
+
- **Rate limiting:** `POST /checkout/discount/preview` lets anyone test codes.
|
|
192
|
+
Rate-limit it (and `POST /checkout`) at the host or CDN; the kit doesn't.
|
|
164
193
|
- Admin routes: see [Admin API](docs/admin.md).
|
|
165
194
|
|
|
166
195
|
## Routes
|
|
167
196
|
|
|
168
197
|
Relative to the host's prefix:
|
|
169
198
|
|
|
170
|
-
| Route
|
|
171
|
-
|
|
|
172
|
-
| `GET /catalog/products`
|
|
173
|
-
| `GET /catalog/products/:slug`
|
|
174
|
-
| `GET /catalog/categories`
|
|
175
|
-
| `POST /checkout`
|
|
176
|
-
| `POST /
|
|
177
|
-
| `
|
|
199
|
+
| Route | Purpose |
|
|
200
|
+
| --------------------------------- | --------------------------------------------------------------- |
|
|
201
|
+
| `GET /catalog/products` | Active products (`?category=`, `?featured=true`) |
|
|
202
|
+
| `GET /catalog/products/:slug` | One product, or 404 `PRODUCT_NOT_FOUND` |
|
|
203
|
+
| `GET /catalog/categories` | Active product counts per category |
|
|
204
|
+
| `POST /checkout` | `{ items: [{ productId, quantity }] }` → `{ url }`, or 409 |
|
|
205
|
+
| `POST /checkout/discount/preview` | `{ code, items }` → discount preview, or 422 `DISCOUNT_INVALID` |
|
|
206
|
+
| `POST /orders/webhooks/stripe` | Stripe webhook (raw body, `stripe-signature` header) |
|
|
207
|
+
| `GET /orders/session/:sessionId` | `orderSummarySchema` for the success page |
|
|
208
|
+
|
|
209
|
+
## Discounts
|
|
210
|
+
|
|
211
|
+
`POST /checkout/discount/preview` takes `{ code, items }` and answers
|
|
212
|
+
`{ code, discountCents, subtotalCents, currency }`, or 422
|
|
213
|
+
`{ error: 'DISCOUNT_INVALID', reason }`. The subtotal is priced from the
|
|
214
|
+
database over the items that are currently purchasable in the shop currency;
|
|
215
|
+
unavailable items are left out, matching what checkout would charge. Rules run
|
|
216
|
+
in order and the first failure wins: not found, inactive, not started, expired,
|
|
217
|
+
currency (fixed codes), minimum subtotal, redemptions exhausted. Percent codes
|
|
218
|
+
round down; fixed codes never exceed the subtotal; shipping is never
|
|
219
|
+
discounted. An inactive code is reported as `not_found` so drafts don't leak.
|
|
220
|
+
Responses are `Cache-Control: no-store`.
|
|
178
221
|
|
|
179
222
|
## How checkout stays honest
|
|
180
223
|
|
package/dist/index.d.ts
CHANGED
|
@@ -560,6 +560,40 @@ declare const commerceSchema: {
|
|
|
560
560
|
identity: undefined;
|
|
561
561
|
generated: undefined;
|
|
562
562
|
}, {}, {}>;
|
|
563
|
+
discountCents: drizzle_orm_pg_core.PgColumn<{
|
|
564
|
+
name: "discount_cents";
|
|
565
|
+
tableName: "commerce_orders";
|
|
566
|
+
dataType: "number";
|
|
567
|
+
columnType: "PgInteger";
|
|
568
|
+
data: number;
|
|
569
|
+
driverParam: string | number;
|
|
570
|
+
notNull: true;
|
|
571
|
+
hasDefault: true;
|
|
572
|
+
isPrimaryKey: false;
|
|
573
|
+
isAutoincrement: false;
|
|
574
|
+
hasRuntimeDefault: false;
|
|
575
|
+
enumValues: undefined;
|
|
576
|
+
baseColumn: never;
|
|
577
|
+
identity: undefined;
|
|
578
|
+
generated: undefined;
|
|
579
|
+
}, {}, {}>;
|
|
580
|
+
discountCode: drizzle_orm_pg_core.PgColumn<{
|
|
581
|
+
name: "discount_code";
|
|
582
|
+
tableName: "commerce_orders";
|
|
583
|
+
dataType: "string";
|
|
584
|
+
columnType: "PgText";
|
|
585
|
+
data: string;
|
|
586
|
+
driverParam: string;
|
|
587
|
+
notNull: false;
|
|
588
|
+
hasDefault: false;
|
|
589
|
+
isPrimaryKey: false;
|
|
590
|
+
isAutoincrement: false;
|
|
591
|
+
hasRuntimeDefault: false;
|
|
592
|
+
enumValues: [string, ...string[]];
|
|
593
|
+
baseColumn: never;
|
|
594
|
+
identity: undefined;
|
|
595
|
+
generated: undefined;
|
|
596
|
+
}, {}, {}>;
|
|
563
597
|
shippingCents: drizzle_orm_pg_core.PgColumn<{
|
|
564
598
|
name: "shipping_cents";
|
|
565
599
|
tableName: "commerce_orders";
|
|
@@ -1238,6 +1272,360 @@ declare const commerceSchema: {
|
|
|
1238
1272
|
};
|
|
1239
1273
|
dialect: "pg";
|
|
1240
1274
|
}>;
|
|
1275
|
+
discounts: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1276
|
+
name: "commerce_discounts";
|
|
1277
|
+
schema: undefined;
|
|
1278
|
+
columns: {
|
|
1279
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1280
|
+
name: "id";
|
|
1281
|
+
tableName: "commerce_discounts";
|
|
1282
|
+
dataType: "string";
|
|
1283
|
+
columnType: "PgUUID";
|
|
1284
|
+
data: string;
|
|
1285
|
+
driverParam: string;
|
|
1286
|
+
notNull: true;
|
|
1287
|
+
hasDefault: true;
|
|
1288
|
+
isPrimaryKey: true;
|
|
1289
|
+
isAutoincrement: false;
|
|
1290
|
+
hasRuntimeDefault: false;
|
|
1291
|
+
enumValues: undefined;
|
|
1292
|
+
baseColumn: never;
|
|
1293
|
+
identity: undefined;
|
|
1294
|
+
generated: undefined;
|
|
1295
|
+
}, {}, {}>;
|
|
1296
|
+
code: drizzle_orm_pg_core.PgColumn<{
|
|
1297
|
+
name: "code";
|
|
1298
|
+
tableName: "commerce_discounts";
|
|
1299
|
+
dataType: "string";
|
|
1300
|
+
columnType: "PgText";
|
|
1301
|
+
data: string;
|
|
1302
|
+
driverParam: string;
|
|
1303
|
+
notNull: true;
|
|
1304
|
+
hasDefault: false;
|
|
1305
|
+
isPrimaryKey: false;
|
|
1306
|
+
isAutoincrement: false;
|
|
1307
|
+
hasRuntimeDefault: false;
|
|
1308
|
+
enumValues: [string, ...string[]];
|
|
1309
|
+
baseColumn: never;
|
|
1310
|
+
identity: undefined;
|
|
1311
|
+
generated: undefined;
|
|
1312
|
+
}, {}, {}>;
|
|
1313
|
+
type: drizzle_orm_pg_core.PgColumn<{
|
|
1314
|
+
name: "type";
|
|
1315
|
+
tableName: "commerce_discounts";
|
|
1316
|
+
dataType: "string";
|
|
1317
|
+
columnType: "PgText";
|
|
1318
|
+
data: "fixed" | "percent";
|
|
1319
|
+
driverParam: string;
|
|
1320
|
+
notNull: true;
|
|
1321
|
+
hasDefault: false;
|
|
1322
|
+
isPrimaryKey: false;
|
|
1323
|
+
isAutoincrement: false;
|
|
1324
|
+
hasRuntimeDefault: false;
|
|
1325
|
+
enumValues: ["percent", "fixed"];
|
|
1326
|
+
baseColumn: never;
|
|
1327
|
+
identity: undefined;
|
|
1328
|
+
generated: undefined;
|
|
1329
|
+
}, {}, {}>;
|
|
1330
|
+
percentOff: drizzle_orm_pg_core.PgColumn<{
|
|
1331
|
+
name: "percent_off";
|
|
1332
|
+
tableName: "commerce_discounts";
|
|
1333
|
+
dataType: "number";
|
|
1334
|
+
columnType: "PgInteger";
|
|
1335
|
+
data: number;
|
|
1336
|
+
driverParam: string | number;
|
|
1337
|
+
notNull: false;
|
|
1338
|
+
hasDefault: false;
|
|
1339
|
+
isPrimaryKey: false;
|
|
1340
|
+
isAutoincrement: false;
|
|
1341
|
+
hasRuntimeDefault: false;
|
|
1342
|
+
enumValues: undefined;
|
|
1343
|
+
baseColumn: never;
|
|
1344
|
+
identity: undefined;
|
|
1345
|
+
generated: undefined;
|
|
1346
|
+
}, {}, {}>;
|
|
1347
|
+
amountOffCents: drizzle_orm_pg_core.PgColumn<{
|
|
1348
|
+
name: "amount_off_cents";
|
|
1349
|
+
tableName: "commerce_discounts";
|
|
1350
|
+
dataType: "number";
|
|
1351
|
+
columnType: "PgInteger";
|
|
1352
|
+
data: number;
|
|
1353
|
+
driverParam: string | number;
|
|
1354
|
+
notNull: false;
|
|
1355
|
+
hasDefault: false;
|
|
1356
|
+
isPrimaryKey: false;
|
|
1357
|
+
isAutoincrement: false;
|
|
1358
|
+
hasRuntimeDefault: false;
|
|
1359
|
+
enumValues: undefined;
|
|
1360
|
+
baseColumn: never;
|
|
1361
|
+
identity: undefined;
|
|
1362
|
+
generated: undefined;
|
|
1363
|
+
}, {}, {}>;
|
|
1364
|
+
currency: drizzle_orm_pg_core.PgColumn<{
|
|
1365
|
+
name: "currency";
|
|
1366
|
+
tableName: "commerce_discounts";
|
|
1367
|
+
dataType: "string";
|
|
1368
|
+
columnType: "PgText";
|
|
1369
|
+
data: string;
|
|
1370
|
+
driverParam: string;
|
|
1371
|
+
notNull: false;
|
|
1372
|
+
hasDefault: false;
|
|
1373
|
+
isPrimaryKey: false;
|
|
1374
|
+
isAutoincrement: false;
|
|
1375
|
+
hasRuntimeDefault: false;
|
|
1376
|
+
enumValues: [string, ...string[]];
|
|
1377
|
+
baseColumn: never;
|
|
1378
|
+
identity: undefined;
|
|
1379
|
+
generated: undefined;
|
|
1380
|
+
}, {}, {}>;
|
|
1381
|
+
minSubtotalCents: drizzle_orm_pg_core.PgColumn<{
|
|
1382
|
+
name: "min_subtotal_cents";
|
|
1383
|
+
tableName: "commerce_discounts";
|
|
1384
|
+
dataType: "number";
|
|
1385
|
+
columnType: "PgInteger";
|
|
1386
|
+
data: number;
|
|
1387
|
+
driverParam: string | number;
|
|
1388
|
+
notNull: false;
|
|
1389
|
+
hasDefault: false;
|
|
1390
|
+
isPrimaryKey: false;
|
|
1391
|
+
isAutoincrement: false;
|
|
1392
|
+
hasRuntimeDefault: false;
|
|
1393
|
+
enumValues: undefined;
|
|
1394
|
+
baseColumn: never;
|
|
1395
|
+
identity: undefined;
|
|
1396
|
+
generated: undefined;
|
|
1397
|
+
}, {}, {}>;
|
|
1398
|
+
startsAt: drizzle_orm_pg_core.PgColumn<{
|
|
1399
|
+
name: "starts_at";
|
|
1400
|
+
tableName: "commerce_discounts";
|
|
1401
|
+
dataType: "date";
|
|
1402
|
+
columnType: "PgTimestamp";
|
|
1403
|
+
data: Date;
|
|
1404
|
+
driverParam: string;
|
|
1405
|
+
notNull: false;
|
|
1406
|
+
hasDefault: false;
|
|
1407
|
+
isPrimaryKey: false;
|
|
1408
|
+
isAutoincrement: false;
|
|
1409
|
+
hasRuntimeDefault: false;
|
|
1410
|
+
enumValues: undefined;
|
|
1411
|
+
baseColumn: never;
|
|
1412
|
+
identity: undefined;
|
|
1413
|
+
generated: undefined;
|
|
1414
|
+
}, {}, {}>;
|
|
1415
|
+
endsAt: drizzle_orm_pg_core.PgColumn<{
|
|
1416
|
+
name: "ends_at";
|
|
1417
|
+
tableName: "commerce_discounts";
|
|
1418
|
+
dataType: "date";
|
|
1419
|
+
columnType: "PgTimestamp";
|
|
1420
|
+
data: Date;
|
|
1421
|
+
driverParam: string;
|
|
1422
|
+
notNull: false;
|
|
1423
|
+
hasDefault: false;
|
|
1424
|
+
isPrimaryKey: false;
|
|
1425
|
+
isAutoincrement: false;
|
|
1426
|
+
hasRuntimeDefault: false;
|
|
1427
|
+
enumValues: undefined;
|
|
1428
|
+
baseColumn: never;
|
|
1429
|
+
identity: undefined;
|
|
1430
|
+
generated: undefined;
|
|
1431
|
+
}, {}, {}>;
|
|
1432
|
+
maxRedemptions: drizzle_orm_pg_core.PgColumn<{
|
|
1433
|
+
name: "max_redemptions";
|
|
1434
|
+
tableName: "commerce_discounts";
|
|
1435
|
+
dataType: "number";
|
|
1436
|
+
columnType: "PgInteger";
|
|
1437
|
+
data: number;
|
|
1438
|
+
driverParam: string | number;
|
|
1439
|
+
notNull: false;
|
|
1440
|
+
hasDefault: false;
|
|
1441
|
+
isPrimaryKey: false;
|
|
1442
|
+
isAutoincrement: false;
|
|
1443
|
+
hasRuntimeDefault: false;
|
|
1444
|
+
enumValues: undefined;
|
|
1445
|
+
baseColumn: never;
|
|
1446
|
+
identity: undefined;
|
|
1447
|
+
generated: undefined;
|
|
1448
|
+
}, {}, {}>;
|
|
1449
|
+
active: drizzle_orm_pg_core.PgColumn<{
|
|
1450
|
+
name: "active";
|
|
1451
|
+
tableName: "commerce_discounts";
|
|
1452
|
+
dataType: "boolean";
|
|
1453
|
+
columnType: "PgBoolean";
|
|
1454
|
+
data: boolean;
|
|
1455
|
+
driverParam: boolean;
|
|
1456
|
+
notNull: true;
|
|
1457
|
+
hasDefault: true;
|
|
1458
|
+
isPrimaryKey: false;
|
|
1459
|
+
isAutoincrement: false;
|
|
1460
|
+
hasRuntimeDefault: false;
|
|
1461
|
+
enumValues: undefined;
|
|
1462
|
+
baseColumn: never;
|
|
1463
|
+
identity: undefined;
|
|
1464
|
+
generated: undefined;
|
|
1465
|
+
}, {}, {}>;
|
|
1466
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1467
|
+
name: "created_at";
|
|
1468
|
+
tableName: "commerce_discounts";
|
|
1469
|
+
dataType: "date";
|
|
1470
|
+
columnType: "PgTimestamp";
|
|
1471
|
+
data: Date;
|
|
1472
|
+
driverParam: string;
|
|
1473
|
+
notNull: true;
|
|
1474
|
+
hasDefault: true;
|
|
1475
|
+
isPrimaryKey: false;
|
|
1476
|
+
isAutoincrement: false;
|
|
1477
|
+
hasRuntimeDefault: false;
|
|
1478
|
+
enumValues: undefined;
|
|
1479
|
+
baseColumn: never;
|
|
1480
|
+
identity: undefined;
|
|
1481
|
+
generated: undefined;
|
|
1482
|
+
}, {}, {}>;
|
|
1483
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1484
|
+
name: "updated_at";
|
|
1485
|
+
tableName: "commerce_discounts";
|
|
1486
|
+
dataType: "date";
|
|
1487
|
+
columnType: "PgTimestamp";
|
|
1488
|
+
data: Date;
|
|
1489
|
+
driverParam: string;
|
|
1490
|
+
notNull: true;
|
|
1491
|
+
hasDefault: true;
|
|
1492
|
+
isPrimaryKey: false;
|
|
1493
|
+
isAutoincrement: false;
|
|
1494
|
+
hasRuntimeDefault: false;
|
|
1495
|
+
enumValues: undefined;
|
|
1496
|
+
baseColumn: never;
|
|
1497
|
+
identity: undefined;
|
|
1498
|
+
generated: undefined;
|
|
1499
|
+
}, {}, {}>;
|
|
1500
|
+
};
|
|
1501
|
+
dialect: "pg";
|
|
1502
|
+
}>;
|
|
1503
|
+
discountRedemptions: drizzle_orm_pg_core.PgTableWithColumns<{
|
|
1504
|
+
name: "commerce_discount_redemptions";
|
|
1505
|
+
schema: undefined;
|
|
1506
|
+
columns: {
|
|
1507
|
+
id: drizzle_orm_pg_core.PgColumn<{
|
|
1508
|
+
name: "id";
|
|
1509
|
+
tableName: "commerce_discount_redemptions";
|
|
1510
|
+
dataType: "string";
|
|
1511
|
+
columnType: "PgUUID";
|
|
1512
|
+
data: string;
|
|
1513
|
+
driverParam: string;
|
|
1514
|
+
notNull: true;
|
|
1515
|
+
hasDefault: true;
|
|
1516
|
+
isPrimaryKey: true;
|
|
1517
|
+
isAutoincrement: false;
|
|
1518
|
+
hasRuntimeDefault: false;
|
|
1519
|
+
enumValues: undefined;
|
|
1520
|
+
baseColumn: never;
|
|
1521
|
+
identity: undefined;
|
|
1522
|
+
generated: undefined;
|
|
1523
|
+
}, {}, {}>;
|
|
1524
|
+
discountId: drizzle_orm_pg_core.PgColumn<{
|
|
1525
|
+
name: "discount_id";
|
|
1526
|
+
tableName: "commerce_discount_redemptions";
|
|
1527
|
+
dataType: "string";
|
|
1528
|
+
columnType: "PgUUID";
|
|
1529
|
+
data: string;
|
|
1530
|
+
driverParam: string;
|
|
1531
|
+
notNull: true;
|
|
1532
|
+
hasDefault: false;
|
|
1533
|
+
isPrimaryKey: false;
|
|
1534
|
+
isAutoincrement: false;
|
|
1535
|
+
hasRuntimeDefault: false;
|
|
1536
|
+
enumValues: undefined;
|
|
1537
|
+
baseColumn: never;
|
|
1538
|
+
identity: undefined;
|
|
1539
|
+
generated: undefined;
|
|
1540
|
+
}, {}, {}>;
|
|
1541
|
+
orderId: drizzle_orm_pg_core.PgColumn<{
|
|
1542
|
+
name: "order_id";
|
|
1543
|
+
tableName: "commerce_discount_redemptions";
|
|
1544
|
+
dataType: "string";
|
|
1545
|
+
columnType: "PgUUID";
|
|
1546
|
+
data: string;
|
|
1547
|
+
driverParam: string;
|
|
1548
|
+
notNull: true;
|
|
1549
|
+
hasDefault: false;
|
|
1550
|
+
isPrimaryKey: false;
|
|
1551
|
+
isAutoincrement: false;
|
|
1552
|
+
hasRuntimeDefault: false;
|
|
1553
|
+
enumValues: undefined;
|
|
1554
|
+
baseColumn: never;
|
|
1555
|
+
identity: undefined;
|
|
1556
|
+
generated: undefined;
|
|
1557
|
+
}, {}, {}>;
|
|
1558
|
+
status: drizzle_orm_pg_core.PgColumn<{
|
|
1559
|
+
name: "status";
|
|
1560
|
+
tableName: "commerce_discount_redemptions";
|
|
1561
|
+
dataType: "string";
|
|
1562
|
+
columnType: "PgText";
|
|
1563
|
+
data: "released" | "committed" | "reserved";
|
|
1564
|
+
driverParam: string;
|
|
1565
|
+
notNull: true;
|
|
1566
|
+
hasDefault: true;
|
|
1567
|
+
isPrimaryKey: false;
|
|
1568
|
+
isAutoincrement: false;
|
|
1569
|
+
hasRuntimeDefault: false;
|
|
1570
|
+
enumValues: ["reserved", "committed", "released"];
|
|
1571
|
+
baseColumn: never;
|
|
1572
|
+
identity: undefined;
|
|
1573
|
+
generated: undefined;
|
|
1574
|
+
}, {}, {}>;
|
|
1575
|
+
amountCents: drizzle_orm_pg_core.PgColumn<{
|
|
1576
|
+
name: "amount_cents";
|
|
1577
|
+
tableName: "commerce_discount_redemptions";
|
|
1578
|
+
dataType: "number";
|
|
1579
|
+
columnType: "PgInteger";
|
|
1580
|
+
data: number;
|
|
1581
|
+
driverParam: string | number;
|
|
1582
|
+
notNull: true;
|
|
1583
|
+
hasDefault: false;
|
|
1584
|
+
isPrimaryKey: false;
|
|
1585
|
+
isAutoincrement: false;
|
|
1586
|
+
hasRuntimeDefault: false;
|
|
1587
|
+
enumValues: undefined;
|
|
1588
|
+
baseColumn: never;
|
|
1589
|
+
identity: undefined;
|
|
1590
|
+
generated: undefined;
|
|
1591
|
+
}, {}, {}>;
|
|
1592
|
+
createdAt: drizzle_orm_pg_core.PgColumn<{
|
|
1593
|
+
name: "created_at";
|
|
1594
|
+
tableName: "commerce_discount_redemptions";
|
|
1595
|
+
dataType: "date";
|
|
1596
|
+
columnType: "PgTimestamp";
|
|
1597
|
+
data: Date;
|
|
1598
|
+
driverParam: string;
|
|
1599
|
+
notNull: true;
|
|
1600
|
+
hasDefault: true;
|
|
1601
|
+
isPrimaryKey: false;
|
|
1602
|
+
isAutoincrement: false;
|
|
1603
|
+
hasRuntimeDefault: false;
|
|
1604
|
+
enumValues: undefined;
|
|
1605
|
+
baseColumn: never;
|
|
1606
|
+
identity: undefined;
|
|
1607
|
+
generated: undefined;
|
|
1608
|
+
}, {}, {}>;
|
|
1609
|
+
updatedAt: drizzle_orm_pg_core.PgColumn<{
|
|
1610
|
+
name: "updated_at";
|
|
1611
|
+
tableName: "commerce_discount_redemptions";
|
|
1612
|
+
dataType: "date";
|
|
1613
|
+
columnType: "PgTimestamp";
|
|
1614
|
+
data: Date;
|
|
1615
|
+
driverParam: string;
|
|
1616
|
+
notNull: true;
|
|
1617
|
+
hasDefault: true;
|
|
1618
|
+
isPrimaryKey: false;
|
|
1619
|
+
isAutoincrement: false;
|
|
1620
|
+
hasRuntimeDefault: false;
|
|
1621
|
+
enumValues: undefined;
|
|
1622
|
+
baseColumn: never;
|
|
1623
|
+
identity: undefined;
|
|
1624
|
+
generated: undefined;
|
|
1625
|
+
}, {}, {}>;
|
|
1626
|
+
};
|
|
1627
|
+
dialect: "pg";
|
|
1628
|
+
}>;
|
|
1241
1629
|
};
|
|
1242
1630
|
type CommerceSchema = typeof commerceSchema;
|
|
1243
1631
|
|
|
@@ -1290,6 +1678,11 @@ interface CreateCheckoutSessionInput {
|
|
|
1290
1678
|
shippingCountries: string[];
|
|
1291
1679
|
shippingRates: ShippingRateOption[];
|
|
1292
1680
|
expiresAt: Date;
|
|
1681
|
+
discount?: CheckoutDiscount;
|
|
1682
|
+
}
|
|
1683
|
+
interface CheckoutDiscount {
|
|
1684
|
+
code: string;
|
|
1685
|
+
amountCents: number;
|
|
1293
1686
|
}
|
|
1294
1687
|
interface CheckoutSession {
|
|
1295
1688
|
id: string;
|
|
@@ -1387,12 +1780,17 @@ interface CheckoutOptions {
|
|
|
1387
1780
|
urls: CheckoutUrls;
|
|
1388
1781
|
shippingCountries?: string[];
|
|
1389
1782
|
hooks?: OrderHooks;
|
|
1783
|
+
devCheckout?: boolean | DevCheckoutSetting;
|
|
1784
|
+
}
|
|
1785
|
+
interface DevCheckoutSetting {
|
|
1786
|
+
apiUrl?: string;
|
|
1390
1787
|
}
|
|
1391
1788
|
interface CatalogOnlyOptions {
|
|
1392
1789
|
payment?: undefined;
|
|
1393
1790
|
urls?: undefined;
|
|
1394
1791
|
shippingCountries?: undefined;
|
|
1395
1792
|
hooks?: undefined;
|
|
1793
|
+
devCheckout?: undefined;
|
|
1396
1794
|
}
|
|
1397
1795
|
type CommercePluginOptions = {
|
|
1398
1796
|
db: CommerceDb;
|
|
@@ -1427,6 +1825,8 @@ interface SignedWebhook {
|
|
|
1427
1825
|
signature: string;
|
|
1428
1826
|
}
|
|
1429
1827
|
interface FakeGateway extends PaymentGateway {
|
|
1828
|
+
readonly kind: 'fake';
|
|
1829
|
+
useSessionUrl(build: (sessionId: string) => string): void;
|
|
1430
1830
|
readonly sessions: (CreateCheckoutSessionInput & {
|
|
1431
1831
|
id: string;
|
|
1432
1832
|
})[];
|
|
@@ -1453,6 +1853,7 @@ interface FakeGatewayOptions {
|
|
|
1453
1853
|
secret?: string;
|
|
1454
1854
|
}
|
|
1455
1855
|
declare function createFakeGateway({ secret, }?: FakeGatewayOptions): FakeGateway;
|
|
1856
|
+
declare function isFakeGateway(gateway: PaymentGateway): gateway is FakeGateway;
|
|
1456
1857
|
|
|
1457
1858
|
interface HoldSweeperOptions {
|
|
1458
1859
|
intervalMs?: number;
|
|
@@ -1463,6 +1864,42 @@ interface HoldSweeper {
|
|
|
1463
1864
|
}
|
|
1464
1865
|
declare function startHoldSweeper(db: CommerceDb, { intervalMs, onError }?: HoldSweeperOptions): HoldSweeper;
|
|
1465
1866
|
|
|
1867
|
+
interface EmailLine {
|
|
1868
|
+
label: string;
|
|
1869
|
+
amount: string;
|
|
1870
|
+
}
|
|
1871
|
+
interface OrderEmailLabels {
|
|
1872
|
+
subtotal: string;
|
|
1873
|
+
discount: (code: string | null) => string;
|
|
1874
|
+
shipping: (label: string | null) => string;
|
|
1875
|
+
total: string;
|
|
1876
|
+
}
|
|
1877
|
+
interface OrderEmailLinesOptions {
|
|
1878
|
+
locale?: string;
|
|
1879
|
+
labels?: Partial<OrderEmailLabels>;
|
|
1880
|
+
}
|
|
1881
|
+
interface OrderEmailLinesText {
|
|
1882
|
+
items: string;
|
|
1883
|
+
totals: string;
|
|
1884
|
+
address: string;
|
|
1885
|
+
}
|
|
1886
|
+
interface OrderEmailLinesHtml {
|
|
1887
|
+
items: string;
|
|
1888
|
+
totals: string;
|
|
1889
|
+
address: string;
|
|
1890
|
+
}
|
|
1891
|
+
interface OrderEmailLines {
|
|
1892
|
+
items: EmailLine[];
|
|
1893
|
+
subtotal: EmailLine;
|
|
1894
|
+
discount?: EmailLine;
|
|
1895
|
+
shipping: EmailLine;
|
|
1896
|
+
total: EmailLine;
|
|
1897
|
+
address?: string[];
|
|
1898
|
+
text: OrderEmailLinesText;
|
|
1899
|
+
html: OrderEmailLinesHtml;
|
|
1900
|
+
}
|
|
1901
|
+
declare function orderEmailLines(order: OrderDetail, options?: OrderEmailLinesOptions): OrderEmailLines;
|
|
1902
|
+
|
|
1466
1903
|
declare function runCommerceMigrations(db: NodePgDatabase<any>): Promise<void>;
|
|
1467
1904
|
|
|
1468
1905
|
interface SeedProduct {
|
|
@@ -1503,5 +1940,30 @@ interface MemoryStorage extends FileStorage {
|
|
|
1503
1940
|
}
|
|
1504
1941
|
declare function createMemoryStorage(baseUrl?: string): MemoryStorage;
|
|
1505
1942
|
|
|
1506
|
-
|
|
1507
|
-
|
|
1943
|
+
interface DiskStorageOptions {
|
|
1944
|
+
dir: string;
|
|
1945
|
+
publicUrl: string;
|
|
1946
|
+
}
|
|
1947
|
+
interface StoredFileStream {
|
|
1948
|
+
stream: Readable;
|
|
1949
|
+
contentType: string | undefined;
|
|
1950
|
+
size: number;
|
|
1951
|
+
}
|
|
1952
|
+
declare function createDiskStorage(options: DiskStorageOptions): FileStorage;
|
|
1953
|
+
declare function openStoredFile(dir: string, key: string): Promise<StoredFileStream | null>;
|
|
1954
|
+
|
|
1955
|
+
interface PaymentEnv {
|
|
1956
|
+
NODE_ENV?: string;
|
|
1957
|
+
PAYMENT_GATEWAY?: string;
|
|
1958
|
+
STRIPE_SECRET_KEY?: string;
|
|
1959
|
+
STRIPE_WEBHOOK_SECRET?: string;
|
|
1960
|
+
}
|
|
1961
|
+
declare function resolvePayment(env?: PaymentEnv): PaymentGateway;
|
|
1962
|
+
interface CheckoutUrlPaths {
|
|
1963
|
+
successPath?: string;
|
|
1964
|
+
cancelPath?: string;
|
|
1965
|
+
}
|
|
1966
|
+
declare function checkoutUrls(webUrl: string, { successPath, cancelPath, }?: CheckoutUrlPaths): CheckoutUrls;
|
|
1967
|
+
|
|
1968
|
+
export { ProductNotFoundError, SESSION_ID_PLACEHOLDER, WebhookSignatureError, catalogPlugin, checkoutUrls, commercePlugin, commerceSchema, createDiskStorage, createFakeGateway, createMemoryStorage, createStripeGateway, isFakeGateway, openStoredFile, orderEmailLines, ordersPlugin, resolvePayment, runCommerceMigrations, seedProducts, seedShippingRates, startHoldSweeper };
|
|
1969
|
+
export type { AdminOptions, CatalogCacheOptions, CatalogPluginOptions, CategoryLabels, CheckoutDiscount, CheckoutLine, CheckoutSession, CheckoutUrlPaths, CheckoutUrls, ChosenShipping, CommerceDb, CommercePluginOptions, CommerceSchema, CreateCheckoutSessionInput, DevCheckoutSetting, DiskStorageOptions, EmailLine, FakeGateway, FakeGatewayOptions, FileStorage, GatewayRefund, HoldSweeper, HoldSweeperOptions, MemoryStorage, OrderEmailLabels, OrderEmailLines, OrderEmailLinesOptions, OrderHooks, OrdersPluginOptions, PaymentEnv, PaymentEvent, PaymentGateway, RefundInput, SeedProduct, SeedShippingRate, ShippingAddress, ShippingRateOption, SignedWebhook, StoredFile, StoredFileStream, StripeGatewayOptions };
|