@ikeboy003/cart 0.3.0 → 0.4.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/dist/engine.d.ts +16 -1
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +59 -4
- package/dist/engine.js.map +1 -1
- package/dist/server.d.ts +30 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -8
- package/dist/server.js.map +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/engine.ts +62 -4
- package/src/server.ts +48 -6
- package/src/types.ts +8 -0
package/dist/engine.d.ts
CHANGED
|
@@ -2,11 +2,13 @@ import type { CartItem, CartSnapshot, CreateCartOptions } from "./types.js";
|
|
|
2
2
|
export declare class CartEngine<TItem extends CartItem = CartItem> {
|
|
3
3
|
readonly namespace: string;
|
|
4
4
|
private lines;
|
|
5
|
-
private
|
|
5
|
+
private cartId;
|
|
6
|
+
private readonly mintId;
|
|
6
7
|
private readonly listeners;
|
|
7
8
|
private readonly storage;
|
|
8
9
|
private readonly sync?;
|
|
9
10
|
private readonly debounceMs;
|
|
11
|
+
private readonly ttlMs;
|
|
10
12
|
private flushTimer;
|
|
11
13
|
private hideHandler?;
|
|
12
14
|
/** Stable reference returned from getSnapshot until lines actually change. */
|
|
@@ -16,6 +18,8 @@ export declare class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
16
18
|
private loadId;
|
|
17
19
|
private loadLines;
|
|
18
20
|
private persistLocal;
|
|
21
|
+
/** True when a non-empty cart's last touch is older than the TTL (0 = disabled). */
|
|
22
|
+
private isExpired;
|
|
19
23
|
subscribe: (fn: () => void) => (() => void);
|
|
20
24
|
/** Stable identity between mutations — safe for `useSyncExternalStore`. */
|
|
21
25
|
getSnapshot: () => TItem[];
|
|
@@ -26,6 +30,17 @@ export declare class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
26
30
|
/** Set an exact quantity. `<= 0` removes the line. */
|
|
27
31
|
updateQuantity(id: string, quantity: number): void;
|
|
28
32
|
remove(id: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* CONSUME the cart: empty it AND retire its id, minting a fresh one for the next
|
|
35
|
+
* order. clear() is the checkout-success signal — at that point the cart's state has
|
|
36
|
+
* already MOVED into the durable order record (the checkout order_intent snapshot), so
|
|
37
|
+
* the cart is spent. Keeping the SAME id let a re-checkout reuse the same order_intent
|
|
38
|
+
* slot + the client's cached shipping quote, so several orders shared ONE frozen
|
|
39
|
+
* EasyPost shipment (the first bought the label; later orders' label keys 404'd). A
|
|
40
|
+
* fresh id ⇒ a fresh order_intent slot + a fresh quote per order. The retired id's
|
|
41
|
+
* durable cart row is orphaned-empty and never referenced again (the order lives in
|
|
42
|
+
* order_intents, not carts), so nothing is lost.
|
|
43
|
+
*/
|
|
29
44
|
clear(): void;
|
|
30
45
|
get items(): TItem[];
|
|
31
46
|
get count(): number;
|
package/dist/engine.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EAEZ,iBAAiB,EAClB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EAEZ,iBAAiB,EAClB,MAAM,YAAY,CAAC;AA0BpB,qBAAa,UAAU,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IACvD,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAE3B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAyB;IACnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiB;IACzC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAyB;IAC/C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,UAAU,CAA8C;IAChE,OAAO,CAAC,WAAW,CAAC,CAAa;IACjC,8EAA8E;IAC9E,OAAO,CAAC,WAAW,CAAe;gBAEtB,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC;IA0C1C,IAAI,EAAE,IAAI,MAAM,CAEf;IAED,OAAO,CAAC,MAAM;IAQd,OAAO,CAAC,SAAS;IAWjB,OAAO,CAAC,YAAY;IAMpB,oFAAoF;IACpF,OAAO,CAAC,SAAS;IASjB,SAAS,GAAI,IAAI,MAAM,IAAI,KAAG,CAAC,MAAM,IAAI,CAAC,CAGxC;IAEF,2EAA2E;IAC3E,WAAW,QAAO,KAAK,EAAE,CAAqB;IAE9C,OAAO,CAAC,IAAI;IAOZ,OAAO,CAAC,MAAM;IAOd,2EAA2E;IAC3E,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI;IActB,sDAAsD;IACtD,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAYlD,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI;IAKxB;;;;;;;;;;OAUG;IACH,KAAK,IAAI,IAAI;IA4Bb,IAAI,KAAK,IAAI,KAAK,EAAE,CAEnB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,aAAa,IAAI,MAAM,CAE1B;IAED,QAAQ,IAAI,YAAY,CAAC,KAAK,CAAC;IAW/B,+EAA+E;IACzE,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAc9B,OAAO,CAAC,YAAY;YASN,IAAI;IASlB;;;OAGG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B,sEAAsE;IACtE,OAAO,IAAI,IAAI;CAQhB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,EAC1D,IAAI,EAAE,iBAAiB,CAAC,KAAK,CAAC,GAC7B,UAAU,CAAC,KAAK,CAAC,CAEnB"}
|
package/dist/engine.js
CHANGED
|
@@ -5,6 +5,9 @@
|
|
|
5
5
|
// useSyncExternalStore, or otherwise) can bind to it.
|
|
6
6
|
const itemsKey = (ns) => `cart:${ns}:items`;
|
|
7
7
|
const idKey = (ns) => `cart:${ns}:id`;
|
|
8
|
+
/** Last-touched epoch ms — drives abandonment expiry (see `ttlMs`). */
|
|
9
|
+
const stampKey = (ns) => `cart:${ns}:touched`;
|
|
10
|
+
const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
8
11
|
function safeLocalStorage() {
|
|
9
12
|
try {
|
|
10
13
|
return typeof localStorage !== "undefined" ? localStorage : null;
|
|
@@ -47,9 +50,19 @@ export class CartEngine {
|
|
|
47
50
|
this.storage = opts.storage === undefined ? safeLocalStorage() : opts.storage;
|
|
48
51
|
this.sync = opts.sync;
|
|
49
52
|
this.debounceMs = opts.debounceMs ?? 400;
|
|
50
|
-
|
|
51
|
-
this.
|
|
53
|
+
this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
54
|
+
this.mintId = opts.newId ?? defaultNewId;
|
|
55
|
+
this.cartId = this.loadId(this.mintId);
|
|
52
56
|
this.lines = this.loadLines();
|
|
57
|
+
// Abandonment expiry: a non-empty cart untouched past the TTL is consumed on load —
|
|
58
|
+
// dropped + its id retired — so a returning shopper starts fresh instead of resuming a
|
|
59
|
+
// days-old cart or a checkout's frozen shipping quote. (Empty carts never expire.)
|
|
60
|
+
if (this.isExpired()) {
|
|
61
|
+
this.lines = [];
|
|
62
|
+
this.cartId = this.mintId();
|
|
63
|
+
this.storage?.setItem(idKey(this.namespace), this.cartId);
|
|
64
|
+
this.persistLocal(); // writes empty items + a fresh touch stamp under the new id
|
|
65
|
+
}
|
|
53
66
|
this.snapshotRef = this.lines;
|
|
54
67
|
// Hard-guarantee the durable copy lands before the tab goes away (close,
|
|
55
68
|
// navigate, mobile background). `visibilitychange→hidden` is the reliable
|
|
@@ -89,6 +102,16 @@ export class CartEngine {
|
|
|
89
102
|
}
|
|
90
103
|
persistLocal() {
|
|
91
104
|
this.storage?.setItem(itemsKey(this.namespace), JSON.stringify(this.lines));
|
|
105
|
+
// Touch on every write so abandonment is measured from the last real activity.
|
|
106
|
+
this.storage?.setItem(stampKey(this.namespace), String(Date.now()));
|
|
107
|
+
}
|
|
108
|
+
/** True when a non-empty cart's last touch is older than the TTL (0 = disabled). */
|
|
109
|
+
isExpired() {
|
|
110
|
+
if (this.ttlMs <= 0 || this.lines.length === 0)
|
|
111
|
+
return false;
|
|
112
|
+
const raw = this.storage?.getItem(stampKey(this.namespace));
|
|
113
|
+
const touched = raw ? Number(raw) : NaN;
|
|
114
|
+
return Number.isFinite(touched) && Date.now() - touched > this.ttlMs;
|
|
92
115
|
}
|
|
93
116
|
emit() {
|
|
94
117
|
this.snapshotRef = this.lines;
|
|
@@ -136,9 +159,41 @@ export class CartEngine {
|
|
|
136
159
|
if (next.length !== this.lines.length)
|
|
137
160
|
this.commit(next);
|
|
138
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* CONSUME the cart: empty it AND retire its id, minting a fresh one for the next
|
|
164
|
+
* order. clear() is the checkout-success signal — at that point the cart's state has
|
|
165
|
+
* already MOVED into the durable order record (the checkout order_intent snapshot), so
|
|
166
|
+
* the cart is spent. Keeping the SAME id let a re-checkout reuse the same order_intent
|
|
167
|
+
* slot + the client's cached shipping quote, so several orders shared ONE frozen
|
|
168
|
+
* EasyPost shipment (the first bought the label; later orders' label keys 404'd). A
|
|
169
|
+
* fresh id ⇒ a fresh order_intent slot + a fresh quote per order. The retired id's
|
|
170
|
+
* durable cart row is orphaned-empty and never referenced again (the order lives in
|
|
171
|
+
* order_intents, not carts), so nothing is lost.
|
|
172
|
+
*/
|
|
139
173
|
clear() {
|
|
140
|
-
|
|
141
|
-
|
|
174
|
+
const oldId = this.cartId;
|
|
175
|
+
this.lines = [];
|
|
176
|
+
this.persistLocal(); // empty local under the OLD id + fresh stamp
|
|
177
|
+
// Retire the OLD id's durable row explicitly. A debounced commit([]) would NOT do this:
|
|
178
|
+
// push() reads this.cartId lazily, so after the rotation below it would PUT empty under
|
|
179
|
+
// the NEW id and leave the old row populated (a phantom cart another device holding the
|
|
180
|
+
// old id could restore). So push empty to the captured old id directly, cancel any
|
|
181
|
+
// pending debounce, THEN rotate.
|
|
182
|
+
if (this.sync) {
|
|
183
|
+
void this.sync
|
|
184
|
+
.push({ id: oldId, namespace: this.namespace, items: [], updatedAt: Date.now() })
|
|
185
|
+
.catch(() => { }); // durable cleanup is best-effort; local state is already empty
|
|
186
|
+
}
|
|
187
|
+
if (this.flushTimer) {
|
|
188
|
+
clearTimeout(this.flushTimer);
|
|
189
|
+
this.flushTimer = null;
|
|
190
|
+
}
|
|
191
|
+
// Fresh identity for the next order — a new order_intent slot + a fresh quote.
|
|
192
|
+
const id = this.mintId();
|
|
193
|
+
this.cartId = id;
|
|
194
|
+
this.storage?.setItem(idKey(this.namespace), id);
|
|
195
|
+
this.persistLocal();
|
|
196
|
+
this.emit();
|
|
142
197
|
}
|
|
143
198
|
// ---- derived -----------------------------------------------------------
|
|
144
199
|
get items() {
|
package/dist/engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,2EAA2E;AAC3E,yEAAyE;AACzE,oEAAoE;AACpE,sDAAsD;AAStD,MAAM,QAAQ,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC;AACpD,MAAM,KAAK,GAAG,CAAC,EAAU,EAAE,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -34,7 +34,30 @@ export interface CreateCartStoreOptions {
|
|
|
34
34
|
export declare function createCartStore<TItem extends CartItem = CartItem>(opts?: CreateCartStoreOptions): Promise<DurableCartStore<TItem>>;
|
|
35
35
|
/** `order_intents` DDL — the immutable per-checkout order snapshot. `createOrderStore`
|
|
36
36
|
* self-applies it (idempotent), so no separate migration step. */
|
|
37
|
-
export declare const ORDER_INTENTS_SQL = "CREATE TABLE IF NOT EXISTS order_intents (\n cart_id TEXT PRIMARY KEY,\n site TEXT NOT NULL,\n items TEXT NOT NULL DEFAULT '[]',\n subtotal_cents INTEGER NOT NULL DEFAULT 0,\n customer_name TEXT,\n customer_email TEXT,\n customer_phone TEXT,\n created_at INTEGER\n)";
|
|
37
|
+
export declare const ORDER_INTENTS_SQL = "CREATE TABLE IF NOT EXISTS order_intents (\n cart_id TEXT PRIMARY KEY,\n site TEXT NOT NULL,\n items TEXT NOT NULL DEFAULT '[]',\n subtotal_cents INTEGER NOT NULL DEFAULT 0,\n customer_name TEXT,\n customer_email TEXT,\n customer_phone TEXT,\n fulfillment TEXT NOT NULL DEFAULT 'pickup',\n ship_to TEXT,\n shipping TEXT,\n created_at INTEGER\n)";
|
|
38
|
+
/** A shipping destination frozen into the snapshot (structural — the cart layer
|
|
39
|
+
* stays below @ikeboy003/checkout, so it doesn't import ShipTo). */
|
|
40
|
+
export interface SnapshotShipTo {
|
|
41
|
+
name?: string;
|
|
42
|
+
phone?: string;
|
|
43
|
+
street1?: string;
|
|
44
|
+
street2?: string;
|
|
45
|
+
city?: string;
|
|
46
|
+
state?: string;
|
|
47
|
+
postal?: string;
|
|
48
|
+
country?: string;
|
|
49
|
+
}
|
|
50
|
+
/** The chosen shipping rate frozen into the snapshot (structural — mirrors
|
|
51
|
+
* @ikeboy003/checkout's ShippingQuote without importing it). */
|
|
52
|
+
export interface SnapshotShipping {
|
|
53
|
+
rateId?: string;
|
|
54
|
+
shipmentId?: string;
|
|
55
|
+
amountCents?: number;
|
|
56
|
+
carrier?: string;
|
|
57
|
+
service?: string;
|
|
58
|
+
estDays?: number;
|
|
59
|
+
weightOz?: number;
|
|
60
|
+
}
|
|
38
61
|
/** A checkout snapshot: the cart's lines + the guest customer, frozen at PaymentIntent
|
|
39
62
|
* time. The payment webhook reads this (not the mutable cart) to build the order. */
|
|
40
63
|
export interface OrderSnapshot<TItem extends CartItem = CartItem> {
|
|
@@ -50,6 +73,12 @@ export interface OrderSnapshot<TItem extends CartItem = CartItem> {
|
|
|
50
73
|
email?: string;
|
|
51
74
|
phone?: string;
|
|
52
75
|
};
|
|
76
|
+
/** "pickup" | "shipment" | … — project-defined; frozen so the order records it. */
|
|
77
|
+
fulfillment?: string;
|
|
78
|
+
/** Ship-to address — only exists at checkout for a shipment, like the guest customer. */
|
|
79
|
+
shipTo?: SnapshotShipTo | null;
|
|
80
|
+
/** The chosen carrier rate (ids the fulfillment service buys the label by). */
|
|
81
|
+
shipping?: SnapshotShipping | null;
|
|
53
82
|
}
|
|
54
83
|
/** Writes {@link OrderSnapshot}s. One method — the snapshot is write-once-per-checkout. */
|
|
55
84
|
export interface OrderSnapshotStore<TItem extends CartItem = CartItem> {
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAEzD,wFAAwF;AACxF,MAAM,WAAW,gBAAgB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IACjE,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7D,KAAK,CAAC,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,kFAAkF;AAClF,MAAM,WAAW,MAAM;IACrB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;CACpC;AACD,MAAM,WAAW,UAAU;IACzB,IAAI,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,GAAG,UAAU,CAAC;IACvC,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IACxB,KAAK,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;CACzD;AAED,MAAM,MAAM,YAAY,GAAG,OAAO,GAAG,YAAY,CAAC;AAElD,mFAAmF;AACnF,eAAO,MAAM,eAAe,8QAQ1B,CAAC;AAEH,MAAM,WAAW,sBAAsB;IACrC,0FAA0F;IAC1F,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,6FAA6F;IAC7F,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,2FAA2F;IAC3F,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4ED;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ,EACrE,IAAI,GAAE,sBAA2B,GAChC,OAAO,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAUlC;AAUD;mEACmE;AACnE,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/server.js
CHANGED
|
@@ -116,6 +116,9 @@ export const ORDER_INTENTS_SQL = `CREATE TABLE IF NOT EXISTS order_intents (
|
|
|
116
116
|
customer_name TEXT,
|
|
117
117
|
customer_email TEXT,
|
|
118
118
|
customer_phone TEXT,
|
|
119
|
+
fulfillment TEXT NOT NULL DEFAULT 'pickup',
|
|
120
|
+
ship_to TEXT,
|
|
121
|
+
shipping TEXT,
|
|
119
122
|
created_at INTEGER
|
|
120
123
|
)`;
|
|
121
124
|
/** Σ priceCents × quantity over the cart lines — the order subtotal, frozen here so the
|
|
@@ -130,11 +133,12 @@ function d1OrderStore(d1) {
|
|
|
130
133
|
await ready;
|
|
131
134
|
await d1
|
|
132
135
|
.prepare(`INSERT INTO order_intents
|
|
133
|
-
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, created_at)
|
|
134
|
-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)
|
|
136
|
+
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, fulfillment, ship_to, shipping, created_at)
|
|
137
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
135
138
|
ON CONFLICT(cart_id) DO UPDATE SET
|
|
136
|
-
items=?3, subtotal_cents=?4, customer_name=?5, customer_email=?6, customer_phone=?7
|
|
137
|
-
|
|
139
|
+
items=?3, subtotal_cents=?4, customer_name=?5, customer_email=?6, customer_phone=?7,
|
|
140
|
+
fulfillment=?8, ship_to=?9, shipping=?10`)
|
|
141
|
+
.bind(s.cartId, s.site, JSON.stringify(s.items), lineSubtotalCents(s.items), s.customer?.name ?? "", s.customer?.email ?? "", s.customer?.phone ?? "", s.fulfillment ?? "pickup", s.shipTo ? JSON.stringify(s.shipTo) : null, s.shipping ? JSON.stringify(s.shipping) : null, Date.now())
|
|
138
142
|
.run();
|
|
139
143
|
},
|
|
140
144
|
};
|
|
@@ -152,14 +156,15 @@ async function sqliteOrderStore(path) {
|
|
|
152
156
|
const db = new DatabaseSync(path);
|
|
153
157
|
db.exec(ORDER_INTENTS_SQL);
|
|
154
158
|
const ins = db.prepare(`INSERT INTO order_intents
|
|
155
|
-
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, created_at)
|
|
156
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
159
|
+
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, fulfillment, ship_to, shipping, created_at)
|
|
160
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
157
161
|
ON CONFLICT(cart_id) DO UPDATE SET
|
|
158
162
|
items=excluded.items, subtotal_cents=excluded.subtotal_cents, customer_name=excluded.customer_name,
|
|
159
|
-
customer_email=excluded.customer_email, customer_phone=excluded.customer_phone
|
|
163
|
+
customer_email=excluded.customer_email, customer_phone=excluded.customer_phone,
|
|
164
|
+
fulfillment=excluded.fulfillment, ship_to=excluded.ship_to, shipping=excluded.shipping`);
|
|
160
165
|
return {
|
|
161
166
|
async save(s) {
|
|
162
|
-
ins.run(s.cartId, s.site, JSON.stringify(s.items), lineSubtotalCents(s.items), s.customer?.name ?? "", s.customer?.email ?? "", s.customer?.phone ?? "", Date.now());
|
|
167
|
+
ins.run(s.cartId, s.site, JSON.stringify(s.items), lineSubtotalCents(s.items), s.customer?.name ?? "", s.customer?.email ?? "", s.customer?.phone ?? "", s.fulfillment ?? "pickup", s.shipTo ? JSON.stringify(s.shipTo) : null, s.shipping ? JSON.stringify(s.shipping) : null, Date.now());
|
|
163
168
|
},
|
|
164
169
|
};
|
|
165
170
|
}
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -54,6 +54,14 @@ export interface CreateCartOptions<TItem extends CartItem = CartItem> {
|
|
|
54
54
|
sync?: CartSyncAdapter<TItem>;
|
|
55
55
|
/** Coalesce window for durable pushes (ms). Default 400. */
|
|
56
56
|
debounceMs?: number;
|
|
57
|
+
/**
|
|
58
|
+
* Abandonment TTL (ms). On load, a non-empty cart untouched for longer than this is
|
|
59
|
+
* CONSUMED — emptied + its id retired for a fresh one — so a returning shopper never
|
|
60
|
+
* resumes a stale cart (or a checkout's frozen shipping quote). Identity is the
|
|
61
|
+
* localStorage cart-id capability, so this is a client-side, per-browser check.
|
|
62
|
+
* Default 7 days. Set 0 to disable.
|
|
63
|
+
*/
|
|
64
|
+
ttlMs?: number;
|
|
57
65
|
/** Id minter. Default `crypto.randomUUID`. */
|
|
58
66
|
newId?: () => string;
|
|
59
67
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAC7D,0EAA0E;IAC1E,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAChE,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;CAC9D;AAED;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC;AAE7C,oEAAoE;AACpE,MAAM,WAAW,iBAAiB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAClE,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,kFAAkF;IAClF,IAAI,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiBA;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,yEAAyE;AACzE,MAAM,WAAW,YAAY,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAC7D,0EAA0E;IAC1E,EAAE,EAAE,MAAM,CAAC;IACX,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,mFAAmF;IACnF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,eAAe,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAChE,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;CAC9D;AAED;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,OAAO,GAAG,YAAY,CAAC;AAE7C,oEAAoE;AACpE,MAAM,WAAW,iBAAiB,CAAC,KAAK,SAAS,QAAQ,GAAG,QAAQ;IAClE,yEAAyE;IACzE,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,6EAA6E;IAC7E,OAAO,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACzB,kFAAkF;IAClF,IAAI,CAAC,EAAE,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,4DAA4D;IAC5D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8CAA8C;IAC9C,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;CACtB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ikeboy003/cart",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Headless cart primitive: local-first state + a configurable durable sync path. Framework-agnostic core, optional React binding. No POS/payment/store logic baked in.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
package/src/engine.ts
CHANGED
|
@@ -13,6 +13,9 @@ import type {
|
|
|
13
13
|
|
|
14
14
|
const itemsKey = (ns: string) => `cart:${ns}:items`;
|
|
15
15
|
const idKey = (ns: string) => `cart:${ns}:id`;
|
|
16
|
+
/** Last-touched epoch ms — drives abandonment expiry (see `ttlMs`). */
|
|
17
|
+
const stampKey = (ns: string) => `cart:${ns}:touched`;
|
|
18
|
+
const DEFAULT_TTL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days
|
|
16
19
|
|
|
17
20
|
function safeLocalStorage(): Storage | null {
|
|
18
21
|
try {
|
|
@@ -36,11 +39,13 @@ export class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
36
39
|
readonly namespace: string;
|
|
37
40
|
|
|
38
41
|
private lines: TItem[] = [];
|
|
39
|
-
private
|
|
42
|
+
private cartId: string;
|
|
43
|
+
private readonly mintId: () => string;
|
|
40
44
|
private readonly listeners = new Set<() => void>();
|
|
41
45
|
private readonly storage: Storage | null;
|
|
42
46
|
private readonly sync?: CartSyncAdapter<TItem>;
|
|
43
47
|
private readonly debounceMs: number;
|
|
48
|
+
private readonly ttlMs: number;
|
|
44
49
|
private flushTimer: ReturnType<typeof setTimeout> | null = null;
|
|
45
50
|
private hideHandler?: () => void;
|
|
46
51
|
/** Stable reference returned from getSnapshot until lines actually change. */
|
|
@@ -58,10 +63,20 @@ export class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
58
63
|
this.storage = opts.storage === undefined ? safeLocalStorage() : opts.storage;
|
|
59
64
|
this.sync = opts.sync;
|
|
60
65
|
this.debounceMs = opts.debounceMs ?? 400;
|
|
61
|
-
|
|
66
|
+
this.ttlMs = opts.ttlMs ?? DEFAULT_TTL_MS;
|
|
67
|
+
this.mintId = opts.newId ?? defaultNewId;
|
|
62
68
|
|
|
63
|
-
this.cartId = this.loadId(
|
|
69
|
+
this.cartId = this.loadId(this.mintId);
|
|
64
70
|
this.lines = this.loadLines();
|
|
71
|
+
// Abandonment expiry: a non-empty cart untouched past the TTL is consumed on load —
|
|
72
|
+
// dropped + its id retired — so a returning shopper starts fresh instead of resuming a
|
|
73
|
+
// days-old cart or a checkout's frozen shipping quote. (Empty carts never expire.)
|
|
74
|
+
if (this.isExpired()) {
|
|
75
|
+
this.lines = [];
|
|
76
|
+
this.cartId = this.mintId();
|
|
77
|
+
this.storage?.setItem(idKey(this.namespace), this.cartId);
|
|
78
|
+
this.persistLocal(); // writes empty items + a fresh touch stamp under the new id
|
|
79
|
+
}
|
|
65
80
|
this.snapshotRef = this.lines;
|
|
66
81
|
|
|
67
82
|
// Hard-guarantee the durable copy lands before the tab goes away (close,
|
|
@@ -103,6 +118,16 @@ export class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
103
118
|
|
|
104
119
|
private persistLocal(): void {
|
|
105
120
|
this.storage?.setItem(itemsKey(this.namespace), JSON.stringify(this.lines));
|
|
121
|
+
// Touch on every write so abandonment is measured from the last real activity.
|
|
122
|
+
this.storage?.setItem(stampKey(this.namespace), String(Date.now()));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** True when a non-empty cart's last touch is older than the TTL (0 = disabled). */
|
|
126
|
+
private isExpired(): boolean {
|
|
127
|
+
if (this.ttlMs <= 0 || this.lines.length === 0) return false;
|
|
128
|
+
const raw = this.storage?.getItem(stampKey(this.namespace));
|
|
129
|
+
const touched = raw ? Number(raw) : NaN;
|
|
130
|
+
return Number.isFinite(touched) && Date.now() - touched > this.ttlMs;
|
|
106
131
|
}
|
|
107
132
|
|
|
108
133
|
// ---- observation -------------------------------------------------------
|
|
@@ -162,8 +187,41 @@ export class CartEngine<TItem extends CartItem = CartItem> {
|
|
|
162
187
|
if (next.length !== this.lines.length) this.commit(next);
|
|
163
188
|
}
|
|
164
189
|
|
|
190
|
+
/**
|
|
191
|
+
* CONSUME the cart: empty it AND retire its id, minting a fresh one for the next
|
|
192
|
+
* order. clear() is the checkout-success signal — at that point the cart's state has
|
|
193
|
+
* already MOVED into the durable order record (the checkout order_intent snapshot), so
|
|
194
|
+
* the cart is spent. Keeping the SAME id let a re-checkout reuse the same order_intent
|
|
195
|
+
* slot + the client's cached shipping quote, so several orders shared ONE frozen
|
|
196
|
+
* EasyPost shipment (the first bought the label; later orders' label keys 404'd). A
|
|
197
|
+
* fresh id ⇒ a fresh order_intent slot + a fresh quote per order. The retired id's
|
|
198
|
+
* durable cart row is orphaned-empty and never referenced again (the order lives in
|
|
199
|
+
* order_intents, not carts), so nothing is lost.
|
|
200
|
+
*/
|
|
165
201
|
clear(): void {
|
|
166
|
-
|
|
202
|
+
const oldId = this.cartId;
|
|
203
|
+
this.lines = [];
|
|
204
|
+
this.persistLocal(); // empty local under the OLD id + fresh stamp
|
|
205
|
+
// Retire the OLD id's durable row explicitly. A debounced commit([]) would NOT do this:
|
|
206
|
+
// push() reads this.cartId lazily, so after the rotation below it would PUT empty under
|
|
207
|
+
// the NEW id and leave the old row populated (a phantom cart another device holding the
|
|
208
|
+
// old id could restore). So push empty to the captured old id directly, cancel any
|
|
209
|
+
// pending debounce, THEN rotate.
|
|
210
|
+
if (this.sync) {
|
|
211
|
+
void this.sync
|
|
212
|
+
.push({ id: oldId, namespace: this.namespace, items: [], updatedAt: Date.now() })
|
|
213
|
+
.catch(() => {}); // durable cleanup is best-effort; local state is already empty
|
|
214
|
+
}
|
|
215
|
+
if (this.flushTimer) {
|
|
216
|
+
clearTimeout(this.flushTimer);
|
|
217
|
+
this.flushTimer = null;
|
|
218
|
+
}
|
|
219
|
+
// Fresh identity for the next order — a new order_intent slot + a fresh quote.
|
|
220
|
+
const id = this.mintId();
|
|
221
|
+
this.cartId = id;
|
|
222
|
+
this.storage?.setItem(idKey(this.namespace), id);
|
|
223
|
+
this.persistLocal();
|
|
224
|
+
this.emit();
|
|
167
225
|
}
|
|
168
226
|
|
|
169
227
|
// ---- derived -----------------------------------------------------------
|
package/src/server.ts
CHANGED
|
@@ -166,9 +166,37 @@ export const ORDER_INTENTS_SQL = `CREATE TABLE IF NOT EXISTS order_intents (
|
|
|
166
166
|
customer_name TEXT,
|
|
167
167
|
customer_email TEXT,
|
|
168
168
|
customer_phone TEXT,
|
|
169
|
+
fulfillment TEXT NOT NULL DEFAULT 'pickup',
|
|
170
|
+
ship_to TEXT,
|
|
171
|
+
shipping TEXT,
|
|
169
172
|
created_at INTEGER
|
|
170
173
|
)`;
|
|
171
174
|
|
|
175
|
+
/** A shipping destination frozen into the snapshot (structural — the cart layer
|
|
176
|
+
* stays below @ikeboy003/checkout, so it doesn't import ShipTo). */
|
|
177
|
+
export interface SnapshotShipTo {
|
|
178
|
+
name?: string;
|
|
179
|
+
phone?: string;
|
|
180
|
+
street1?: string;
|
|
181
|
+
street2?: string;
|
|
182
|
+
city?: string;
|
|
183
|
+
state?: string;
|
|
184
|
+
postal?: string;
|
|
185
|
+
country?: string;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/** The chosen shipping rate frozen into the snapshot (structural — mirrors
|
|
189
|
+
* @ikeboy003/checkout's ShippingQuote without importing it). */
|
|
190
|
+
export interface SnapshotShipping {
|
|
191
|
+
rateId?: string;
|
|
192
|
+
shipmentId?: string;
|
|
193
|
+
amountCents?: number;
|
|
194
|
+
carrier?: string;
|
|
195
|
+
service?: string;
|
|
196
|
+
estDays?: number;
|
|
197
|
+
weightOz?: number;
|
|
198
|
+
}
|
|
199
|
+
|
|
172
200
|
/** A checkout snapshot: the cart's lines + the guest customer, frozen at PaymentIntent
|
|
173
201
|
* time. The payment webhook reads this (not the mutable cart) to build the order. */
|
|
174
202
|
export interface OrderSnapshot<TItem extends CartItem = CartItem> {
|
|
@@ -180,6 +208,12 @@ export interface OrderSnapshot<TItem extends CartItem = CartItem> {
|
|
|
180
208
|
items: TItem[];
|
|
181
209
|
/** Guest contact — only known at checkout, never on the cart. */
|
|
182
210
|
customer?: { name?: string; email?: string; phone?: string };
|
|
211
|
+
/** "pickup" | "shipment" | … — project-defined; frozen so the order records it. */
|
|
212
|
+
fulfillment?: string;
|
|
213
|
+
/** Ship-to address — only exists at checkout for a shipment, like the guest customer. */
|
|
214
|
+
shipTo?: SnapshotShipTo | null;
|
|
215
|
+
/** The chosen carrier rate (ids the fulfillment service buys the label by). */
|
|
216
|
+
shipping?: SnapshotShipping | null;
|
|
183
217
|
}
|
|
184
218
|
|
|
185
219
|
/** Writes {@link OrderSnapshot}s. One method — the snapshot is write-once-per-checkout. */
|
|
@@ -201,10 +235,11 @@ function d1OrderStore<TItem extends CartItem>(d1: D1Like): OrderSnapshotStore<TI
|
|
|
201
235
|
await d1
|
|
202
236
|
.prepare(
|
|
203
237
|
`INSERT INTO order_intents
|
|
204
|
-
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, created_at)
|
|
205
|
-
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)
|
|
238
|
+
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, fulfillment, ship_to, shipping, created_at)
|
|
239
|
+
VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11)
|
|
206
240
|
ON CONFLICT(cart_id) DO UPDATE SET
|
|
207
|
-
items=?3, subtotal_cents=?4, customer_name=?5, customer_email=?6, customer_phone=?7
|
|
241
|
+
items=?3, subtotal_cents=?4, customer_name=?5, customer_email=?6, customer_phone=?7,
|
|
242
|
+
fulfillment=?8, ship_to=?9, shipping=?10`,
|
|
208
243
|
)
|
|
209
244
|
.bind(
|
|
210
245
|
s.cartId,
|
|
@@ -214,6 +249,9 @@ function d1OrderStore<TItem extends CartItem>(d1: D1Like): OrderSnapshotStore<TI
|
|
|
214
249
|
s.customer?.name ?? "",
|
|
215
250
|
s.customer?.email ?? "",
|
|
216
251
|
s.customer?.phone ?? "",
|
|
252
|
+
s.fulfillment ?? "pickup",
|
|
253
|
+
s.shipTo ? JSON.stringify(s.shipTo) : null,
|
|
254
|
+
s.shipping ? JSON.stringify(s.shipping) : null,
|
|
217
255
|
Date.now(),
|
|
218
256
|
)
|
|
219
257
|
.run();
|
|
@@ -242,11 +280,12 @@ async function sqliteOrderStore<TItem extends CartItem>(
|
|
|
242
280
|
db.exec(ORDER_INTENTS_SQL);
|
|
243
281
|
const ins = db.prepare(
|
|
244
282
|
`INSERT INTO order_intents
|
|
245
|
-
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, created_at)
|
|
246
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
283
|
+
(cart_id, site, items, subtotal_cents, customer_name, customer_email, customer_phone, fulfillment, ship_to, shipping, created_at)
|
|
284
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
247
285
|
ON CONFLICT(cart_id) DO UPDATE SET
|
|
248
286
|
items=excluded.items, subtotal_cents=excluded.subtotal_cents, customer_name=excluded.customer_name,
|
|
249
|
-
customer_email=excluded.customer_email, customer_phone=excluded.customer_phone
|
|
287
|
+
customer_email=excluded.customer_email, customer_phone=excluded.customer_phone,
|
|
288
|
+
fulfillment=excluded.fulfillment, ship_to=excluded.ship_to, shipping=excluded.shipping`,
|
|
250
289
|
);
|
|
251
290
|
return {
|
|
252
291
|
async save(s) {
|
|
@@ -258,6 +297,9 @@ async function sqliteOrderStore<TItem extends CartItem>(
|
|
|
258
297
|
s.customer?.name ?? "",
|
|
259
298
|
s.customer?.email ?? "",
|
|
260
299
|
s.customer?.phone ?? "",
|
|
300
|
+
s.fulfillment ?? "pickup",
|
|
301
|
+
s.shipTo ? JSON.stringify(s.shipTo) : null,
|
|
302
|
+
s.shipping ? JSON.stringify(s.shipping) : null,
|
|
261
303
|
Date.now(),
|
|
262
304
|
);
|
|
263
305
|
},
|
package/src/types.ts
CHANGED
|
@@ -75,6 +75,14 @@ export interface CreateCartOptions<TItem extends CartItem = CartItem> {
|
|
|
75
75
|
sync?: CartSyncAdapter<TItem>;
|
|
76
76
|
/** Coalesce window for durable pushes (ms). Default 400. */
|
|
77
77
|
debounceMs?: number;
|
|
78
|
+
/**
|
|
79
|
+
* Abandonment TTL (ms). On load, a non-empty cart untouched for longer than this is
|
|
80
|
+
* CONSUMED — emptied + its id retired for a fresh one — so a returning shopper never
|
|
81
|
+
* resumes a stale cart (or a checkout's frozen shipping quote). Identity is the
|
|
82
|
+
* localStorage cart-id capability, so this is a client-side, per-browser check.
|
|
83
|
+
* Default 7 days. Set 0 to disable.
|
|
84
|
+
*/
|
|
85
|
+
ttlMs?: number;
|
|
78
86
|
/** Id minter. Default `crypto.randomUUID`. */
|
|
79
87
|
newId?: () => string;
|
|
80
88
|
}
|