@zappie/sdk 0.1.4 → 0.1.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # @zappie/sdk
2
2
 
3
+ ## 0.1.6
4
+
5
+ ### Patch Changes
6
+
7
+ - 45295a2: Make product cards ready to tap with route discovery, prefetch lint rules and measured storefront checks.
8
+
9
+ ## 0.1.5
10
+
11
+ ### Patch Changes
12
+
13
+ - e1d601b: Read fulfilment-specific menus, quote signed-in carts through the customer channel and plan cart lines for a branch switch.
14
+
3
15
  ## 0.1.4
4
16
 
5
17
  ### Patch Changes
@@ -0,0 +1,26 @@
1
+ import { M as Money, I as Item, a as Menu } from '../models-Rg5kQUkv.js';
2
+ import { C as CartLine } from '../types-CuDvfW9g.js';
3
+
4
+ /** A line that can move to the destination branch, with its old and new estimates. */
5
+ type BranchSwitchKeptLine = {
6
+ line: CartLine;
7
+ name: string;
8
+ before: Money;
9
+ after: Money;
10
+ };
11
+ /** The lines that can and cannot move to another branch, with the new subtotal. */
12
+ type BranchSwitchPlan = {
13
+ kept: BranchSwitchKeptLine[];
14
+ dropped: {
15
+ line: CartLine;
16
+ name: string;
17
+ }[];
18
+ lines: CartLine[];
19
+ subtotal: Money | null;
20
+ };
21
+ /** Estimate a cart line from its exact variant and selected choices. */
22
+ declare function estimateLine(line: CartLine, item: Item): Money;
23
+ /** Plan which cart lines move to another branch without changing either cart. */
24
+ declare function planBranchSwitch(lines: readonly CartLine[], from: Menu, to: Menu): BranchSwitchPlan;
25
+
26
+ export { type BranchSwitchKeptLine, type BranchSwitchPlan, estimateLine, planBranchSwitch };
@@ -0,0 +1,79 @@
1
+ // src/cart/branch.ts
2
+ import {
3
+ estimateUnitPrice,
4
+ money
5
+ } from "@zappie/sdk";
6
+ function estimateLine(line, item) {
7
+ const unit = estimateUnitPrice(item, line);
8
+ return money(unit.amountMinor * line.quantity, unit.currency);
9
+ }
10
+ function destinationMenu(menu, line) {
11
+ const categories = menu.categories.filter(
12
+ (category) => category.itemIds.includes(line.itemId)
13
+ );
14
+ const sources = menu.menus ?? [
15
+ {
16
+ id: menu.id,
17
+ categoryIds: menu.categories.map((category) => category.id)
18
+ }
19
+ ];
20
+ const placements = menu.items[line.itemId]?.placements;
21
+ const candidates = sources.filter(
22
+ (source) => (!placements || placements.some(
23
+ (placement) => placement.menuId === source.id && source.categoryIds.includes(placement.categoryId)
24
+ )) && source.categoryIds.some(
25
+ (id) => categories.some((category) => category.id === id)
26
+ )
27
+ );
28
+ return (candidates.find((candidate) => candidate.id === line.menuId) ?? candidates[0])?.id;
29
+ }
30
+ function sells(line, item) {
31
+ if (!item?.isAvailable) {
32
+ return false;
33
+ }
34
+ if (line.variantId && !item.variants.some(
35
+ (variant) => variant.id === line.variantId && variant.isAvailable
36
+ )) {
37
+ return false;
38
+ }
39
+ return line.choices.every(
40
+ (selected) => item.optionGroups.some(
41
+ (group) => group.id === selected.groupId && group.choices.some(
42
+ (choice) => choice.id === selected.choiceId && choice.isAvailable
43
+ )
44
+ )
45
+ );
46
+ }
47
+ function planBranchSwitch(lines, from, to) {
48
+ const plan = {
49
+ kept: [],
50
+ dropped: [],
51
+ lines: [],
52
+ subtotal: null
53
+ };
54
+ for (const line of lines) {
55
+ const before = from.items[line.itemId];
56
+ const after = to.items[line.itemId];
57
+ const name = before?.name ?? after?.name ?? "An item";
58
+ const menuId = destinationMenu(to, line);
59
+ if (!sells(line, after) || !menuId) {
60
+ plan.dropped.push({ line, name });
61
+ continue;
62
+ }
63
+ const moved = { ...line, menuId };
64
+ const next = estimateLine(moved, after);
65
+ const previous = before ? estimateLine(line, before) : next;
66
+ plan.kept.push({ line: moved, name, before: previous, after: next });
67
+ plan.lines.push(moved);
68
+ plan.subtotal = money(
69
+ (plan.subtotal?.amountMinor ?? 0) + next.amountMinor,
70
+ next.currency
71
+ );
72
+ }
73
+ return plan;
74
+ }
75
+ export {
76
+ estimateLine,
77
+ planBranchSwitch
78
+ };
79
+ //# sourceMappingURL=branch.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/cart/branch.ts"],
4
+ "sourcesContent": ["// This isolated entry imports the installed core so it does not bundle another copy.\n// eslint-disable-next-line no-restricted-imports\nimport {\n estimateUnitPrice,\n money,\n type CartLine,\n type Item,\n type Menu,\n type Money,\n} from \"@zappie/sdk\";\n\n/** A line that can move to the destination branch, with its old and new estimates. */\nexport type BranchSwitchKeptLine = {\n line: CartLine;\n name: string;\n before: Money;\n after: Money;\n};\n\n/** The lines that can and cannot move to another branch, with the new subtotal. */\nexport type BranchSwitchPlan = {\n kept: BranchSwitchKeptLine[];\n dropped: { line: CartLine; name: string }[];\n lines: CartLine[];\n subtotal: Money | null;\n};\n\n/** Estimate a cart line from its exact variant and selected choices. */\nexport function estimateLine(line: CartLine, item: Item): Money {\n const unit = estimateUnitPrice(item, line);\n return money(unit.amountMinor * line.quantity, unit.currency);\n}\n\nfunction destinationMenu(menu: Menu, line: CartLine) {\n const categories = menu.categories.filter((category) =>\n category.itemIds.includes(line.itemId),\n );\n const sources = menu.menus ?? [\n {\n id: menu.id,\n categoryIds: menu.categories.map((category) => category.id),\n },\n ];\n const placements = menu.items[line.itemId]?.placements;\n const candidates = sources.filter(\n (source) =>\n (!placements ||\n placements.some(\n (placement) =>\n placement.menuId === source.id &&\n source.categoryIds.includes(placement.categoryId),\n )) &&\n source.categoryIds.some((id) =>\n categories.some((category) => category.id === id),\n ),\n );\n return (\n candidates.find((candidate) => candidate.id === line.menuId) ??\n candidates[0]\n )?.id;\n}\n\nfunction sells(line: CartLine, item: Item | undefined): item is Item {\n if (!item?.isAvailable) {\n return false;\n }\n if (\n line.variantId &&\n !item.variants.some(\n (variant) => variant.id === line.variantId && variant.isAvailable,\n )\n ) {\n return false;\n }\n return line.choices.every((selected) =>\n item.optionGroups.some(\n (group) =>\n group.id === selected.groupId &&\n group.choices.some(\n (choice) => choice.id === selected.choiceId && choice.isAvailable,\n ),\n ),\n );\n}\n\n/** Plan which cart lines move to another branch without changing either cart. */\nexport function planBranchSwitch(\n lines: readonly CartLine[],\n from: Menu,\n to: Menu,\n): BranchSwitchPlan {\n const plan: BranchSwitchPlan = {\n kept: [],\n dropped: [],\n lines: [],\n subtotal: null,\n };\n for (const line of lines) {\n const before = from.items[line.itemId];\n const after = to.items[line.itemId];\n const name = before?.name ?? after?.name ?? \"An item\";\n const menuId = destinationMenu(to, line);\n if (!sells(line, after) || !menuId) {\n plan.dropped.push({ line, name });\n continue;\n }\n const moved = { ...line, menuId };\n const next = estimateLine(moved, after);\n const previous = before ? estimateLine(line, before) : next;\n plan.kept.push({ line: moved, name, before: previous, after: next });\n plan.lines.push(moved);\n plan.subtotal = money(\n (plan.subtotal?.amountMinor ?? 0) + next.amountMinor,\n next.currency,\n );\n }\n return plan;\n}\n"],
5
+ "mappings": ";AAEA;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AAmBA,SAAS,aAAa,MAAgB,MAAmB;AAC9D,QAAM,OAAO,kBAAkB,MAAM,IAAI;AACzC,SAAO,MAAM,KAAK,cAAc,KAAK,UAAU,KAAK,QAAQ;AAC9D;AAEA,SAAS,gBAAgB,MAAY,MAAgB;AACnD,QAAM,aAAa,KAAK,WAAW;AAAA,IAAO,CAAC,aACzC,SAAS,QAAQ,SAAS,KAAK,MAAM;AAAA,EACvC;AACA,QAAM,UAAU,KAAK,SAAS;AAAA,IAC5B;AAAA,MACE,IAAI,KAAK;AAAA,MACT,aAAa,KAAK,WAAW,IAAI,CAAC,aAAa,SAAS,EAAE;AAAA,IAC5D;AAAA,EACF;AACA,QAAM,aAAa,KAAK,MAAM,KAAK,MAAM,GAAG;AAC5C,QAAM,aAAa,QAAQ;AAAA,IACzB,CAAC,YACE,CAAC,cACA,WAAW;AAAA,MACT,CAAC,cACC,UAAU,WAAW,OAAO,MAC5B,OAAO,YAAY,SAAS,UAAU,UAAU;AAAA,IACpD,MACF,OAAO,YAAY;AAAA,MAAK,CAAC,OACvB,WAAW,KAAK,CAAC,aAAa,SAAS,OAAO,EAAE;AAAA,IAClD;AAAA,EACJ;AACA,UACE,WAAW,KAAK,CAAC,cAAc,UAAU,OAAO,KAAK,MAAM,KAC3D,WAAW,CAAC,IACX;AACL;AAEA,SAAS,MAAM,MAAgB,MAAsC;AACnE,MAAI,CAAC,MAAM,aAAa;AACtB,WAAO;AAAA,EACT;AACA,MACE,KAAK,aACL,CAAC,KAAK,SAAS;AAAA,IACb,CAAC,YAAY,QAAQ,OAAO,KAAK,aAAa,QAAQ;AAAA,EACxD,GACA;AACA,WAAO;AAAA,EACT;AACA,SAAO,KAAK,QAAQ;AAAA,IAAM,CAAC,aACzB,KAAK,aAAa;AAAA,MAChB,CAAC,UACC,MAAM,OAAO,SAAS,WACtB,MAAM,QAAQ;AAAA,QACZ,CAAC,WAAW,OAAO,OAAO,SAAS,YAAY,OAAO;AAAA,MACxD;AAAA,IACJ;AAAA,EACF;AACF;AAGO,SAAS,iBACd,OACA,MACA,IACkB;AAClB,QAAM,OAAyB;AAAA,IAC7B,MAAM,CAAC;AAAA,IACP,SAAS,CAAC;AAAA,IACV,OAAO,CAAC;AAAA,IACR,UAAU;AAAA,EACZ;AACA,aAAW,QAAQ,OAAO;AACxB,UAAM,SAAS,KAAK,MAAM,KAAK,MAAM;AACrC,UAAM,QAAQ,GAAG,MAAM,KAAK,MAAM;AAClC,UAAM,OAAO,QAAQ,QAAQ,OAAO,QAAQ;AAC5C,UAAM,SAAS,gBAAgB,IAAI,IAAI;AACvC,QAAI,CAAC,MAAM,MAAM,KAAK,KAAK,CAAC,QAAQ;AAClC,WAAK,QAAQ,KAAK,EAAE,MAAM,KAAK,CAAC;AAChC;AAAA,IACF;AACA,UAAM,QAAQ,EAAE,GAAG,MAAM,OAAO;AAChC,UAAM,OAAO,aAAa,OAAO,KAAK;AACtC,UAAM,WAAW,SAAS,aAAa,MAAM,MAAM,IAAI;AACvD,SAAK,KAAK,KAAK,EAAE,MAAM,OAAO,MAAM,QAAQ,UAAU,OAAO,KAAK,CAAC;AACnE,SAAK,MAAM,KAAK,KAAK;AACrB,SAAK,WAAW;AAAA,OACb,KAAK,UAAU,eAAe,KAAK,KAAK;AAAA,MACzC,KAAK;AAAA,IACP;AAAA,EACF;AACA,SAAO;AACT;",
6
+ "names": []
7
+ }
@@ -91,7 +91,7 @@ function createCart(deps) {
91
91
  let quotes;
92
92
  let loadingQuotes;
93
93
  const quoteClient = () => loadingQuotes ?? (loadingQuotes = import("./quote-client.js").then(
94
- ({ createQuoteClient }) => quotes = createQuoteClient(deps.transport, deps.context),
94
+ ({ createQuoteClient }) => quotes = createQuoteClient(deps.transport, deps.context, config),
95
95
  (error) => {
96
96
  loadingQuotes = void 0;
97
97
  throw error;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/index.ts"],
4
- "sourcesContent": ["import type { MenuResource, StoreResource } from \"../client\";\nimport type { ZappieConfig } from \"../config\";\nimport { asError, ZappieError } from \"../errors\";\nimport type { createEmitter } from \"../internal/emitter\";\nimport { multiplyMoney, sumMoney } from \"../internal/money-math\";\nimport type { Branch, Menu } from \"../models\";\nimport { money } from \"../money\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\nimport { ZappieCartError } from \"./errors\";\nimport { estimateUnitPrice } from \"./price\";\nimport type { QuoteClient } from \"./quote-client\";\nimport { freezeLine, lineInput, reconcile } from \"./reconcile\";\nimport type { StoredCart, StoredLine } from \"./storage\";\nimport { createCartStorage, parseCart, validFulfilment } from \"./storage\";\nimport type {\n CartIssue,\n CartLine,\n CartLineInput,\n CartModule,\n CartSnapshot,\n Quote,\n} from \"./types\";\nimport {\n issue,\n normalizeInput,\n resolveVariant,\n validateLine,\n} from \"./validate\";\nimport { wireFulfilment, wireLine } from \"./wire\";\nimport type { createWorkingSet } from \"./working-set\";\nexport const EMPTY_CART: CartSnapshot = Object.freeze({\n lines: Object.freeze([]),\n count: 0,\n subtotal: null,\n fulfilment: null,\n promoCode: null,\n state: { status: \"ready\" as const },\n issues: Object.freeze([]),\n isHydrated: false,\n});\nfunction deepFreeze<T>(value: T): T {\n if (value && typeof value === \"object\" && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const child of Object.values(value)) {\n deepFreeze(child);\n }\n }\n return value;\n}\nfunction identity(input: CartLineInput) {\n return JSON.stringify([\n input.itemId,\n input.menuId,\n input.variantId,\n input.note ?? \"\",\n [...(input.choices ?? [])].sort(\n (a, b) =>\n a.groupId.localeCompare(b.groupId) ||\n a.choiceId.localeCompare(b.choiceId),\n ),\n Object.entries(input.inputs ?? {}).sort(([a], [b]) => a.localeCompare(b)),\n ]);\n}\nexport function createCart(deps: {\n workingSet: ReturnType<typeof createWorkingSet>;\n config: ZappieConfig;\n menu: MenuResource;\n store: StoreResource;\n transport: Transport;\n context: () => RequestCtx;\n events: ReturnType<typeof createEmitter>;\n}) {\n const { config, menu: menus, store, events } = deps;\n const ttl = config.cart?.ttl ?? 7 * 24 * 60 * 60 * 1000;\n if (!Number.isFinite(ttl) || ttl <= 0) {\n throw new ZappieError(\n \"invalid_request\",\n \"Cart ttl must be positive milliseconds\",\n );\n }\n let snapshot = EMPTY_CART;\n let menu: Menu | undefined;\n let branch: Branch | undefined;\n let selected = config.branch;\n let updatedAt = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let revision = 0;\n let quoteRevision = 0;\n let moveSequence = 0;\n let refreshSequence = 0;\n let mounted = 0;\n let detach: (() => void) | undefined;\n let hydration: Promise<void> | undefined;\n let lifecycle = 0;\n let legacy:\n ((read: (key: string) => string | null) => CartLineInput[]) | undefined;\n const listeners = new Set<() => void>();\n const prefix = `zappie:cart:v1:${config.store}:`;\n const scope = config.cart?.storageScope;\n const keyFor = (id: string) => `${prefix}${id}${scope ? `:${scope}` : \"\"}`;\n const key = () => keyFor(branch!.id);\n const storage = createCartStorage(config.storage, (message) =>\n events.emit(\"warning\", { message }),\n );\n // A scoped cart adopts the branch's unscoped cart once, so only one scope inherits it.\n const readSaved = (id: string) => {\n let raw = storage.read(keyFor(id));\n if (raw === null && scope) {\n raw = storage.read(prefix + id);\n if (raw !== null) {\n storage.remove(prefix + id);\n storage.write(keyFor(id), raw);\n }\n }\n return raw;\n };\n // The quote client and response mapping load on the first quote; add/validate stay synchronous.\n let quotes: QuoteClient | undefined;\n let loadingQuotes: Promise<QuoteClient> | undefined;\n const quoteClient = () =>\n (loadingQuotes ??= import(\"./quote-client\").then(\n ({ createQuoteClient }) =>\n (quotes = createQuoteClient(deps.transport, deps.context)),\n (error: unknown) => {\n // A failed chunk load (e.g. offline) must not poison every later quote.\n loadingQuotes = undefined;\n throw error;\n },\n ));\n const publish = (patch: Partial<CartSnapshot>) => {\n snapshot = deepFreeze({\n ...snapshot,\n ...patch,\n branchId: branch?.id,\n });\n for (const fn of [...listeners]) {\n try {\n fn();\n } catch (error) {\n events.emit(\"error\", { error: asError(error) });\n }\n }\n };\n const attention = (\n issues: readonly CartIssue[],\n quote?: Quote,\n ): CartSnapshot[\"state\"] =>\n issues.some((i) => i.severity !== \"info\")\n ? { status: \"needs_attention\", issues, ...(quote ? { quote } : {}) }\n : quote\n ? { status: \"quoted\", quote }\n : { status: \"ready\" };\n const cancel = () => {\n revision++;\n quoteRevision++;\n clearTimeout(timer);\n quotes?.cancel();\n };\n const persist = () => {\n const value: StoredCart = {\n v: 1,\n lines: snapshot.lines.map((line) => ({\n ...lineInput(line),\n id: line.id,\n name: line.name,\n addedAt: line.addedAt,\n unitPrice: line.unitPrice,\n })),\n fulfilment: snapshot.fulfilment,\n promoCode: snapshot.promoCode,\n menuVersion: menu!.version,\n updatedAt,\n };\n storage.write(key(), JSON.stringify(value));\n };\n const schedule = () => {\n clearTimeout(timer);\n if (snapshot.lines.length) {\n timer = setTimeout(() => {\n void cart.quote().catch(() => {});\n }, 300);\n }\n };\n const recompute = (\n lines: readonly (CartLine | StoredLine)[],\n pending = snapshot.issues.filter((i) => i.source === \"local\"),\n patch: Partial<CartSnapshot> = {},\n ) => {\n const currency = store.peek()!.currency;\n const result = reconcile(lines, menu!, branch!, currency, pending);\n const subtotal = result.priced\n ? sumMoney(\n result.lines.map((l) => l.lineSubtotal),\n money(0, currency),\n )\n : null;\n publish({\n ...patch,\n lines: result.lines,\n count: result.lines.reduce((n, l) => n + l.quantity, 0),\n subtotal,\n issues: result.issues,\n state: attention(result.issues),\n });\n for (const i of result.issues) {\n events.emit(\"cart_issue\", { code: i.code });\n }\n };\n const changed = (\n lines: readonly (CartLine | StoredLine)[] = snapshot.lines,\n patch: Partial<CartSnapshot> = {},\n ) => {\n cancel();\n recompute(lines, undefined, patch);\n updatedAt = Date.now();\n persist();\n schedule();\n };\n const choose = (value: Menu) => {\n const found = store.peek()?.branches.find((b) => b.id === value.branchId);\n if (!found) {\n throw new ZappieError(\n \"branch_not_found\",\n \"Load the storefront branch before using its cart\",\n );\n }\n menu = value;\n branch = found;\n selected = found.id;\n };\n const load = (raw: string | null, writeBack = true) => {\n cancel();\n let saved: StoredCart | undefined;\n try {\n saved = raw ? parseCart(raw) : undefined;\n if (saved && Date.now() - saved.updatedAt > ttl) {\n saved = undefined;\n storage.remove(key());\n events.emit(\"cart_expired\", { branchId: branch!.id });\n }\n } catch {\n storage.remove(key());\n storage.warning(\"Invalid saved cart discarded\");\n }\n updatedAt = saved?.updatedAt ?? Date.now();\n const idle = Date.now() - updatedAt;\n let fulfilment = saved?.fulfilment ?? null;\n if (\n fulfilment?.branchId !== branch!.id ||\n (idle > 86_400_000 && fulfilment.type === \"delivery\")\n ) {\n fulfilment = null;\n }\n if (\n fulfilment &&\n \"scheduledFor\" in fulfilment &&\n fulfilment.scheduledFor &&\n Date.parse(fulfilment.scheduledFor) < Date.now()\n ) {\n fulfilment = { ...fulfilment };\n delete fulfilment.scheduledFor;\n }\n const lines = (saved?.lines ?? []).map((line) => ({\n ...line,\n ...(idle > 86_400_000 ? { inputs: {} } : {}),\n }));\n const result = reconcile(lines, menu!, branch!, store.peek()!.currency);\n recompute(result.lines, result.issues, {\n fulfilment,\n promoCode: saved?.promoCode ?? null,\n isHydrated: true,\n });\n // Persist privacy scrubbing and normalized prices without extending idle expiry.\n if (raw !== null && writeBack) {\n persist();\n }\n storage.sweep(prefix, key(), ttl);\n };\n const ensure = () => {\n const id =\n branch?.id ??\n store\n .peek()\n ?.branches.find(\n (b) =>\n b.id === selected ||\n b.slug === selected ||\n (!selected && b.isDefault),\n )?.id ??\n (!selected ? store.peek()?.branches[0]?.id : undefined);\n if (snapshot.isHydrated) {\n return;\n }\n const loaded = menu ?? (id ? deps.workingSet.peek(id, []) : undefined);\n if (!loaded || !store.peek()) {\n throw new ZappieError(\n \"invalid_request\",\n \"Load the store and menu before editing the cart\",\n );\n }\n choose(loaded);\n const raw = readSaved(branch!.id);\n let migrated: CartLineInput[] = [];\n if (raw === null && legacy) {\n try {\n migrated = legacy(storage.read);\n } catch {\n storage.warning(\"Invalid legacy cart discarded\");\n }\n }\n load(raw);\n if (raw === null && legacy) {\n persist();\n }\n for (const input of migrated.slice(0, 100)) {\n try {\n cart.add(input.itemId, input);\n } catch {\n events.emit(\"cart_issue\", { code: \"item_unavailable\" });\n }\n }\n };\n const refresh = async () => {\n const id = branch?.id;\n const seq = moveSequence;\n const request = ++refreshSequence;\n const rev = revision;\n if (!id || !menu) {\n return;\n }\n if (!snapshot.lines.length) {\n return;\n }\n if (menu.completeness !== \"partial\") {\n const version = await deps.transport.getMenuVersion({\n ...deps.context(),\n branchId: id,\n });\n if (version.version === menu.version) {\n return;\n }\n }\n const value = await deps.workingSet.read(\n id,\n snapshot.lines.map((l) => l.itemId),\n true,\n );\n if (\n seq !== moveSequence ||\n request !== refreshSequence ||\n rev !== revision ||\n JSON.stringify(value) === JSON.stringify(menu)\n ) {\n return;\n }\n menu = value;\n cancel();\n recompute(snapshot.lines);\n persist();\n schedule();\n };\n // Validation follows the latest copy of an item the working set holds: a\n // refreshed item can add a required option, and an add, edit or check\n // against the earlier copy would accept a line the server then rejects.\n const current = (itemId: string) => {\n const candidate = deps.workingSet.peek(branch!.id, [\n ...snapshot.lines.map((l) => l.itemId),\n itemId,\n ]);\n if (candidate.items[itemId]) {\n menu = candidate;\n }\n };\n const validated = (\n raw: CartLineInput,\n id?: string,\n addedAt?: string,\n ): CartLine => {\n current(raw.itemId);\n const item = Object.hasOwn(menu!.items, raw.itemId)\n ? menu!.items[raw.itemId]\n : undefined;\n const problems = validateLine(item, raw, { menu: menu!, branch: branch! });\n if (problems.length || !item) {\n throw new ZappieCartError(problems);\n }\n const input = normalizeInput(item, raw);\n const variant = resolveVariant(item, input)!;\n const choices = (input.choices ?? []).map((c) => ({\n ...c,\n quantity: c.quantity ?? 1,\n }));\n const unitPrice = estimateUnitPrice(item, {\n choices,\n variantId: variant.id,\n });\n return freezeLine({\n id:\n id ??\n `line_${Array.from(globalThis.crypto.getRandomValues(new Uint8Array(10)), (byte) => \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-\"[byte & 63]).join(\"\")}`,\n itemId: item.id,\n ...(input.menuId !== undefined ? { menuId: input.menuId } : {}),\n name: item.name,\n quantity: input.quantity!,\n choices,\n inputs: input.inputs ?? {},\n variantId: variant.id,\n ...(input.note !== undefined ? { note: input.note } : {}),\n unitPrice,\n lineSubtotal: multiplyMoney(unitPrice, input.quantity!),\n addedAt: addedAt ?? new Date().toISOString(),\n });\n };\n const offMenu = events.on(\"menu:updated\", ({ branchId, version }) => {\n if (branch?.id === branchId) {\n const value = menus.peek(branchId);\n if (\n value &&\n value.completeness !== \"partial\" &&\n value.version === version &&\n value.version !== menu?.version\n ) {\n refreshSequence++;\n menu = value;\n cancel();\n recompute(snapshot.lines);\n persist();\n schedule();\n }\n }\n });\n const cart: CartModule = {\n get branchId() {\n return snapshot.branchId;\n },\n get lines() {\n return snapshot.lines;\n },\n get count() {\n return snapshot.count;\n },\n get subtotal() {\n return snapshot.subtotal;\n },\n get fulfilment() {\n return snapshot.fulfilment;\n },\n get promoCode() {\n return snapshot.promoCode;\n },\n get state() {\n return snapshot.state;\n },\n get issues() {\n return snapshot.issues;\n },\n get isHydrated() {\n return snapshot.isHydrated;\n },\n getSnapshot: () => snapshot,\n subscribe(fn) {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n },\n async hydrate() {\n if (snapshot.isHydrated) {\n return refresh();\n }\n const life = lifecycle;\n hydration ??= (async () => {\n const value = await store.get();\n const target =\n value.branches.find(\n (b) => b.id === selected || b.slug === selected,\n ) ??\n (!selected\n ? (value.branches.find((b) => b.isDefault) ?? value.branches[0])\n : undefined);\n if (!target) {\n throw new ZappieError(\n \"branch_not_found\",\n \"Cart branch is unavailable\",\n );\n }\n let inputs: readonly { itemId: string }[] = snapshot.lines;\n if (!snapshot.isHydrated) {\n const raw = readSaved(target.id);\n try {\n const saved = raw ? parseCart(raw) : undefined;\n inputs =\n saved && Date.now() - saved.updatedAt <= ttl\n ? saved.lines\n : raw === null\n ? (legacy?.(storage.read) ?? [])\n : [];\n } catch {\n inputs = [];\n }\n }\n const loaded = await deps.workingSet.read(\n target.id,\n inputs.map((l) => l.itemId),\n );\n if (life !== lifecycle) {\n return;\n }\n choose(loaded);\n ensure();\n if (loaded.completeness !== \"partial\") {\n await refresh();\n }\n })().finally(() => {\n hydration = undefined;\n });\n return hydration;\n },\n mount() {\n mounted++;\n if (!detach && typeof window !== \"undefined\") {\n const onStorage = (event: StorageEvent) => {\n if (\n branch &&\n event.key === key() &&\n storage.accepts(event.storageArea)\n ) {\n const raw = event.newValue;\n let ids: string[];\n try {\n ids = raw ? parseCart(raw).lines.map((l) => l.itemId) : [];\n } catch {\n load(raw, false);\n return;\n }\n const cached = deps.workingSet.peek(branch.id, ids);\n if (\n cached.completeness !== \"partial\" ||\n ids.every((id) => cached.items[id])\n ) {\n menu = cached;\n load(raw, false);\n schedule();\n return;\n }\n const rev = revision;\n const request = ++refreshSequence;\n const life = lifecycle;\n void deps.workingSet\n .read(branch.id, ids)\n .then((value) => {\n if (\n life === lifecycle &&\n rev === revision &&\n request === refreshSequence\n ) {\n menu = value;\n load(raw, false);\n schedule();\n }\n })\n .catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n };\n const onFocus = () => {\n void refresh().catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n };\n window.addEventListener(\"storage\", onStorage);\n window.addEventListener(\"focus\", onFocus);\n // Only browser listeners follow mounts; the menu:updated subscription lives until dispose().\n detach = () => {\n window.removeEventListener(\"storage\", onStorage);\n window.removeEventListener(\"focus\", onFocus);\n };\n }\n if (mounted === 1) {\n void cart\n .hydrate()\n .catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n let active = true;\n return () => {\n if (active) {\n active = false;\n mounted--;\n if (mounted === 0) {\n detach?.();\n detach = undefined;\n cancel();\n }\n }\n };\n },\n dispose() {\n lifecycle++;\n moveSequence++;\n offMenu();\n cancel();\n detach?.();\n detach = undefined;\n listeners.clear();\n },\n validate(input) {\n ensure();\n current(input.itemId);\n const problems = validateLine(\n Object.hasOwn(menu!.items, input.itemId)\n ? menu!.items[input.itemId]\n : undefined,\n input,\n { menu: menu!, branch: branch! },\n );\n return problems.length ? { ok: false, issues: problems } : { ok: true };\n },\n add(item, input = {}) {\n ensure();\n let line = validated({\n ...input,\n itemId: typeof item === \"string\" ? item : item.id,\n });\n const existing = snapshot.lines.find(\n (l) => identity(lineInput(l)) === identity(lineInput(line)),\n );\n if (existing) {\n line = validated(\n { ...lineInput(line), quantity: existing.quantity + line.quantity },\n existing.id,\n existing.addedAt,\n );\n } else if (snapshot.lines.length >= 100) {\n throw new ZappieCartError([\n issue(\"quantity_limit\", \"A cart can contain at most 100 lines\"),\n ]);\n }\n changed(\n existing\n ? snapshot.lines.map((l) => (l.id === existing.id ? line : l))\n : [...snapshot.lines, line],\n );\n events.emit(\"add_to_cart\", {\n itemId: line.itemId,\n quantity: line.quantity - (existing?.quantity ?? 0),\n value: multiplyMoney(\n line.unitPrice,\n line.quantity - (existing?.quantity ?? 0),\n ),\n });\n return line;\n },\n update(lineId, patch) {\n ensure();\n const old = snapshot.lines.find((l) => l.id === lineId);\n if (!old) {\n throw new ZappieCartError([\n issue(\"item_not_found\", \"Cart line not found\"),\n ]);\n }\n const input = { ...lineInput(old), ...patch };\n if (patch.choices && !patch.variantId) {\n delete input.variantId;\n }\n let line = validated(input, old.id, old.addedAt);\n const duplicate = snapshot.lines.find(\n (l) =>\n l.id !== lineId &&\n identity(lineInput(l)) === identity(lineInput(line)),\n );\n if (duplicate) {\n line = validated(\n { ...lineInput(line), quantity: line.quantity + duplicate.quantity },\n old.id,\n old.addedAt,\n );\n }\n changed(\n snapshot.lines\n .filter((l) => l.id !== duplicate?.id)\n .map((l) => (l.id === lineId ? line : l)),\n );\n events.emit(\"update_cart_line\", {\n lineId,\n itemId: line.itemId,\n quantity: line.quantity,\n });\n return line;\n },\n remove(lineId) {\n ensure();\n const line = snapshot.lines.find((l) => l.id === lineId);\n changed(snapshot.lines.filter((l) => l.id !== lineId));\n if (line) {\n events.emit(\"remove_from_cart\", {\n itemId: line.itemId,\n quantity: line.quantity,\n value: line.lineSubtotal,\n });\n }\n },\n clear() {\n ensure();\n changed([], { fulfilment: null, promoCode: null });\n },\n setFulfilment(value) {\n ensure();\n if (!validFulfilment(value) || value.branchId !== branch!.id) {\n throw new ZappieCartError([\n issue(\n \"fulfilment_unavailable\",\n \"Select fulfilment for the cart's branch\",\n ),\n ]);\n }\n changed(snapshot.lines, { fulfilment: structuredClone(value) });\n },\n setPromoCode(code) {\n ensure();\n changed(snapshot.lines, { promoCode: code?.trim() || null });\n },\n async moveTo(branchId) {\n ensure();\n const seq = ++moveSequence;\n cancel();\n publish({ state: attention(snapshot.issues) });\n const value = await deps.workingSet.read(\n branchId,\n snapshot.lines.map((l) => l.itemId),\n );\n if (seq !== moveSequence) {\n return;\n }\n const oldKey = key();\n const oldLines = snapshot.lines;\n choose(value);\n const kept = oldLines.filter(\n (line) =>\n !validateLine(value.items[line.itemId], lineInput(line), {\n menu: value,\n branch: branch!,\n }).length,\n );\n changed(kept, { fulfilment: null, promoCode: null });\n const dropped = oldLines\n .filter((line) => !kept.includes(line))\n .map((line) => ({\n ...issue(\n \"item_unavailable\",\n `${line.name} is unavailable at this branch`,\n ),\n severity: \"warning\" as const,\n lineId: line.id,\n }));\n const issues = [...snapshot.issues, ...dropped];\n publish({ issues, state: attention(issues) });\n if (oldKey !== key()) {\n storage.remove(oldKey);\n }\n },\n async quote(opts = {}) {\n ensure();\n clearTimeout(timer);\n if (opts.force) {\n events.emit(\"view_cart\", {});\n }\n const body = {\n branch_id: branch!.id,\n lines: snapshot.lines.map(wireLine),\n ...(snapshot.fulfilment\n ? { fulfilment: wireFulfilment(snapshot.fulfilment) }\n : {}),\n ...(snapshot.promoCode ? { promo_code: snapshot.promoCode } : {}),\n menu_version: menu!.version,\n };\n const seq = revision;\n const attempt = ++quoteRevision;\n publish({ state: { status: \"quoting\" } });\n try {\n const client = await quoteClient();\n return await client.get(body, opts.force ?? false, (quote) => {\n if (seq !== revision) {\n return;\n }\n const local = snapshot.issues.filter((i) => i.source === \"local\");\n // The server re-validates every line; a problem the cart already reports is shown once.\n const remote = quote.issues.filter(\n (q) =>\n !local.some(\n (l) =>\n l.code === q.code &&\n l.lineId === q.lineId &&\n l.groupId === q.groupId,\n ),\n );\n const issues = [...local, ...remote];\n publish({ issues, state: attention(issues, quote) });\n for (const i of remote) {\n events.emit(\"cart_issue\", { code: i.code });\n }\n // A newer server menu means local prices and the sent version are stale. Refreshing\n // reconciles them and re-quotes, so the server stops re-raising the same change.\n if (\n quote.menuVersion !== menu!.version ||\n quote.issues.some((i) => i.code === \"menu_version_stale\")\n ) {\n void refresh().catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n });\n } catch (error) {\n if (seq === revision && attempt === quoteRevision) {\n const local = snapshot.issues.filter((i) => i.source === \"local\");\n publish({ issues: local, state: attention(local) });\n events.emit(\"quote_failed\", { code: asError(error).code });\n }\n throw error instanceof Error && error.name === \"AbortError\"\n ? error\n : asError(error);\n }\n },\n applyFix(problem, fix = problem.fixes[0]) {\n if (\n !snapshot.issues.includes(problem) ||\n !fix ||\n !problem.fixes.some((f) => JSON.stringify(f) === JSON.stringify(fix))\n ) {\n throw new ZappieError(\n \"invalid_request\",\n \"Choose a current cart issue and one of its fixes\",\n );\n }\n switch (fix.action) {\n case \"remove_line\": {\n if (problem.lineId) {\n cart.remove(problem.lineId);\n }\n return;\n }\n case \"remove_promo\":\n cart.setPromoCode(null);\n return;\n case \"set_quantity\": {\n if (problem.lineId) {\n cart.update(problem.lineId, { quantity: fix.quantity });\n }\n return;\n }\n case \"accept_price\": {\n quotes?.accept(problem);\n const issues = snapshot.issues.filter((i) => i !== problem);\n const quote =\n \"quote\" in snapshot.state ? snapshot.state.quote : undefined;\n const accepted = quote\n ? {\n ...quote,\n issues: quote.issues.filter(\n (i) =>\n !(i.code === problem.code && i.lineId === problem.lineId),\n ),\n }\n : undefined;\n publish({ issues, state: attention(issues, accepted) });\n return;\n }\n case \"choose_region\":\n throw new ZappieError(\n \"invalid_request\",\n \"Choose a delivery region and call setFulfilment with deliveryRegionId\",\n );\n default:\n throw new ZappieError(\n \"invalid_request\",\n `${fix.action} needs the shopper's selection; use update or setFulfilment`,\n );\n }\n },\n toCheckoutPayload() {\n ensure();\n const blocking = snapshot.issues.filter((i) => i.severity === \"blocking\");\n if (!snapshot.lines.length || !snapshot.fulfilment) {\n blocking.push(\n issue(\n \"fulfilment_unavailable\",\n \"Add items and select fulfilment before checkout\",\n ),\n );\n }\n if (blocking.length) {\n throw new ZappieCartError(blocking);\n }\n return {\n lines: snapshot.lines.map(wireLine),\n fulfilment: structuredClone(snapshot.fulfilment!),\n ...(snapshot.promoCode ? { promo_code: snapshot.promoCode } : {}),\n menu_version: menu!.version,\n };\n },\n };\n return {\n cart: Object.freeze(cart),\n cartCatalogue: () => menu,\n setLegacyReader(reader: NonNullable<typeof legacy>) {\n legacy = reader;\n },\n };\n}\n"],
5
- "mappings": ";AAEA,SAAS,SAAS,mBAAmB;AAErC,SAAS,eAAe,gBAAgB;AAExC,SAAS,aAAa;AAEtB,SAAS,uBAAuB;AAChC,SAAS,yBAAyB;AAElC,SAAS,YAAY,WAAW,iBAAiB;AAEjD,SAAS,mBAAmB,WAAW,uBAAuB;AAS9D;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,gBAAgB,gBAAgB;AAElC,IAAM,aAA2B,OAAO,OAAO;AAAA,EACpD,OAAO,OAAO,OAAO,CAAC,CAAC;AAAA,EACvB,OAAO;AAAA,EACP,UAAU;AAAA,EACV,YAAY;AAAA,EACZ,WAAW;AAAA,EACX,OAAO,EAAE,QAAQ,QAAiB;AAAA,EAClC,QAAQ,OAAO,OAAO,CAAC,CAAC;AAAA,EACxB,YAAY;AACd,CAAC;AACD,SAAS,WAAc,OAAa;AAClC,MAAI,SAAS,OAAO,UAAU,YAAY,CAAC,OAAO,SAAS,KAAK,GAAG;AACjE,WAAO,OAAO,KAAK;AACnB,eAAW,SAAS,OAAO,OAAO,KAAK,GAAG;AACxC,iBAAW,KAAK;AAAA,IAClB;AAAA,EACF;AACA,SAAO;AACT;AACA,SAAS,SAAS,OAAsB;AACtC,SAAO,KAAK,UAAU;AAAA,IACpB,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM,QAAQ;AAAA,IACd,CAAC,GAAI,MAAM,WAAW,CAAC,CAAE,EAAE;AAAA,MACzB,CAAC,GAAG,MACF,EAAE,QAAQ,cAAc,EAAE,OAAO,KACjC,EAAE,SAAS,cAAc,EAAE,QAAQ;AAAA,IACvC;AAAA,IACA,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;AAAA,EAC1E,CAAC;AACH;AACO,SAAS,WAAW,MAQxB;AACD,QAAM,EAAE,QAAQ,MAAM,OAAO,OAAO,OAAO,IAAI;AAC/C,QAAM,MAAM,OAAO,MAAM,OAAO,IAAI,KAAK,KAAK,KAAK;AACnD,MAAI,CAAC,OAAO,SAAS,GAAG,KAAK,OAAO,GAAG;AACrC,UAAM,IAAI;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,EACF;AACA,MAAI,WAAW;AACf,MAAI;AACJ,MAAI;AACJ,MAAI,WAAW,OAAO;AACtB,MAAI,YAAY;AAChB,MAAI;AACJ,MAAI,WAAW;AACf,MAAI,gBAAgB;AACpB,MAAI,eAAe;AACnB,MAAI,kBAAkB;AACtB,MAAI,UAAU;AACd,MAAI;AACJ,MAAI;AACJ,MAAI,YAAY;AAChB,MAAI;AAEJ,QAAM,YAAY,oBAAI,IAAgB;AACtC,QAAM,SAAS,kBAAkB,OAAO,KAAK;AAC7C,QAAM,QAAQ,OAAO,MAAM;AAC3B,QAAM,SAAS,CAAC,OAAe,GAAG,MAAM,GAAG,EAAE,GAAG,QAAQ,IAAI,KAAK,KAAK,EAAE;AACxE,QAAM,MAAM,MAAM,OAAO,OAAQ,EAAE;AACnC,QAAM,UAAU;AAAA,IAAkB,OAAO;AAAA,IAAS,CAAC,YACjD,OAAO,KAAK,WAAW,EAAE,QAAQ,CAAC;AAAA,EACpC;AAEA,QAAM,YAAY,CAAC,OAAe;AAChC,QAAI,MAAM,QAAQ,KAAK,OAAO,EAAE,CAAC;AACjC,QAAI,QAAQ,QAAQ,OAAO;AACzB,YAAM,QAAQ,KAAK,SAAS,EAAE;AAC9B,UAAI,QAAQ,MAAM;AAChB,gBAAQ,OAAO,SAAS,EAAE;AAC1B,gBAAQ,MAAM,OAAO,EAAE,GAAG,GAAG;AAAA,MAC/B;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAEA,MAAI;AACJ,MAAI;AACJ,QAAM,cAAc,MACjB,kCAAkB,OAAO,mBAAgB,EAAE;AAAA,IAC1C,CAAC,EAAE,kBAAkB,MAClB,SAAS,kBAAkB,KAAK,WAAW,KAAK,OAAO;AAAA,IAC1D,CAAC,UAAmB;AAElB,sBAAgB;AAChB,YAAM;AAAA,IACR;AAAA,EACF;AACF,QAAM,UAAU,CAAC,UAAiC;AAChD,eAAW,WAAW;AAAA,MACpB,GAAG;AAAA,MACH,GAAG;AAAA,MACH,UAAU,QAAQ;AAAA,IACpB,CAAC;AACD,eAAW,MAAM,CAAC,GAAG,SAAS,GAAG;AAC/B,UAAI;AACF,WAAG;AAAA,MACL,SAAS,OAAO;AACd,eAAO,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,EAAE,CAAC;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AACA,QAAM,YAAY,CAChB,QACA,UAEA,OAAO,KAAK,CAAC,MAAM,EAAE,aAAa,MAAM,IACpC,EAAE,QAAQ,mBAAmB,QAAQ,GAAI,QAAQ,EAAE,MAAM,IAAI,CAAC,EAAG,IACjE,QACE,EAAE,QAAQ,UAAU,MAAM,IAC1B,EAAE,QAAQ,QAAQ;AAC1B,QAAM,SAAS,MAAM;AACnB;AACA;AACA,iBAAa,KAAK;AAClB,YAAQ,OAAO;AAAA,EACjB;AACA,QAAM,UAAU,MAAM;AACpB,UAAM,QAAoB;AAAA,MACxB,GAAG;AAAA,MACH,OAAO,SAAS,MAAM,IAAI,CAAC,UAAU;AAAA,QACnC,GAAG,UAAU,IAAI;AAAA,QACjB,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,SAAS,KAAK;AAAA,QACd,WAAW,KAAK;AAAA,MAClB,EAAE;AAAA,MACF,YAAY,SAAS;AAAA,MACrB,WAAW,SAAS;AAAA,MACpB,aAAa,KAAM;AAAA,MACnB;AAAA,IACF;AACA,YAAQ,MAAM,IAAI,GAAG,KAAK,UAAU,KAAK,CAAC;AAAA,EAC5C;AACA,QAAM,WAAW,MAAM;AACrB,iBAAa,KAAK;AAClB,QAAI,SAAS,MAAM,QAAQ;AACzB,cAAQ,WAAW,MAAM;AACvB,aAAK,KAAK,MAAM,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAClC,GAAG,GAAG;AAAA,IACR;AAAA,EACF;AACA,QAAM,YAAY,CAChB,OACA,UAAU,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO,GAC5D,QAA+B,CAAC,MAC7B;AACH,UAAM,WAAW,MAAM,KAAK,EAAG;AAC/B,UAAM,SAAS,UAAU,OAAO,MAAO,QAAS,UAAU,OAAO;AACjE,UAAM,WAAW,OAAO,SACpB;AAAA,MACE,OAAO,MAAM,IAAI,CAAC,MAAM,EAAE,YAAY;AAAA,MACtC,MAAM,GAAG,QAAQ;AAAA,IACnB,IACA;AACJ,YAAQ;AAAA,MACN,GAAG;AAAA,MACH,OAAO,OAAO;AAAA,MACd,OAAO,OAAO,MAAM,OAAO,CAAC,GAAG,MAAM,IAAI,EAAE,UAAU,CAAC;AAAA,MACtD;AAAA,MACA,QAAQ,OAAO;AAAA,MACf,OAAO,UAAU,OAAO,MAAM;AAAA,IAChC,CAAC;AACD,eAAW,KAAK,OAAO,QAAQ;AAC7B,aAAO,KAAK,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,IAC5C;AAAA,EACF;AACA,QAAM,UAAU,CACd,QAA4C,SAAS,OACrD,QAA+B,CAAC,MAC7B;AACH,WAAO;AACP,cAAU,OAAO,QAAW,KAAK;AACjC,gBAAY,KAAK,IAAI;AACrB,YAAQ;AACR,aAAS;AAAA,EACX;AACA,QAAM,SAAS,CAAC,UAAgB;AAC9B,UAAM,QAAQ,MAAM,KAAK,GAAG,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM,QAAQ;AACxE,QAAI,CAAC,OAAO;AACV,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO;AACP,aAAS;AACT,eAAW,MAAM;AAAA,EACnB;AACA,QAAM,OAAO,CAAC,KAAoB,YAAY,SAAS;AACrD,WAAO;AACP,QAAI;AACJ,QAAI;AACF,cAAQ,MAAM,UAAU,GAAG,IAAI;AAC/B,UAAI,SAAS,KAAK,IAAI,IAAI,MAAM,YAAY,KAAK;AAC/C,gBAAQ;AACR,gBAAQ,OAAO,IAAI,CAAC;AACpB,eAAO,KAAK,gBAAgB,EAAE,UAAU,OAAQ,GAAG,CAAC;AAAA,MACtD;AAAA,IACF,QAAQ;AACN,cAAQ,OAAO,IAAI,CAAC;AACpB,cAAQ,QAAQ,8BAA8B;AAAA,IAChD;AACA,gBAAY,OAAO,aAAa,KAAK,IAAI;AACzC,UAAM,OAAO,KAAK,IAAI,IAAI;AAC1B,QAAI,aAAa,OAAO,cAAc;AACtC,QACE,YAAY,aAAa,OAAQ,MAChC,OAAO,SAAc,WAAW,SAAS,YAC1C;AACA,mBAAa;AAAA,IACf;AACA,QACE,cACA,kBAAkB,cAClB,WAAW,gBACX,KAAK,MAAM,WAAW,YAAY,IAAI,KAAK,IAAI,GAC/C;AACA,mBAAa,EAAE,GAAG,WAAW;AAC7B,aAAO,WAAW;AAAA,IACpB;AACA,UAAM,SAAS,OAAO,SAAS,CAAC,GAAG,IAAI,CAAC,UAAU;AAAA,MAChD,GAAG;AAAA,MACH,GAAI,OAAO,QAAa,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC;AAAA,IAC5C,EAAE;AACF,UAAM,SAAS,UAAU,OAAO,MAAO,QAAS,MAAM,KAAK,EAAG,QAAQ;AACtE,cAAU,OAAO,OAAO,OAAO,QAAQ;AAAA,MACrC;AAAA,MACA,WAAW,OAAO,aAAa;AAAA,MAC/B,YAAY;AAAA,IACd,CAAC;AAED,QAAI,QAAQ,QAAQ,WAAW;AAC7B,cAAQ;AAAA,IACV;AACA,YAAQ,MAAM,QAAQ,IAAI,GAAG,GAAG;AAAA,EAClC;AACA,QAAM,SAAS,MAAM;AACnB,UAAM,KACJ,QAAQ,MACR,MACG,KAAK,GACJ,SAAS;AAAA,MACT,CAAC,MACC,EAAE,OAAO,YACT,EAAE,SAAS,YACV,CAAC,YAAY,EAAE;AAAA,IACpB,GAAG,OACJ,CAAC,WAAW,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,KAAK;AAC/C,QAAI,SAAS,YAAY;AACvB;AAAA,IACF;AACA,UAAM,SAAS,SAAS,KAAK,KAAK,WAAW,KAAK,IAAI,CAAC,CAAC,IAAI;AAC5D,QAAI,CAAC,UAAU,CAAC,MAAM,KAAK,GAAG;AAC5B,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO,MAAM;AACb,UAAM,MAAM,UAAU,OAAQ,EAAE;AAChC,QAAI,WAA4B,CAAC;AACjC,QAAI,QAAQ,QAAQ,QAAQ;AAC1B,UAAI;AACF,mBAAW,OAAO,QAAQ,IAAI;AAAA,MAChC,QAAQ;AACN,gBAAQ,QAAQ,+BAA+B;AAAA,MACjD;AAAA,IACF;AACA,SAAK,GAAG;AACR,QAAI,QAAQ,QAAQ,QAAQ;AAC1B,cAAQ;AAAA,IACV;AACA,eAAW,SAAS,SAAS,MAAM,GAAG,GAAG,GAAG;AAC1C,UAAI;AACF,aAAK,IAAI,MAAM,QAAQ,KAAK;AAAA,MAC9B,QAAQ;AACN,eAAO,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAAA,MACxD;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,YAAY;AAC1B,UAAM,KAAK,QAAQ;AACnB,UAAM,MAAM;AACZ,UAAM,UAAU,EAAE;AAClB,UAAM,MAAM;AACZ,QAAI,CAAC,MAAM,CAAC,MAAM;AAChB;AAAA,IACF;AACA,QAAI,CAAC,SAAS,MAAM,QAAQ;AAC1B;AAAA,IACF;AACA,QAAI,KAAK,iBAAiB,WAAW;AACnC,YAAM,UAAU,MAAM,KAAK,UAAU,eAAe;AAAA,QAClD,GAAG,KAAK,QAAQ;AAAA,QAChB,UAAU;AAAA,MACZ,CAAC;AACD,UAAI,QAAQ,YAAY,KAAK,SAAS;AACpC;AAAA,MACF;AAAA,IACF;AACA,UAAM,QAAQ,MAAM,KAAK,WAAW;AAAA,MAClC;AAAA,MACA,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MAClC;AAAA,IACF;AACA,QACE,QAAQ,gBACR,YAAY,mBACZ,QAAQ,YACR,KAAK,UAAU,KAAK,MAAM,KAAK,UAAU,IAAI,GAC7C;AACA;AAAA,IACF;AACA,WAAO;AACP,WAAO;AACP,cAAU,SAAS,KAAK;AACxB,YAAQ;AACR,aAAS;AAAA,EACX;AAIA,QAAM,UAAU,CAAC,WAAmB;AAClC,UAAM,YAAY,KAAK,WAAW,KAAK,OAAQ,IAAI;AAAA,MACjD,GAAG,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACrC;AAAA,IACF,CAAC;AACD,QAAI,UAAU,MAAM,MAAM,GAAG;AAC3B,aAAO;AAAA,IACT;AAAA,EACF;AACA,QAAM,YAAY,CAChB,KACA,IACA,YACa;AACb,YAAQ,IAAI,MAAM;AAClB,UAAM,OAAO,OAAO,OAAO,KAAM,OAAO,IAAI,MAAM,IAC9C,KAAM,MAAM,IAAI,MAAM,IACtB;AACJ,UAAM,WAAW,aAAa,MAAM,KAAK,EAAE,MAAa,OAAgB,CAAC;AACzE,QAAI,SAAS,UAAU,CAAC,MAAM;AAC5B,YAAM,IAAI,gBAAgB,QAAQ;AAAA,IACpC;AACA,UAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,UAAM,UAAU,eAAe,MAAM,KAAK;AAC1C,UAAM,WAAW,MAAM,WAAW,CAAC,GAAG,IAAI,CAAC,OAAO;AAAA,MAChD,GAAG;AAAA,MACH,UAAU,EAAE,YAAY;AAAA,IAC1B,EAAE;AACF,UAAM,YAAY,kBAAkB,MAAM;AAAA,MACxC;AAAA,MACA,WAAW,QAAQ;AAAA,IACrB,CAAC;AACD,WAAO,WAAW;AAAA,MAChB,IACE,MACA,QAAQ,MAAM,KAAK,WAAW,OAAO,gBAAgB,IAAI,WAAW,EAAE,CAAC,GAAG,CAAC,SAAS,mEAAmE,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;AAAA,MAC7K,QAAQ,KAAK;AAAA,MACb,GAAI,MAAM,WAAW,SAAY,EAAE,QAAQ,MAAM,OAAO,IAAI,CAAC;AAAA,MAC7D,MAAM,KAAK;AAAA,MACX,UAAU,MAAM;AAAA,MAChB;AAAA,MACA,QAAQ,MAAM,UAAU,CAAC;AAAA,MACzB,WAAW,QAAQ;AAAA,MACnB,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,KAAK,IAAI,CAAC;AAAA,MACvD;AAAA,MACA,cAAc,cAAc,WAAW,MAAM,QAAS;AAAA,MACtD,SAAS,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IAC7C,CAAC;AAAA,EACH;AACA,QAAM,UAAU,OAAO,GAAG,gBAAgB,CAAC,EAAE,UAAU,QAAQ,MAAM;AACnE,QAAI,QAAQ,OAAO,UAAU;AAC3B,YAAM,QAAQ,MAAM,KAAK,QAAQ;AACjC,UACE,SACA,MAAM,iBAAiB,aACvB,MAAM,YAAY,WAClB,MAAM,YAAY,MAAM,SACxB;AACA;AACA,eAAO;AACP,eAAO;AACP,kBAAU,SAAS,KAAK;AACxB,gBAAQ;AACR,iBAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,CAAC;AACD,QAAM,OAAmB;AAAA,IACvB,IAAI,WAAW;AACb,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,QAAQ;AACV,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,QAAQ;AACV,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,WAAW;AACb,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,aAAa;AACf,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,YAAY;AACd,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,QAAQ;AACV,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,SAAS;AACX,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,IAAI,aAAa;AACf,aAAO,SAAS;AAAA,IAClB;AAAA,IACA,aAAa,MAAM;AAAA,IACnB,UAAU,IAAI;AACZ,gBAAU,IAAI,EAAE;AAChB,aAAO,MAAM;AACX,kBAAU,OAAO,EAAE;AAAA,MACrB;AAAA,IACF;AAAA,IACA,MAAM,UAAU;AACd,UAAI,SAAS,YAAY;AACvB,eAAO,QAAQ;AAAA,MACjB;AACA,YAAM,OAAO;AACb,iCAAe,YAAY;AACzB,cAAM,QAAQ,MAAM,MAAM,IAAI;AAC9B,cAAM,SACJ,MAAM,SAAS;AAAA,UACb,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,SAAS;AAAA,QACzC,MACC,CAAC,WACG,MAAM,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,KAAK,MAAM,SAAS,CAAC,IAC5D;AACN,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,YAAI,SAAwC,SAAS;AACrD,YAAI,CAAC,SAAS,YAAY;AACxB,gBAAM,MAAM,UAAU,OAAO,EAAE;AAC/B,cAAI;AACF,kBAAM,QAAQ,MAAM,UAAU,GAAG,IAAI;AACrC,qBACE,SAAS,KAAK,IAAI,IAAI,MAAM,aAAa,MACrC,MAAM,QACN,QAAQ,OACL,SAAS,QAAQ,IAAI,KAAK,CAAC,IAC5B,CAAC;AAAA,UACX,QAAQ;AACN,qBAAS,CAAC;AAAA,UACZ;AAAA,QACF;AACA,cAAM,SAAS,MAAM,KAAK,WAAW;AAAA,UACnC,OAAO;AAAA,UACP,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,QAC5B;AACA,YAAI,SAAS,WAAW;AACtB;AAAA,QACF;AACA,eAAO,MAAM;AACb,eAAO;AACP,YAAI,OAAO,iBAAiB,WAAW;AACrC,gBAAM,QAAQ;AAAA,QAChB;AAAA,MACF,GAAG,EAAE,QAAQ,MAAM;AACjB,oBAAY;AAAA,MACd,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,QAAQ;AACN;AACA,UAAI,CAAC,UAAU,OAAO,WAAW,aAAa;AAC5C,cAAM,YAAY,CAAC,UAAwB;AACzC,cACE,UACA,MAAM,QAAQ,IAAI,KAClB,QAAQ,QAAQ,MAAM,WAAW,GACjC;AACA,kBAAM,MAAM,MAAM;AAClB,gBAAI;AACJ,gBAAI;AACF,oBAAM,MAAM,UAAU,GAAG,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC;AAAA,YAC3D,QAAQ;AACN,mBAAK,KAAK,KAAK;AACf;AAAA,YACF;AACA,kBAAM,SAAS,KAAK,WAAW,KAAK,OAAO,IAAI,GAAG;AAClD,gBACE,OAAO,iBAAiB,aACxB,IAAI,MAAM,CAAC,OAAO,OAAO,MAAM,EAAE,CAAC,GAClC;AACA,qBAAO;AACP,mBAAK,KAAK,KAAK;AACf,uBAAS;AACT;AAAA,YACF;AACA,kBAAM,MAAM;AACZ,kBAAM,UAAU,EAAE;AAClB,kBAAM,OAAO;AACb,iBAAK,KAAK,WACP,KAAK,OAAO,IAAI,GAAG,EACnB,KAAK,CAAC,UAAU;AACf,kBACE,SAAS,aACT,QAAQ,YACR,YAAY,iBACZ;AACA,uBAAO;AACP,qBAAK,KAAK,KAAK;AACf,yBAAS;AAAA,cACX;AAAA,YACF,CAAC,EACA;AAAA,cAAM,CAAC,UACN,OAAO,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,EAAE,CAAC;AAAA,YAChD;AAAA,UACJ;AAAA,QACF;AACA,cAAM,UAAU,MAAM;AACpB,eAAK,QAAQ,EAAE;AAAA,YAAM,CAAC,UACpB,OAAO,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,EAAE,CAAC;AAAA,UAChD;AAAA,QACF;AACA,eAAO,iBAAiB,WAAW,SAAS;AAC5C,eAAO,iBAAiB,SAAS,OAAO;AAExC,iBAAS,MAAM;AACb,iBAAO,oBAAoB,WAAW,SAAS;AAC/C,iBAAO,oBAAoB,SAAS,OAAO;AAAA,QAC7C;AAAA,MACF;AACA,UAAI,YAAY,GAAG;AACjB,aAAK,KACF,QAAQ,EACR;AAAA,UAAM,CAAC,UACN,OAAO,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,EAAE,CAAC;AAAA,QAChD;AAAA,MACJ;AACA,UAAI,SAAS;AACb,aAAO,MAAM;AACX,YAAI,QAAQ;AACV,mBAAS;AACT;AACA,cAAI,YAAY,GAAG;AACjB,qBAAS;AACT,qBAAS;AACT,mBAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IACA,UAAU;AACR;AACA;AACA,cAAQ;AACR,aAAO;AACP,eAAS;AACT,eAAS;AACT,gBAAU,MAAM;AAAA,IAClB;AAAA,IACA,SAAS,OAAO;AACd,aAAO;AACP,cAAQ,MAAM,MAAM;AACpB,YAAM,WAAW;AAAA,QACf,OAAO,OAAO,KAAM,OAAO,MAAM,MAAM,IACnC,KAAM,MAAM,MAAM,MAAM,IACxB;AAAA,QACJ;AAAA,QACA,EAAE,MAAa,OAAgB;AAAA,MACjC;AACA,aAAO,SAAS,SAAS,EAAE,IAAI,OAAO,QAAQ,SAAS,IAAI,EAAE,IAAI,KAAK;AAAA,IACxE;AAAA,IACA,IAAI,MAAM,QAAQ,CAAC,GAAG;AACpB,aAAO;AACP,UAAI,OAAO,UAAU;AAAA,QACnB,GAAG;AAAA,QACH,QAAQ,OAAO,SAAS,WAAW,OAAO,KAAK;AAAA,MACjD,CAAC;AACD,YAAM,WAAW,SAAS,MAAM;AAAA,QAC9B,CAAC,MAAM,SAAS,UAAU,CAAC,CAAC,MAAM,SAAS,UAAU,IAAI,CAAC;AAAA,MAC5D;AACA,UAAI,UAAU;AACZ,eAAO;AAAA,UACL,EAAE,GAAG,UAAU,IAAI,GAAG,UAAU,SAAS,WAAW,KAAK,SAAS;AAAA,UAClE,SAAS;AAAA,UACT,SAAS;AAAA,QACX;AAAA,MACF,WAAW,SAAS,MAAM,UAAU,KAAK;AACvC,cAAM,IAAI,gBAAgB;AAAA,UACxB,MAAM,kBAAkB,sCAAsC;AAAA,QAChE,CAAC;AAAA,MACH;AACA;AAAA,QACE,WACI,SAAS,MAAM,IAAI,CAAC,MAAO,EAAE,OAAO,SAAS,KAAK,OAAO,CAAE,IAC3D,CAAC,GAAG,SAAS,OAAO,IAAI;AAAA,MAC9B;AACA,aAAO,KAAK,eAAe;AAAA,QACzB,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK,YAAY,UAAU,YAAY;AAAA,QACjD,OAAO;AAAA,UACL,KAAK;AAAA,UACL,KAAK,YAAY,UAAU,YAAY;AAAA,QACzC;AAAA,MACF,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,OAAO,QAAQ,OAAO;AACpB,aAAO;AACP,YAAM,MAAM,SAAS,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AACtD,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,gBAAgB;AAAA,UACxB,MAAM,kBAAkB,qBAAqB;AAAA,QAC/C,CAAC;AAAA,MACH;AACA,YAAM,QAAQ,EAAE,GAAG,UAAU,GAAG,GAAG,GAAG,MAAM;AAC5C,UAAI,MAAM,WAAW,CAAC,MAAM,WAAW;AACrC,eAAO,MAAM;AAAA,MACf;AACA,UAAI,OAAO,UAAU,OAAO,IAAI,IAAI,IAAI,OAAO;AAC/C,YAAM,YAAY,SAAS,MAAM;AAAA,QAC/B,CAAC,MACC,EAAE,OAAO,UACT,SAAS,UAAU,CAAC,CAAC,MAAM,SAAS,UAAU,IAAI,CAAC;AAAA,MACvD;AACA,UAAI,WAAW;AACb,eAAO;AAAA,UACL,EAAE,GAAG,UAAU,IAAI,GAAG,UAAU,KAAK,WAAW,UAAU,SAAS;AAAA,UACnE,IAAI;AAAA,UACJ,IAAI;AAAA,QACN;AAAA,MACF;AACA;AAAA,QACE,SAAS,MACN,OAAO,CAAC,MAAM,EAAE,OAAO,WAAW,EAAE,EACpC,IAAI,CAAC,MAAO,EAAE,OAAO,SAAS,OAAO,CAAE;AAAA,MAC5C;AACA,aAAO,KAAK,oBAAoB;AAAA,QAC9B;AAAA,QACA,QAAQ,KAAK;AAAA,QACb,UAAU,KAAK;AAAA,MACjB,CAAC;AACD,aAAO;AAAA,IACT;AAAA,IACA,OAAO,QAAQ;AACb,aAAO;AACP,YAAM,OAAO,SAAS,MAAM,KAAK,CAAC,MAAM,EAAE,OAAO,MAAM;AACvD,cAAQ,SAAS,MAAM,OAAO,CAAC,MAAM,EAAE,OAAO,MAAM,CAAC;AACrD,UAAI,MAAM;AACR,eAAO,KAAK,oBAAoB;AAAA,UAC9B,QAAQ,KAAK;AAAA,UACb,UAAU,KAAK;AAAA,UACf,OAAO,KAAK;AAAA,QACd,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,QAAQ;AACN,aAAO;AACP,cAAQ,CAAC,GAAG,EAAE,YAAY,MAAM,WAAW,KAAK,CAAC;AAAA,IACnD;AAAA,IACA,cAAc,OAAO;AACnB,aAAO;AACP,UAAI,CAAC,gBAAgB,KAAK,KAAK,MAAM,aAAa,OAAQ,IAAI;AAC5D,cAAM,IAAI,gBAAgB;AAAA,UACxB;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,cAAQ,SAAS,OAAO,EAAE,YAAY,gBAAgB,KAAK,EAAE,CAAC;AAAA,IAChE;AAAA,IACA,aAAa,MAAM;AACjB,aAAO;AACP,cAAQ,SAAS,OAAO,EAAE,WAAW,MAAM,KAAK,KAAK,KAAK,CAAC;AAAA,IAC7D;AAAA,IACA,MAAM,OAAO,UAAU;AACrB,aAAO;AACP,YAAM,MAAM,EAAE;AACd,aAAO;AACP,cAAQ,EAAE,OAAO,UAAU,SAAS,MAAM,EAAE,CAAC;AAC7C,YAAM,QAAQ,MAAM,KAAK,WAAW;AAAA,QAClC;AAAA,QACA,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM;AAAA,MACpC;AACA,UAAI,QAAQ,cAAc;AACxB;AAAA,MACF;AACA,YAAM,SAAS,IAAI;AACnB,YAAM,WAAW,SAAS;AAC1B,aAAO,KAAK;AACZ,YAAM,OAAO,SAAS;AAAA,QACpB,CAAC,SACC,CAAC,aAAa,MAAM,MAAM,KAAK,MAAM,GAAG,UAAU,IAAI,GAAG;AAAA,UACvD,MAAM;AAAA,UACN;AAAA,QACF,CAAC,EAAE;AAAA,MACP;AACA,cAAQ,MAAM,EAAE,YAAY,MAAM,WAAW,KAAK,CAAC;AACnD,YAAM,UAAU,SACb,OAAO,CAAC,SAAS,CAAC,KAAK,SAAS,IAAI,CAAC,EACrC,IAAI,CAAC,UAAU;AAAA,QACd,GAAG;AAAA,UACD;AAAA,UACA,GAAG,KAAK,IAAI;AAAA,QACd;AAAA,QACA,UAAU;AAAA,QACV,QAAQ,KAAK;AAAA,MACf,EAAE;AACJ,YAAM,SAAS,CAAC,GAAG,SAAS,QAAQ,GAAG,OAAO;AAC9C,cAAQ,EAAE,QAAQ,OAAO,UAAU,MAAM,EAAE,CAAC;AAC5C,UAAI,WAAW,IAAI,GAAG;AACpB,gBAAQ,OAAO,MAAM;AAAA,MACvB;AAAA,IACF;AAAA,IACA,MAAM,MAAM,OAAO,CAAC,GAAG;AACrB,aAAO;AACP,mBAAa,KAAK;AAClB,UAAI,KAAK,OAAO;AACd,eAAO,KAAK,aAAa,CAAC,CAAC;AAAA,MAC7B;AACA,YAAM,OAAO;AAAA,QACX,WAAW,OAAQ;AAAA,QACnB,OAAO,SAAS,MAAM,IAAI,QAAQ;AAAA,QAClC,GAAI,SAAS,aACT,EAAE,YAAY,eAAe,SAAS,UAAU,EAAE,IAClD,CAAC;AAAA,QACL,GAAI,SAAS,YAAY,EAAE,YAAY,SAAS,UAAU,IAAI,CAAC;AAAA,QAC/D,cAAc,KAAM;AAAA,MACtB;AACA,YAAM,MAAM;AACZ,YAAM,UAAU,EAAE;AAClB,cAAQ,EAAE,OAAO,EAAE,QAAQ,UAAU,EAAE,CAAC;AACxC,UAAI;AACF,cAAM,SAAS,MAAM,YAAY;AACjC,eAAO,MAAM,OAAO,IAAI,MAAM,KAAK,SAAS,OAAO,CAAC,UAAU;AAC5D,cAAI,QAAQ,UAAU;AACpB;AAAA,UACF;AACA,gBAAM,QAAQ,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAEhE,gBAAM,SAAS,MAAM,OAAO;AAAA,YAC1B,CAAC,MACC,CAAC,MAAM;AAAA,cACL,CAAC,MACC,EAAE,SAAS,EAAE,QACb,EAAE,WAAW,EAAE,UACf,EAAE,YAAY,EAAE;AAAA,YACpB;AAAA,UACJ;AACA,gBAAM,SAAS,CAAC,GAAG,OAAO,GAAG,MAAM;AACnC,kBAAQ,EAAE,QAAQ,OAAO,UAAU,QAAQ,KAAK,EAAE,CAAC;AACnD,qBAAW,KAAK,QAAQ;AACtB,mBAAO,KAAK,cAAc,EAAE,MAAM,EAAE,KAAK,CAAC;AAAA,UAC5C;AAGA,cACE,MAAM,gBAAgB,KAAM,WAC5B,MAAM,OAAO,KAAK,CAAC,MAAM,EAAE,SAAS,oBAAoB,GACxD;AACA,iBAAK,QAAQ,EAAE;AAAA,cAAM,CAAC,UACpB,OAAO,KAAK,SAAS,EAAE,OAAO,QAAQ,KAAK,EAAE,CAAC;AAAA,YAChD;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,SAAS,OAAO;AACd,YAAI,QAAQ,YAAY,YAAY,eAAe;AACjD,gBAAM,QAAQ,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,OAAO;AAChE,kBAAQ,EAAE,QAAQ,OAAO,OAAO,UAAU,KAAK,EAAE,CAAC;AAClD,iBAAO,KAAK,gBAAgB,EAAE,MAAM,QAAQ,KAAK,EAAE,KAAK,CAAC;AAAA,QAC3D;AACA,cAAM,iBAAiB,SAAS,MAAM,SAAS,eAC3C,QACA,QAAQ,KAAK;AAAA,MACnB;AAAA,IACF;AAAA,IACA,SAAS,SAAS,MAAM,QAAQ,MAAM,CAAC,GAAG;AACxC,UACE,CAAC,SAAS,OAAO,SAAS,OAAO,KACjC,CAAC,OACD,CAAC,QAAQ,MAAM,KAAK,CAAC,MAAM,KAAK,UAAU,CAAC,MAAM,KAAK,UAAU,GAAG,CAAC,GACpE;AACA,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,cAAQ,IAAI,QAAQ;AAAA,QAClB,KAAK,eAAe;AAClB,cAAI,QAAQ,QAAQ;AAClB,iBAAK,OAAO,QAAQ,MAAM;AAAA,UAC5B;AACA;AAAA,QACF;AAAA,QACA,KAAK;AACH,eAAK,aAAa,IAAI;AACtB;AAAA,QACF,KAAK,gBAAgB;AACnB,cAAI,QAAQ,QAAQ;AAClB,iBAAK,OAAO,QAAQ,QAAQ,EAAE,UAAU,IAAI,SAAS,CAAC;AAAA,UACxD;AACA;AAAA,QACF;AAAA,QACA,KAAK,gBAAgB;AACnB,kBAAQ,OAAO,OAAO;AACtB,gBAAM,SAAS,SAAS,OAAO,OAAO,CAAC,MAAM,MAAM,OAAO;AAC1D,gBAAM,QACJ,WAAW,SAAS,QAAQ,SAAS,MAAM,QAAQ;AACrD,gBAAM,WAAW,QACb;AAAA,YACE,GAAG;AAAA,YACH,QAAQ,MAAM,OAAO;AAAA,cACnB,CAAC,MACC,EAAE,EAAE,SAAS,QAAQ,QAAQ,EAAE,WAAW,QAAQ;AAAA,YACtD;AAAA,UACF,IACA;AACJ,kBAAQ,EAAE,QAAQ,OAAO,UAAU,QAAQ,QAAQ,EAAE,CAAC;AACtD;AAAA,QACF;AAAA,QACA,KAAK;AACH,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACE,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,GAAG,IAAI,MAAM;AAAA,UACf;AAAA,MACJ;AAAA,IACF;AAAA,IACA,oBAAoB;AAClB,aAAO;AACP,YAAM,WAAW,SAAS,OAAO,OAAO,CAAC,MAAM,EAAE,aAAa,UAAU;AACxE,UAAI,CAAC,SAAS,MAAM,UAAU,CAAC,SAAS,YAAY;AAClD,iBAAS;AAAA,UACP;AAAA,YACE;AAAA,YACA;AAAA,UACF;AAAA,QACF;AAAA,MACF;AACA,UAAI,SAAS,QAAQ;AACnB,cAAM,IAAI,gBAAgB,QAAQ;AAAA,MACpC;AACA,aAAO;AAAA,QACL,OAAO,SAAS,MAAM,IAAI,QAAQ;AAAA,QAClC,YAAY,gBAAgB,SAAS,UAAW;AAAA,QAChD,GAAI,SAAS,YAAY,EAAE,YAAY,SAAS,UAAU,IAAI,CAAC;AAAA,QAC/D,cAAc,KAAM;AAAA,MACtB;AAAA,IACF;AAAA,EACF;AACA,SAAO;AAAA,IACL,MAAM,OAAO,OAAO,IAAI;AAAA,IACxB,eAAe,MAAM;AAAA,IACrB,gBAAgB,QAAoC;AAClD,eAAS;AAAA,IACX;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import type { MenuResource, StoreResource } from \"../client\";\nimport type { ZappieConfig } from \"../config\";\nimport { asError, ZappieError } from \"../errors\";\nimport type { createEmitter } from \"../internal/emitter\";\nimport { multiplyMoney, sumMoney } from \"../internal/money-math\";\nimport type { Branch, Menu } from \"../models\";\nimport { money } from \"../money\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\nimport { ZappieCartError } from \"./errors\";\nimport { estimateUnitPrice } from \"./price\";\nimport type { QuoteClient } from \"./quote-client\";\nimport { freezeLine, lineInput, reconcile } from \"./reconcile\";\nimport type { StoredCart, StoredLine } from \"./storage\";\nimport { createCartStorage, parseCart, validFulfilment } from \"./storage\";\nimport type {\n CartIssue,\n CartLine,\n CartLineInput,\n CartModule,\n CartSnapshot,\n Quote,\n} from \"./types\";\nimport {\n issue,\n normalizeInput,\n resolveVariant,\n validateLine,\n} from \"./validate\";\nimport { wireFulfilment, wireLine } from \"./wire\";\nimport type { createWorkingSet } from \"./working-set\";\nexport const EMPTY_CART: CartSnapshot = Object.freeze({\n lines: Object.freeze([]),\n count: 0,\n subtotal: null,\n fulfilment: null,\n promoCode: null,\n state: { status: \"ready\" as const },\n issues: Object.freeze([]),\n isHydrated: false,\n});\nfunction deepFreeze<T>(value: T): T {\n if (value && typeof value === \"object\" && !Object.isFrozen(value)) {\n Object.freeze(value);\n for (const child of Object.values(value)) {\n deepFreeze(child);\n }\n }\n return value;\n}\nfunction identity(input: CartLineInput) {\n return JSON.stringify([\n input.itemId,\n input.menuId,\n input.variantId,\n input.note ?? \"\",\n [...(input.choices ?? [])].sort(\n (a, b) =>\n a.groupId.localeCompare(b.groupId) ||\n a.choiceId.localeCompare(b.choiceId),\n ),\n Object.entries(input.inputs ?? {}).sort(([a], [b]) => a.localeCompare(b)),\n ]);\n}\nexport function createCart(deps: {\n workingSet: ReturnType<typeof createWorkingSet>;\n config: ZappieConfig;\n menu: MenuResource;\n store: StoreResource;\n transport: Transport;\n context: () => RequestCtx;\n events: ReturnType<typeof createEmitter>;\n}) {\n const { config, menu: menus, store, events } = deps;\n const ttl = config.cart?.ttl ?? 7 * 24 * 60 * 60 * 1000;\n if (!Number.isFinite(ttl) || ttl <= 0) {\n throw new ZappieError(\n \"invalid_request\",\n \"Cart ttl must be positive milliseconds\",\n );\n }\n let snapshot = EMPTY_CART;\n let menu: Menu | undefined;\n let branch: Branch | undefined;\n let selected = config.branch;\n let updatedAt = 0;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let revision = 0;\n let quoteRevision = 0;\n let moveSequence = 0;\n let refreshSequence = 0;\n let mounted = 0;\n let detach: (() => void) | undefined;\n let hydration: Promise<void> | undefined;\n let lifecycle = 0;\n let legacy:\n ((read: (key: string) => string | null) => CartLineInput[]) | undefined;\n const listeners = new Set<() => void>();\n const prefix = `zappie:cart:v1:${config.store}:`;\n const scope = config.cart?.storageScope;\n const keyFor = (id: string) => `${prefix}${id}${scope ? `:${scope}` : \"\"}`;\n const key = () => keyFor(branch!.id);\n const storage = createCartStorage(config.storage, (message) =>\n events.emit(\"warning\", { message }),\n );\n // A scoped cart adopts the branch's unscoped cart once, so only one scope inherits it.\n const readSaved = (id: string) => {\n let raw = storage.read(keyFor(id));\n if (raw === null && scope) {\n raw = storage.read(prefix + id);\n if (raw !== null) {\n storage.remove(prefix + id);\n storage.write(keyFor(id), raw);\n }\n }\n return raw;\n };\n // The quote client and response mapping load on the first quote; add/validate stay synchronous.\n let quotes: QuoteClient | undefined;\n let loadingQuotes: Promise<QuoteClient> | undefined;\n const quoteClient = () =>\n (loadingQuotes ??= import(\"./quote-client\").then(\n ({ createQuoteClient }) =>\n (quotes = createQuoteClient(deps.transport, deps.context, config)),\n (error: unknown) => {\n // A failed chunk load (e.g. offline) must not poison every later quote.\n loadingQuotes = undefined;\n throw error;\n },\n ));\n const publish = (patch: Partial<CartSnapshot>) => {\n snapshot = deepFreeze({\n ...snapshot,\n ...patch,\n branchId: branch?.id,\n });\n for (const fn of [...listeners]) {\n try {\n fn();\n } catch (error) {\n events.emit(\"error\", { error: asError(error) });\n }\n }\n };\n const attention = (\n issues: readonly CartIssue[],\n quote?: Quote,\n ): CartSnapshot[\"state\"] =>\n issues.some((i) => i.severity !== \"info\")\n ? { status: \"needs_attention\", issues, ...(quote ? { quote } : {}) }\n : quote\n ? { status: \"quoted\", quote }\n : { status: \"ready\" };\n const cancel = () => {\n revision++;\n quoteRevision++;\n clearTimeout(timer);\n quotes?.cancel();\n };\n const persist = () => {\n const value: StoredCart = {\n v: 1,\n lines: snapshot.lines.map((line) => ({\n ...lineInput(line),\n id: line.id,\n name: line.name,\n addedAt: line.addedAt,\n unitPrice: line.unitPrice,\n })),\n fulfilment: snapshot.fulfilment,\n promoCode: snapshot.promoCode,\n menuVersion: menu!.version,\n updatedAt,\n };\n storage.write(key(), JSON.stringify(value));\n };\n const schedule = () => {\n clearTimeout(timer);\n if (snapshot.lines.length) {\n timer = setTimeout(() => {\n void cart.quote().catch(() => {});\n }, 300);\n }\n };\n const recompute = (\n lines: readonly (CartLine | StoredLine)[],\n pending = snapshot.issues.filter((i) => i.source === \"local\"),\n patch: Partial<CartSnapshot> = {},\n ) => {\n const currency = store.peek()!.currency;\n const result = reconcile(lines, menu!, branch!, currency, pending);\n const subtotal = result.priced\n ? sumMoney(\n result.lines.map((l) => l.lineSubtotal),\n money(0, currency),\n )\n : null;\n publish({\n ...patch,\n lines: result.lines,\n count: result.lines.reduce((n, l) => n + l.quantity, 0),\n subtotal,\n issues: result.issues,\n state: attention(result.issues),\n });\n for (const i of result.issues) {\n events.emit(\"cart_issue\", { code: i.code });\n }\n };\n const changed = (\n lines: readonly (CartLine | StoredLine)[] = snapshot.lines,\n patch: Partial<CartSnapshot> = {},\n ) => {\n cancel();\n recompute(lines, undefined, patch);\n updatedAt = Date.now();\n persist();\n schedule();\n };\n const choose = (value: Menu) => {\n const found = store.peek()?.branches.find((b) => b.id === value.branchId);\n if (!found) {\n throw new ZappieError(\n \"branch_not_found\",\n \"Load the storefront branch before using its cart\",\n );\n }\n menu = value;\n branch = found;\n selected = found.id;\n };\n const load = (raw: string | null, writeBack = true) => {\n cancel();\n let saved: StoredCart | undefined;\n try {\n saved = raw ? parseCart(raw) : undefined;\n if (saved && Date.now() - saved.updatedAt > ttl) {\n saved = undefined;\n storage.remove(key());\n events.emit(\"cart_expired\", { branchId: branch!.id });\n }\n } catch {\n storage.remove(key());\n storage.warning(\"Invalid saved cart discarded\");\n }\n updatedAt = saved?.updatedAt ?? Date.now();\n const idle = Date.now() - updatedAt;\n let fulfilment = saved?.fulfilment ?? null;\n if (\n fulfilment?.branchId !== branch!.id ||\n (idle > 86_400_000 && fulfilment.type === \"delivery\")\n ) {\n fulfilment = null;\n }\n if (\n fulfilment &&\n \"scheduledFor\" in fulfilment &&\n fulfilment.scheduledFor &&\n Date.parse(fulfilment.scheduledFor) < Date.now()\n ) {\n fulfilment = { ...fulfilment };\n delete fulfilment.scheduledFor;\n }\n const lines = (saved?.lines ?? []).map((line) => ({\n ...line,\n ...(idle > 86_400_000 ? { inputs: {} } : {}),\n }));\n const result = reconcile(lines, menu!, branch!, store.peek()!.currency);\n recompute(result.lines, result.issues, {\n fulfilment,\n promoCode: saved?.promoCode ?? null,\n isHydrated: true,\n });\n // Persist privacy scrubbing and normalized prices without extending idle expiry.\n if (raw !== null && writeBack) {\n persist();\n }\n storage.sweep(prefix, key(), ttl);\n };\n const ensure = () => {\n const id =\n branch?.id ??\n store\n .peek()\n ?.branches.find(\n (b) =>\n b.id === selected ||\n b.slug === selected ||\n (!selected && b.isDefault),\n )?.id ??\n (!selected ? store.peek()?.branches[0]?.id : undefined);\n if (snapshot.isHydrated) {\n return;\n }\n const loaded = menu ?? (id ? deps.workingSet.peek(id, []) : undefined);\n if (!loaded || !store.peek()) {\n throw new ZappieError(\n \"invalid_request\",\n \"Load the store and menu before editing the cart\",\n );\n }\n choose(loaded);\n const raw = readSaved(branch!.id);\n let migrated: CartLineInput[] = [];\n if (raw === null && legacy) {\n try {\n migrated = legacy(storage.read);\n } catch {\n storage.warning(\"Invalid legacy cart discarded\");\n }\n }\n load(raw);\n if (raw === null && legacy) {\n persist();\n }\n for (const input of migrated.slice(0, 100)) {\n try {\n cart.add(input.itemId, input);\n } catch {\n events.emit(\"cart_issue\", { code: \"item_unavailable\" });\n }\n }\n };\n const refresh = async () => {\n const id = branch?.id;\n const seq = moveSequence;\n const request = ++refreshSequence;\n const rev = revision;\n if (!id || !menu) {\n return;\n }\n if (!snapshot.lines.length) {\n return;\n }\n if (menu.completeness !== \"partial\") {\n const version = await deps.transport.getMenuVersion({\n ...deps.context(),\n branchId: id,\n });\n if (version.version === menu.version) {\n return;\n }\n }\n const value = await deps.workingSet.read(\n id,\n snapshot.lines.map((l) => l.itemId),\n true,\n );\n if (\n seq !== moveSequence ||\n request !== refreshSequence ||\n rev !== revision ||\n JSON.stringify(value) === JSON.stringify(menu)\n ) {\n return;\n }\n menu = value;\n cancel();\n recompute(snapshot.lines);\n persist();\n schedule();\n };\n // Validation follows the latest copy of an item the working set holds: a\n // refreshed item can add a required option, and an add, edit or check\n // against the earlier copy would accept a line the server then rejects.\n const current = (itemId: string) => {\n const candidate = deps.workingSet.peek(branch!.id, [\n ...snapshot.lines.map((l) => l.itemId),\n itemId,\n ]);\n if (candidate.items[itemId]) {\n menu = candidate;\n }\n };\n const validated = (\n raw: CartLineInput,\n id?: string,\n addedAt?: string,\n ): CartLine => {\n current(raw.itemId);\n const item = Object.hasOwn(menu!.items, raw.itemId)\n ? menu!.items[raw.itemId]\n : undefined;\n const problems = validateLine(item, raw, { menu: menu!, branch: branch! });\n if (problems.length || !item) {\n throw new ZappieCartError(problems);\n }\n const input = normalizeInput(item, raw);\n const variant = resolveVariant(item, input)!;\n const choices = (input.choices ?? []).map((c) => ({\n ...c,\n quantity: c.quantity ?? 1,\n }));\n const unitPrice = estimateUnitPrice(item, {\n choices,\n variantId: variant.id,\n });\n return freezeLine({\n id:\n id ??\n `line_${Array.from(globalThis.crypto.getRandomValues(new Uint8Array(10)), (byte) => \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz-\"[byte & 63]).join(\"\")}`,\n itemId: item.id,\n ...(input.menuId !== undefined ? { menuId: input.menuId } : {}),\n name: item.name,\n quantity: input.quantity!,\n choices,\n inputs: input.inputs ?? {},\n variantId: variant.id,\n ...(input.note !== undefined ? { note: input.note } : {}),\n unitPrice,\n lineSubtotal: multiplyMoney(unitPrice, input.quantity!),\n addedAt: addedAt ?? new Date().toISOString(),\n });\n };\n const offMenu = events.on(\"menu:updated\", ({ branchId, version }) => {\n if (branch?.id === branchId) {\n const value = menus.peek(branchId);\n if (\n value &&\n value.completeness !== \"partial\" &&\n value.version === version &&\n value.version !== menu?.version\n ) {\n refreshSequence++;\n menu = value;\n cancel();\n recompute(snapshot.lines);\n persist();\n schedule();\n }\n }\n });\n const cart: CartModule = {\n get branchId() {\n return snapshot.branchId;\n },\n get lines() {\n return snapshot.lines;\n },\n get count() {\n return snapshot.count;\n },\n get subtotal() {\n return snapshot.subtotal;\n },\n get fulfilment() {\n return snapshot.fulfilment;\n },\n get promoCode() {\n return snapshot.promoCode;\n },\n get state() {\n return snapshot.state;\n },\n get issues() {\n return snapshot.issues;\n },\n get isHydrated() {\n return snapshot.isHydrated;\n },\n getSnapshot: () => snapshot,\n subscribe(fn) {\n listeners.add(fn);\n return () => {\n listeners.delete(fn);\n };\n },\n async hydrate() {\n if (snapshot.isHydrated) {\n return refresh();\n }\n const life = lifecycle;\n hydration ??= (async () => {\n const value = await store.get();\n const target =\n value.branches.find(\n (b) => b.id === selected || b.slug === selected,\n ) ??\n (!selected\n ? (value.branches.find((b) => b.isDefault) ?? value.branches[0])\n : undefined);\n if (!target) {\n throw new ZappieError(\n \"branch_not_found\",\n \"Cart branch is unavailable\",\n );\n }\n let inputs: readonly { itemId: string }[] = snapshot.lines;\n if (!snapshot.isHydrated) {\n const raw = readSaved(target.id);\n try {\n const saved = raw ? parseCart(raw) : undefined;\n inputs =\n saved && Date.now() - saved.updatedAt <= ttl\n ? saved.lines\n : raw === null\n ? (legacy?.(storage.read) ?? [])\n : [];\n } catch {\n inputs = [];\n }\n }\n const loaded = await deps.workingSet.read(\n target.id,\n inputs.map((l) => l.itemId),\n );\n if (life !== lifecycle) {\n return;\n }\n choose(loaded);\n ensure();\n if (loaded.completeness !== \"partial\") {\n await refresh();\n }\n })().finally(() => {\n hydration = undefined;\n });\n return hydration;\n },\n mount() {\n mounted++;\n if (!detach && typeof window !== \"undefined\") {\n const onStorage = (event: StorageEvent) => {\n if (\n branch &&\n event.key === key() &&\n storage.accepts(event.storageArea)\n ) {\n const raw = event.newValue;\n let ids: string[];\n try {\n ids = raw ? parseCart(raw).lines.map((l) => l.itemId) : [];\n } catch {\n load(raw, false);\n return;\n }\n const cached = deps.workingSet.peek(branch.id, ids);\n if (\n cached.completeness !== \"partial\" ||\n ids.every((id) => cached.items[id])\n ) {\n menu = cached;\n load(raw, false);\n schedule();\n return;\n }\n const rev = revision;\n const request = ++refreshSequence;\n const life = lifecycle;\n void deps.workingSet\n .read(branch.id, ids)\n .then((value) => {\n if (\n life === lifecycle &&\n rev === revision &&\n request === refreshSequence\n ) {\n menu = value;\n load(raw, false);\n schedule();\n }\n })\n .catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n };\n const onFocus = () => {\n void refresh().catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n };\n window.addEventListener(\"storage\", onStorage);\n window.addEventListener(\"focus\", onFocus);\n // Only browser listeners follow mounts; the menu:updated subscription lives until dispose().\n detach = () => {\n window.removeEventListener(\"storage\", onStorage);\n window.removeEventListener(\"focus\", onFocus);\n };\n }\n if (mounted === 1) {\n void cart\n .hydrate()\n .catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n let active = true;\n return () => {\n if (active) {\n active = false;\n mounted--;\n if (mounted === 0) {\n detach?.();\n detach = undefined;\n cancel();\n }\n }\n };\n },\n dispose() {\n lifecycle++;\n moveSequence++;\n offMenu();\n cancel();\n detach?.();\n detach = undefined;\n listeners.clear();\n },\n validate(input) {\n ensure();\n current(input.itemId);\n const problems = validateLine(\n Object.hasOwn(menu!.items, input.itemId)\n ? menu!.items[input.itemId]\n : undefined,\n input,\n { menu: menu!, branch: branch! },\n );\n return problems.length ? { ok: false, issues: problems } : { ok: true };\n },\n add(item, input = {}) {\n ensure();\n let line = validated({\n ...input,\n itemId: typeof item === \"string\" ? item : item.id,\n });\n const existing = snapshot.lines.find(\n (l) => identity(lineInput(l)) === identity(lineInput(line)),\n );\n if (existing) {\n line = validated(\n { ...lineInput(line), quantity: existing.quantity + line.quantity },\n existing.id,\n existing.addedAt,\n );\n } else if (snapshot.lines.length >= 100) {\n throw new ZappieCartError([\n issue(\"quantity_limit\", \"A cart can contain at most 100 lines\"),\n ]);\n }\n changed(\n existing\n ? snapshot.lines.map((l) => (l.id === existing.id ? line : l))\n : [...snapshot.lines, line],\n );\n events.emit(\"add_to_cart\", {\n itemId: line.itemId,\n quantity: line.quantity - (existing?.quantity ?? 0),\n value: multiplyMoney(\n line.unitPrice,\n line.quantity - (existing?.quantity ?? 0),\n ),\n });\n return line;\n },\n update(lineId, patch) {\n ensure();\n const old = snapshot.lines.find((l) => l.id === lineId);\n if (!old) {\n throw new ZappieCartError([\n issue(\"item_not_found\", \"Cart line not found\"),\n ]);\n }\n const input = { ...lineInput(old), ...patch };\n if (patch.choices && !patch.variantId) {\n delete input.variantId;\n }\n let line = validated(input, old.id, old.addedAt);\n const duplicate = snapshot.lines.find(\n (l) =>\n l.id !== lineId &&\n identity(lineInput(l)) === identity(lineInput(line)),\n );\n if (duplicate) {\n line = validated(\n { ...lineInput(line), quantity: line.quantity + duplicate.quantity },\n old.id,\n old.addedAt,\n );\n }\n changed(\n snapshot.lines\n .filter((l) => l.id !== duplicate?.id)\n .map((l) => (l.id === lineId ? line : l)),\n );\n events.emit(\"update_cart_line\", {\n lineId,\n itemId: line.itemId,\n quantity: line.quantity,\n });\n return line;\n },\n remove(lineId) {\n ensure();\n const line = snapshot.lines.find((l) => l.id === lineId);\n changed(snapshot.lines.filter((l) => l.id !== lineId));\n if (line) {\n events.emit(\"remove_from_cart\", {\n itemId: line.itemId,\n quantity: line.quantity,\n value: line.lineSubtotal,\n });\n }\n },\n clear() {\n ensure();\n changed([], { fulfilment: null, promoCode: null });\n },\n setFulfilment(value) {\n ensure();\n if (!validFulfilment(value) || value.branchId !== branch!.id) {\n throw new ZappieCartError([\n issue(\n \"fulfilment_unavailable\",\n \"Select fulfilment for the cart's branch\",\n ),\n ]);\n }\n changed(snapshot.lines, { fulfilment: structuredClone(value) });\n },\n setPromoCode(code) {\n ensure();\n changed(snapshot.lines, { promoCode: code?.trim() || null });\n },\n async moveTo(branchId) {\n ensure();\n const seq = ++moveSequence;\n cancel();\n publish({ state: attention(snapshot.issues) });\n const value = await deps.workingSet.read(\n branchId,\n snapshot.lines.map((l) => l.itemId),\n );\n if (seq !== moveSequence) {\n return;\n }\n const oldKey = key();\n const oldLines = snapshot.lines;\n choose(value);\n const kept = oldLines.filter(\n (line) =>\n !validateLine(value.items[line.itemId], lineInput(line), {\n menu: value,\n branch: branch!,\n }).length,\n );\n changed(kept, { fulfilment: null, promoCode: null });\n const dropped = oldLines\n .filter((line) => !kept.includes(line))\n .map((line) => ({\n ...issue(\n \"item_unavailable\",\n `${line.name} is unavailable at this branch`,\n ),\n severity: \"warning\" as const,\n lineId: line.id,\n }));\n const issues = [...snapshot.issues, ...dropped];\n publish({ issues, state: attention(issues) });\n if (oldKey !== key()) {\n storage.remove(oldKey);\n }\n },\n async quote(opts = {}) {\n ensure();\n clearTimeout(timer);\n if (opts.force) {\n events.emit(\"view_cart\", {});\n }\n const body = {\n branch_id: branch!.id,\n lines: snapshot.lines.map(wireLine),\n ...(snapshot.fulfilment\n ? { fulfilment: wireFulfilment(snapshot.fulfilment) }\n : {}),\n ...(snapshot.promoCode ? { promo_code: snapshot.promoCode } : {}),\n menu_version: menu!.version,\n };\n const seq = revision;\n const attempt = ++quoteRevision;\n publish({ state: { status: \"quoting\" } });\n try {\n const client = await quoteClient();\n return await client.get(body, opts.force ?? false, (quote) => {\n if (seq !== revision) {\n return;\n }\n const local = snapshot.issues.filter((i) => i.source === \"local\");\n // The server re-validates every line; a problem the cart already reports is shown once.\n const remote = quote.issues.filter(\n (q) =>\n !local.some(\n (l) =>\n l.code === q.code &&\n l.lineId === q.lineId &&\n l.groupId === q.groupId,\n ),\n );\n const issues = [...local, ...remote];\n publish({ issues, state: attention(issues, quote) });\n for (const i of remote) {\n events.emit(\"cart_issue\", { code: i.code });\n }\n // A newer server menu means local prices and the sent version are stale. Refreshing\n // reconciles them and re-quotes, so the server stops re-raising the same change.\n if (\n quote.menuVersion !== menu!.version ||\n quote.issues.some((i) => i.code === \"menu_version_stale\")\n ) {\n void refresh().catch((error: unknown) =>\n events.emit(\"error\", { error: asError(error) }),\n );\n }\n });\n } catch (error) {\n if (seq === revision && attempt === quoteRevision) {\n const local = snapshot.issues.filter((i) => i.source === \"local\");\n publish({ issues: local, state: attention(local) });\n events.emit(\"quote_failed\", { code: asError(error).code });\n }\n throw error instanceof Error && error.name === \"AbortError\"\n ? error\n : asError(error);\n }\n },\n applyFix(problem, fix = problem.fixes[0]) {\n if (\n !snapshot.issues.includes(problem) ||\n !fix ||\n !problem.fixes.some((f) => JSON.stringify(f) === JSON.stringify(fix))\n ) {\n throw new ZappieError(\n \"invalid_request\",\n \"Choose a current cart issue and one of its fixes\",\n );\n }\n switch (fix.action) {\n case \"remove_line\": {\n if (problem.lineId) {\n cart.remove(problem.lineId);\n }\n return;\n }\n case \"remove_promo\":\n cart.setPromoCode(null);\n return;\n case \"set_quantity\": {\n if (problem.lineId) {\n cart.update(problem.lineId, { quantity: fix.quantity });\n }\n return;\n }\n case \"accept_price\": {\n quotes?.accept(problem);\n const issues = snapshot.issues.filter((i) => i !== problem);\n const quote =\n \"quote\" in snapshot.state ? snapshot.state.quote : undefined;\n const accepted = quote\n ? {\n ...quote,\n issues: quote.issues.filter(\n (i) =>\n !(i.code === problem.code && i.lineId === problem.lineId),\n ),\n }\n : undefined;\n publish({ issues, state: attention(issues, accepted) });\n return;\n }\n case \"choose_region\":\n throw new ZappieError(\n \"invalid_request\",\n \"Choose a delivery region and call setFulfilment with deliveryRegionId\",\n );\n default:\n throw new ZappieError(\n \"invalid_request\",\n `${fix.action} needs the shopper's selection; use update or setFulfilment`,\n );\n }\n },\n toCheckoutPayload() {\n ensure();\n const blocking = snapshot.issues.filter((i) => i.severity === \"blocking\");\n if (!snapshot.lines.length || !snapshot.fulfilment) {\n blocking.push(\n issue(\n \"fulfilment_unavailable\",\n \"Add items and select fulfilment before checkout\",\n ),\n );\n }\n if (blocking.length) {\n throw new ZappieCartError(blocking);\n }\n return {\n lines: snapshot.lines.map(wireLine),\n fulfilment: structuredClone(snapshot.fulfilment!),\n ...(snapshot.promoCode ? { promo_code: snapshot.promoCode } : {}),\n menu_version: menu!.version,\n };\n },\n };\n return {\n cart: Object.freeze(cart),\n cartCatalogue: () => menu,\n setLegacyReader(reader: NonNullable<typeof legacy>) {\n legacy = reader;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,5 +1,6 @@
1
- import { Z as Zappie } from '../client-RFcLoZ04.js';
1
+ import { Z as Zappie } from '../client-Bm2cCYea.js';
2
2
  import { I as Item } from '../models-Rg5kQUkv.js';
3
+ import '../types-CuDvfW9g.js';
3
4
 
4
5
  /** Register an item already read by a partial/selected catalogue, without fetching it again. */
5
6
  declare function prepareItem(client: Zappie, item: Item, options: {
@@ -1,8 +1,53 @@
1
1
  // src/cart/quote-client.ts
2
- import { ZappieError } from "../errors.js";
2
+ import { wireError, ZappieError } from "../errors.js";
3
+ import { requestWithRetry } from "../internal/customer-http.js";
3
4
  import { payloadKey } from "../internal/digest.js";
4
5
  import { mapQuote } from "./quote-response.js";
5
- function createQuoteClient(transport, context) {
6
+ function customerQuoteBody(body) {
7
+ const value = body.fulfilment;
8
+ if (!value) {
9
+ return body;
10
+ }
11
+ const { table: _table, address, ...fulfilment } = value;
12
+ if (!address) {
13
+ return { ...body, fulfilment };
14
+ }
15
+ const { line2: _line2, instructions, ...rest } = address;
16
+ return {
17
+ ...body,
18
+ fulfilment: {
19
+ ...fulfilment,
20
+ ...fulfilment.instructions === void 0 && instructions !== void 0 ? { instructions } : {},
21
+ address: rest
22
+ }
23
+ };
24
+ }
25
+ function createQuoteClient(transport, context, options = {}) {
26
+ const customerBase = options.customerBase?.replace(/\/+$/, "");
27
+ const signedQuote = async (body, signal, idempotencyKey) => {
28
+ const response = await requestWithRetry(
29
+ options.fetch ?? globalThis.fetch,
30
+ `${customerBase}/quote`,
31
+ {
32
+ method: "POST",
33
+ headers: {
34
+ "Content-Type": "application/json",
35
+ "Idempotency-Key": idempotencyKey
36
+ },
37
+ body: JSON.stringify(customerQuoteBody(body)),
38
+ signal
39
+ },
40
+ "Could not reach the storefront quote service"
41
+ );
42
+ if (!response.ok) {
43
+ throw wireError(
44
+ await response.json().catch(() => ({})),
45
+ response.status,
46
+ response.headers.get("Zappie-Request-Id") ?? void 0
47
+ );
48
+ }
49
+ return await response.json();
50
+ };
6
51
  let controller;
7
52
  let sequence = 0;
8
53
  let cached;
@@ -30,7 +75,7 @@ function createQuoteClient(transport, context) {
30
75
  const promise = (async () => {
31
76
  const idempotencyKey = await payloadKey(key);
32
77
  signal.throwIfAborted();
33
- const raw = await transport.quote(
78
+ const raw = customerBase ? await signedQuote(body, signal, idempotencyKey) : await transport.quote(
34
79
  { ...context(), signal, idempotencyKey },
35
80
  body
36
81
  );
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/quote-client.ts"],
4
- "sourcesContent": ["import { ZappieError } from \"../errors\";\nimport { payloadKey } from \"../internal/digest\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\nimport { mapQuote } from \"./quote-response\";\nimport type { Quote, QuoteRequest } from \"./types\";\nexport function createQuoteClient(\n transport: Transport,\n context: () => RequestCtx,\n) {\n let controller: AbortController | undefined;\n let sequence = 0;\n let cached: { key: string; quote: Quote } | undefined;\n let flight: { key: string; promise: Promise<Quote> } | undefined;\n const cancel = () => {\n sequence++;\n controller?.abort();\n flight = undefined;\n };\n return {\n cancel,\n async get(\n body: QuoteRequest,\n force: boolean,\n apply: (quote: Quote) => void,\n ): Promise<Quote> {\n const key = JSON.stringify(body);\n if (\n !force &&\n cached?.key === key &&\n Date.parse(cached.quote.expiresAt) > Date.now()\n ) {\n apply(cached.quote);\n return cached.quote;\n }\n if (!force && flight?.key === key) {\n return flight.promise;\n }\n cancel();\n const seq = sequence;\n controller = new AbortController();\n const signal = controller.signal;\n const promise = (async () => {\n const idempotencyKey = await payloadKey(key);\n signal.throwIfAborted();\n const raw = await transport.quote(\n { ...context(), signal, idempotencyKey },\n body,\n );\n signal.throwIfAborted();\n const quote = mapQuote(raw, body.branch_id);\n const ids = new Set(quote.lines.map((line) => line.lineId));\n if (\n ids.size !== quote.lines.length ||\n quote.lines.length !== body.lines.length ||\n body.lines.some((line) => !ids.has(line.line_id))\n ) {\n throw new ZappieError(\n \"server_error\",\n \"Quote line identities do not match the cart\",\n );\n }\n if (seq === sequence) {\n cached = { key, quote };\n apply(quote);\n }\n return quote;\n })();\n flight = { key, promise };\n try {\n return await promise;\n } finally {\n if (seq === sequence) {\n flight = undefined;\n }\n }\n },\n accept(issue: CartIssueForAcceptance) {\n if (cached) {\n cached.quote = {\n ...cached.quote,\n issues: cached.quote.issues.filter(\n (i) => !(i.code === issue.code && i.lineId === issue.lineId),\n ),\n };\n }\n },\n };\n}\ntype CartIssueForAcceptance = { code: string; lineId?: string };\n\nexport type QuoteClient = ReturnType<typeof createQuoteClient>;\n"],
5
- "mappings": ";AAAA,SAAS,mBAAmB;AAC5B,SAAS,kBAAkB;AAE3B,SAAS,gBAAgB;AAElB,SAAS,kBACd,WACA,SACA;AACA,MAAI;AACJ,MAAI,WAAW;AACf,MAAI;AACJ,MAAI;AACJ,QAAM,SAAS,MAAM;AACnB;AACA,gBAAY,MAAM;AAClB,aAAS;AAAA,EACX;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,IACJ,MACA,OACA,OACgB;AAChB,YAAM,MAAM,KAAK,UAAU,IAAI;AAC/B,UACE,CAAC,SACD,QAAQ,QAAQ,OAChB,KAAK,MAAM,OAAO,MAAM,SAAS,IAAI,KAAK,IAAI,GAC9C;AACA,cAAM,OAAO,KAAK;AAClB,eAAO,OAAO;AAAA,MAChB;AACA,UAAI,CAAC,SAAS,QAAQ,QAAQ,KAAK;AACjC,eAAO,OAAO;AAAA,MAChB;AACA,aAAO;AACP,YAAM,MAAM;AACZ,mBAAa,IAAI,gBAAgB;AACjC,YAAM,SAAS,WAAW;AAC1B,YAAM,WAAW,YAAY;AAC3B,cAAM,iBAAiB,MAAM,WAAW,GAAG;AAC3C,eAAO,eAAe;AACtB,cAAM,MAAM,MAAM,UAAU;AAAA,UAC1B,EAAE,GAAG,QAAQ,GAAG,QAAQ,eAAe;AAAA,UACvC;AAAA,QACF;AACA,eAAO,eAAe;AACtB,cAAM,QAAQ,SAAS,KAAK,KAAK,SAAS;AAC1C,cAAM,MAAM,IAAI,IAAI,MAAM,MAAM,IAAI,CAAC,SAAS,KAAK,MAAM,CAAC;AAC1D,YACE,IAAI,SAAS,MAAM,MAAM,UACzB,MAAM,MAAM,WAAW,KAAK,MAAM,UAClC,KAAK,MAAM,KAAK,CAAC,SAAS,CAAC,IAAI,IAAI,KAAK,OAAO,CAAC,GAChD;AACA,gBAAM,IAAI;AAAA,YACR;AAAA,YACA;AAAA,UACF;AAAA,QACF;AACA,YAAI,QAAQ,UAAU;AACpB,mBAAS,EAAE,KAAK,MAAM;AACtB,gBAAM,KAAK;AAAA,QACb;AACA,eAAO;AAAA,MACT,GAAG;AACH,eAAS,EAAE,KAAK,QAAQ;AACxB,UAAI;AACF,eAAO,MAAM;AAAA,MACf,UAAE;AACA,YAAI,QAAQ,UAAU;AACpB,mBAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA,OAAO,OAA+B;AACpC,UAAI,QAAQ;AACV,eAAO,QAAQ;AAAA,UACb,GAAG,OAAO;AAAA,UACV,QAAQ,OAAO,MAAM,OAAO;AAAA,YAC1B,CAAC,MAAM,EAAE,EAAE,SAAS,MAAM,QAAQ,EAAE,WAAW,MAAM;AAAA,UACvD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["import { wireError, ZappieError } from \"../errors\";\nimport { requestWithRetry } from \"../internal/customer-http\";\nimport { payloadKey } from \"../internal/digest\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\nimport { mapQuote } from \"./quote-response\";\nimport type { Quote, QuoteRequest, WireQuote } from \"./types\";\ntype QuoteClientOptions = {\n customerBase?: string | undefined;\n fetch?: typeof fetch | undefined;\n};\nfunction customerQuoteBody(body: QuoteRequest): QuoteRequest {\n const value = body.fulfilment;\n if (!value) {\n return body;\n }\n const { table: _table, address, ...fulfilment } = value;\n if (!address) {\n return { ...body, fulfilment };\n }\n const { line2: _line2, instructions, ...rest } = address;\n return {\n ...body,\n fulfilment: {\n ...fulfilment,\n ...(fulfilment.instructions === undefined && instructions !== undefined\n ? { instructions }\n : {}),\n address: rest,\n },\n };\n}\nexport function createQuoteClient(\n transport: Transport,\n context: () => RequestCtx,\n options: QuoteClientOptions = {},\n) {\n const customerBase = options.customerBase?.replace(/\\/+$/, \"\");\n const signedQuote = async (\n body: QuoteRequest,\n signal: AbortSignal,\n idempotencyKey: string,\n ): Promise<WireQuote> => {\n const response = await requestWithRetry(\n options.fetch ?? globalThis.fetch,\n `${customerBase}/quote`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n },\n body: JSON.stringify(customerQuoteBody(body)),\n signal,\n },\n \"Could not reach the storefront quote service\",\n );\n if (!response.ok) {\n throw wireError(\n await response.json().catch(() => ({})),\n response.status,\n response.headers.get(\"Zappie-Request-Id\") ?? undefined,\n );\n }\n return (await response.json()) as WireQuote;\n };\n let controller: AbortController | undefined;\n let sequence = 0;\n let cached: { key: string; quote: Quote } | undefined;\n let flight: { key: string; promise: Promise<Quote> } | undefined;\n const cancel = () => {\n sequence++;\n controller?.abort();\n flight = undefined;\n };\n return {\n cancel,\n async get(\n body: QuoteRequest,\n force: boolean,\n apply: (quote: Quote) => void,\n ): Promise<Quote> {\n const key = JSON.stringify(body);\n if (\n !force &&\n cached?.key === key &&\n Date.parse(cached.quote.expiresAt) > Date.now()\n ) {\n apply(cached.quote);\n return cached.quote;\n }\n if (!force && flight?.key === key) {\n return flight.promise;\n }\n cancel();\n const seq = sequence;\n controller = new AbortController();\n const signal = controller.signal;\n const promise = (async () => {\n const idempotencyKey = await payloadKey(key);\n signal.throwIfAborted();\n const raw = customerBase\n ? await signedQuote(body, signal, idempotencyKey)\n : await transport.quote(\n { ...context(), signal, idempotencyKey },\n body,\n );\n signal.throwIfAborted();\n const quote = mapQuote(raw, body.branch_id);\n const ids = new Set(quote.lines.map((line) => line.lineId));\n if (\n ids.size !== quote.lines.length ||\n quote.lines.length !== body.lines.length ||\n body.lines.some((line) => !ids.has(line.line_id))\n ) {\n throw new ZappieError(\n \"server_error\",\n \"Quote line identities do not match the cart\",\n );\n }\n if (seq === sequence) {\n cached = { key, quote };\n apply(quote);\n }\n return quote;\n })();\n flight = { key, promise };\n try {\n return await promise;\n } finally {\n if (seq === sequence) {\n flight = undefined;\n }\n }\n },\n accept(issue: CartIssueForAcceptance) {\n if (cached) {\n cached.quote = {\n ...cached.quote,\n issues: cached.quote.issues.filter(\n (i) => !(i.code === issue.code && i.lineId === issue.lineId),\n ),\n };\n }\n },\n };\n}\ntype CartIssueForAcceptance = { code: string; lineId?: string };\n\nexport type QuoteClient = ReturnType<typeof createQuoteClient>;\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,12 @@
1
- import { T as Transport, R as RequestCtx, Q as QuoteRequest, a as Quote } from '../client-RFcLoZ04.js';
1
+ import { T as Transport, R as RequestCtx } from '../client-Bm2cCYea.js';
2
+ import { Q as QuoteRequest, a as Quote } from '../types-CuDvfW9g.js';
2
3
  import '../models-Rg5kQUkv.js';
3
4
 
4
- declare function createQuoteClient(transport: Transport, context: () => RequestCtx): {
5
+ type QuoteClientOptions = {
6
+ customerBase?: string | undefined;
7
+ fetch?: typeof fetch | undefined;
8
+ };
9
+ declare function createQuoteClient(transport: Transport, context: () => RequestCtx, options?: QuoteClientOptions): {
5
10
  cancel: () => void;
6
11
  get(body: QuoteRequest, force: boolean, apply: (quote: Quote) => void): Promise<Quote>;
7
12
  accept(issue: CartIssueForAcceptance): void;