@zappie/sdk 0.2.0 → 0.3.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.
Files changed (129) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/cart/branch.js.map +0 -1
  3. package/dist/cart/errors.js.map +0 -1
  4. package/dist/cart/index.js.map +0 -1
  5. package/dist/cart/item.d.ts +1 -1
  6. package/dist/cart/item.js.map +0 -1
  7. package/dist/cart/preview.js.map +0 -1
  8. package/dist/cart/price.js.map +0 -1
  9. package/dist/cart/quote-client.js.map +0 -1
  10. package/dist/cart/quote-response.js.map +0 -1
  11. package/dist/cart/quote.d.ts +1 -1
  12. package/dist/cart/reconcile.js.map +0 -1
  13. package/dist/cart/source-menu.js.map +0 -1
  14. package/dist/cart/storage.js.map +0 -1
  15. package/dist/cart/types.js.map +0 -1
  16. package/dist/cart/validate.js.map +0 -1
  17. package/dist/cart/wire.js.map +0 -1
  18. package/dist/cart/working-set.js.map +0 -1
  19. package/dist/checkout/client.js.map +0 -1
  20. package/dist/checkout/embed.js.map +0 -1
  21. package/dist/checkout/error.js.map +0 -1
  22. package/dist/checkout/index.js.map +0 -1
  23. package/dist/checkout/react.js.map +0 -1
  24. package/dist/checkout/readiness.js.map +0 -1
  25. package/dist/checkout/sdk.js.map +0 -1
  26. package/dist/checkout/session.js.map +0 -1
  27. package/dist/checkout/types.js.map +0 -1
  28. package/dist/checkout-defaults/index.js.map +0 -1
  29. package/dist/{client-B377AzNC.d.ts → client-DHxakZrv.d.ts} +2 -2
  30. package/dist/client.js.map +0 -1
  31. package/dist/config/index.js.map +0 -1
  32. package/dist/config.js.map +0 -1
  33. package/dist/customer/client.js.map +0 -1
  34. package/dist/customer/error.js.map +0 -1
  35. package/dist/customer/index.js.map +0 -1
  36. package/dist/customer/navigation.js.map +0 -1
  37. package/dist/customer/react.js.map +0 -1
  38. package/dist/customer/request.js.map +0 -1
  39. package/dist/customer/sdk.js.map +0 -1
  40. package/dist/customer/types.js.map +0 -1
  41. package/dist/customer/watch-order.js.map +0 -1
  42. package/dist/debug.js +1 -1
  43. package/dist/debug.js.map +0 -1
  44. package/dist/errors.js.map +0 -1
  45. package/dist/index.d.ts +6 -6
  46. package/dist/index.js +1 -1
  47. package/dist/index.js.map +0 -1
  48. package/dist/integrations/index.d.ts +2 -2
  49. package/dist/integrations/index.js.map +0 -1
  50. package/dist/internal/abort.js.map +0 -1
  51. package/dist/internal/cache.js.map +0 -1
  52. package/dist/internal/customer-http.js.map +0 -1
  53. package/dist/internal/digest.js.map +0 -1
  54. package/dist/internal/emitter.js.map +0 -1
  55. package/dist/internal/money-math.js.map +0 -1
  56. package/dist/internal/return-path.js.map +0 -1
  57. package/dist/internal.d.ts +2 -2
  58. package/dist/internal.js.map +0 -1
  59. package/dist/{models-tf9rNoki.d.ts → models-C-kEg1Id.d.ts} +1 -1
  60. package/dist/models.js.map +0 -1
  61. package/dist/money.js.map +0 -1
  62. package/dist/persist/catalogue.d.ts +3 -3
  63. package/dist/persist/catalogue.js.map +0 -1
  64. package/dist/places/client.js.map +0 -1
  65. package/dist/places/error.js.map +0 -1
  66. package/dist/places/index.js.map +0 -1
  67. package/dist/places/request.js.map +0 -1
  68. package/dist/places/sdk.js.map +0 -1
  69. package/dist/places/search.js.map +0 -1
  70. package/dist/places/types.js.map +0 -1
  71. package/dist/pricing/index.js.map +0 -1
  72. package/dist/react/cart.js.map +0 -1
  73. package/dist/react/hooks.js.map +0 -1
  74. package/dist/react/index.js.map +0 -1
  75. package/dist/react/provider.js.map +0 -1
  76. package/dist/redirect/index.js.map +0 -1
  77. package/dist/server/auth/crypto.js.map +0 -1
  78. package/dist/server/auth/jwt.js.map +0 -1
  79. package/dist/server/auth/session-store.js.map +0 -1
  80. package/dist/server/edge-snapshot.js.map +0 -1
  81. package/dist/server/index.d.ts +1 -1
  82. package/dist/server/index.js.map +0 -1
  83. package/dist/server/security.js.map +0 -1
  84. package/dist/server/storefront-url/build-v1.js.map +0 -1
  85. package/dist/server/storefront-url/build-v2.js.map +0 -1
  86. package/dist/server/storefront-url/build.js.map +0 -1
  87. package/dist/server/storefront-url/canonical.js.map +0 -1
  88. package/dist/server/storefront-url/contract.js.map +0 -1
  89. package/dist/server/storefront-url/index.js.map +0 -1
  90. package/dist/server/storefront-url/installation.js.map +0 -1
  91. package/dist/server/storefront-url/params.js.map +0 -1
  92. package/dist/server/storefront-url/parse-v1.js.map +0 -1
  93. package/dist/server/storefront-url/parse-v2.js.map +0 -1
  94. package/dist/server/storefront-url/parse.js.map +0 -1
  95. package/dist/server/storefront-url/public-id.js.map +0 -1
  96. package/dist/server/storefront-url/redirect.js.map +0 -1
  97. package/dist/server/storefront-url/sign-in.js.map +0 -1
  98. package/dist/server/storefront-url/types.js.map +0 -1
  99. package/dist/server/storefront-url/url.js.map +0 -1
  100. package/dist/server/webhook.js.map +0 -1
  101. package/dist/services/index.d.ts +21 -0
  102. package/dist/services/index.js +24 -0
  103. package/dist/services/index.js.map +6 -0
  104. package/dist/site-config/helpers.js.map +0 -1
  105. package/dist/site-config/sections.js.map +0 -1
  106. package/dist/site-config/types.js.map +0 -1
  107. package/dist/site-config/validate.js.map +0 -1
  108. package/dist/template/index.d.ts +2 -2
  109. package/dist/template/index.js +1 -1
  110. package/dist/template/index.js.map +1 -2
  111. package/dist/template/react.js.map +0 -1
  112. package/dist/testing/index.d.ts +1 -1
  113. package/dist/testing/index.js +2 -0
  114. package/dist/transport/category-page.js.map +0 -1
  115. package/dist/transport/mappers.js.map +0 -1
  116. package/dist/transport/presentation.js.map +0 -1
  117. package/dist/transport/quote-body.js.map +0 -1
  118. package/dist/transport/rest.js.map +0 -1
  119. package/dist/transport/search.d.ts +1 -1
  120. package/dist/transport/search.js.map +0 -1
  121. package/dist/transport/selected-menu.d.ts +3 -3
  122. package/dist/transport/selected-menu.js.map +0 -1
  123. package/dist/transport/store.js.map +0 -1
  124. package/dist/transport/types.js.map +0 -1
  125. package/dist/{types-B3Ghmpmy.d.ts → types-CxY5C6AN.d.ts} +1 -1
  126. package/dist/url/index.js.map +0 -1
  127. package/dist/visits/index.js.map +0 -1
  128. package/dist/visits/page-views.js.map +0 -1
  129. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @zappie/sdk
2
2
 
3
+ ## 0.3.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e0b5464: `checkoutUrl(path, environment)` and `appUrl(path, environment)` in the new `@zappie/sdk/services` entry build a URL on Zappie's checkout or app, for production or staging, such as the new home of an old payment or pay-point link. A path that could leave that service throws. `no-offsite-navigation` accepts both, as it accepts `safeRedirect`, and `no-direct-api` points a written-out checkout address to `checkoutUrl`.
8
+
9
+ ## 0.2.1
10
+
11
+ ### Patch Changes
12
+
13
+ - 6bcf696: A closed branch that takes orders ahead can take an order for a later slot. `canOrderAhead(branch)` in `@zappie/foundations` says whether a branch takes orders ahead, and `getOpenStatus` and `OpenStatus` return it as `canOrderAhead`, with `data-order-ahead` on the span. `scheduleSlots` and `Schedule` reach as far as the branch's `orderAheadDays`, or a pre-order menu's own limit, and offer no later slots when the branch takes orders only while open. `maxDays` still caps the horizon when you pass it. The SDK's test fixtures and the starter's mock API send `order_ahead_days`, as the API does.
14
+ - 7e108d9: `resized()` and `srcSet()` percent-encode the photo URL once, so a name with spaces or non-ASCII letters keeps every responsive candidate whole. An already encoded URL keeps its encoding.
15
+ - ffdfc91: Source maps name each file and line without copying the source text, which keeps the archive within its size cap.
16
+
3
17
  ## 0.2.0
4
18
 
5
19
  ### Minor Changes
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
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 // A kept line carries the destination's price, so the moved cart never shows the old one.\n const unitPrice = estimateUnitPrice(after, line);\n const next = money(\n unitPrice.amountMinor * line.quantity,\n unitPrice.currency,\n );\n const moved = { ...line, menuId, unitPrice, lineSubtotal: next };\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
4
  "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;AAEA,UAAM,YAAY,kBAAkB,OAAO,IAAI;AAC/C,UAAM,OAAO;AAAA,MACX,UAAU,cAAc,KAAK;AAAA,MAC7B,UAAU;AAAA,IACZ;AACA,UAAM,QAAQ,EAAE,GAAG,MAAM,QAAQ,WAAW,cAAc,KAAK;AAC/D,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
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/errors.ts"],
4
- "sourcesContent": ["import { ZappieError } from \"../errors\";\nimport type { CartIssue } from \"./types\";\nexport class ZappieCartError extends ZappieError {\n constructor(readonly issues: CartIssue[]) {\n super(\"cart_invalid\", issues[0]?.message ?? \"The cart needs attention\");\n this.name = \"ZappieCartError\";\n }\n}\n"],
5
4
  "mappings": ";AAAA,SAAS,mBAAmB;AAErB,IAAM,kBAAN,cAA8B,YAAY;AAAA,EAC/C,YAAqB,QAAqB;AACxC,UAAM,gBAAgB,OAAO,CAAC,GAAG,WAAW,0BAA0B;AADnD;AAEnB,SAAK,OAAO;AAAA,EACd;AACF;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
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, 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 // Totals read a cart with lines and no quote as waiting for one, so a cart\n // restored or remounted without a quote must ask for it.\n const resume = () => {\n if (!(\"quote\" in snapshot.state)) {\n schedule();\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 resume();\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 resume();\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
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,6 +1,6 @@
1
1
  import { Zappie } from '../index.js';
2
2
  import { Item } from '../index.js';
3
- import '../types-B3Ghmpmy.js';
3
+ import '../types-CxY5C6AN.js';
4
4
 
5
5
  /** Register an item already read by a partial/selected catalogue, without fetching it again. */
6
6
  declare function prepareItem(client: Zappie, item: Item, options: {
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/item.ts"],
4
- "sourcesContent": ["import type { Zappie } from \"../client\";\nimport type { Item } from \"../models\";\n\n/** Register an item already read by a partial/selected catalogue, without fetching it again. */\nexport async function prepareItem(\n client: Zappie,\n item: Item,\n options: { branch: string; signal?: AbortSignal },\n): Promise<Item> {\n options.signal?.throwIfAborted();\n await client.menu.get({ ...options, metadataOnly: true });\n options.signal?.throwIfAborted();\n client._internal.cache.set(`item:${options.branch}:${item.id}`, item);\n // menu.item owns the working-set item registry. Its fresh cache entry means\n // this registration does no item read and never promotes a partial menu.\n return client.menu.item(item.id, options);\n}\n"],
5
4
  "mappings": ";AAIA,eAAsB,YACpB,QACA,MACA,SACe;AACf,UAAQ,QAAQ,eAAe;AAC/B,QAAM,OAAO,KAAK,IAAI,EAAE,GAAG,SAAS,cAAc,KAAK,CAAC;AACxD,UAAQ,QAAQ,eAAe;AAC/B,SAAO,UAAU,MAAM,IAAI,QAAQ,QAAQ,MAAM,IAAI,KAAK,EAAE,IAAI,IAAI;AAGpE,SAAO,OAAO,KAAK,KAAK,KAAK,IAAI,OAAO;AAC1C;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/preview.ts"],
4
- "sourcesContent": ["import type { Item } from \"../models\";\nimport { multiplyMoney } from \"../internal/money-math\";\nimport { estimateUnitPrice } from \"./price\";\nimport { effectiveGroups, normalizeInput, resolveVariant } from \"./validate\";\nimport type { CartLineInput } from \"./types\";\nfunction previewQuantity(value: number | undefined) {\n return Number.isInteger(value) && value! >= 0 && value! <= 99 ? value! : 0;\n}\n/** Presentation preview shares the cart's conditions, exact-variant resolution and pricing. */\nexport function previewItem(item: Item, raw: CartLineInput) {\n const input = normalizeInput(item, raw);\n const groups = effectiveGroups(item, input).filter(\n (group) => group.isAvailable !== false,\n );\n const variantId = resolveVariant(item, input)?.id;\n const choices = (input.choices ?? [])\n .filter(({ groupId, choiceId }) =>\n groups.some(\n (group) =>\n group.id === groupId &&\n group.choices.some((choice) => choice.id === choiceId),\n ),\n )\n .map((selection) => ({\n ...selection,\n quantity: previewQuantity(selection.quantity),\n }));\n const unitPrice = estimateUnitPrice(item, {\n choices,\n ...(variantId ? { variantId } : {}),\n });\n const total = multiplyMoney(unitPrice, previewQuantity(input.quantity));\n return { groups, unitPrice, total };\n}\n"],
5
4
  "mappings": ";AACA,SAAS,qBAAqB;AAC9B,SAAS,yBAAyB;AAClC,SAAS,iBAAiB,gBAAgB,sBAAsB;AAEhE,SAAS,gBAAgB,OAA2B;AAClD,SAAO,OAAO,UAAU,KAAK,KAAK,SAAU,KAAK,SAAU,KAAK,QAAS;AAC3E;AAEO,SAAS,YAAY,MAAY,KAAoB;AAC1D,QAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,QAAM,SAAS,gBAAgB,MAAM,KAAK,EAAE;AAAA,IAC1C,CAAC,UAAU,MAAM,gBAAgB;AAAA,EACnC;AACA,QAAM,YAAY,eAAe,MAAM,KAAK,GAAG;AAC/C,QAAM,WAAW,MAAM,WAAW,CAAC,GAChC;AAAA,IAAO,CAAC,EAAE,SAAS,SAAS,MAC3B,OAAO;AAAA,MACL,CAAC,UACC,MAAM,OAAO,WACb,MAAM,QAAQ,KAAK,CAAC,WAAW,OAAO,OAAO,QAAQ;AAAA,IACzD;AAAA,EACF,EACC,IAAI,CAAC,eAAe;AAAA,IACnB,GAAG;AAAA,IACH,UAAU,gBAAgB,UAAU,QAAQ;AAAA,EAC9C,EAAE;AACJ,QAAM,YAAY,kBAAkB,MAAM;AAAA,IACxC;AAAA,IACA,GAAI,YAAY,EAAE,UAAU,IAAI,CAAC;AAAA,EACnC,CAAC;AACD,QAAM,QAAQ,cAAc,WAAW,gBAAgB,MAAM,QAAQ,CAAC;AACtE,SAAO,EAAE,QAAQ,WAAW,MAAM;AACpC;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/price.ts"],
4
- "sourcesContent": ["import { ZappieError } from \"../errors\";\nimport { multiplyMoney, sumMoney } from \"../internal/money-math\";\nimport type { Item } from \"../models\";\nimport type { CartLine } from \"./types\";\n/**\n * Estimate one item's price from its selected variant and non-attribute option quantities.\n * Uses the item price when no variant is selected and throws if a selected variant or option is missing.\n *\n * @param item - The catalogue item containing prices and options.\n * @param line - The variant and choices to price. Each option quantity is treated as at least one.\n * @returns A local unit-price estimate. Use a server quote for checkout totals.\n */\nexport function estimateUnitPrice(\n item: Item,\n line: Pick<CartLine, \"choices\" | \"variantId\">,\n) {\n const variant = line.variantId\n ? item.variants.find((v) => v.id === line.variantId)\n : undefined;\n if (line.variantId && !variant) {\n throw new ZappieError(\"invalid_request\", \"The selected variant is missing\");\n }\n const extras = line.choices.flatMap((selected) => {\n const group = item.optionGroups.find((g) => g.id === selected.groupId);\n const choice = group?.choices.find((c) => c.id === selected.choiceId);\n if (!group || !choice) {\n throw new ZappieError(\n \"invalid_request\",\n \"The selected option is missing\",\n );\n }\n return group.isAttribute\n ? []\n : [multiplyMoney(choice.price, Math.max(selected.quantity, 1))];\n });\n return sumMoney(extras, variant?.price ?? item.price);\n}\n"],
5
4
  "mappings": ";AAAA,SAAS,mBAAmB;AAC5B,SAAS,eAAe,gBAAgB;AAWjC,SAAS,kBACd,MACA,MACA;AACA,QAAM,UAAU,KAAK,YACjB,KAAK,SAAS,KAAK,CAAC,MAAM,EAAE,OAAO,KAAK,SAAS,IACjD;AACJ,MAAI,KAAK,aAAa,CAAC,SAAS;AAC9B,UAAM,IAAI,YAAY,mBAAmB,iCAAiC;AAAA,EAC5E;AACA,QAAM,SAAS,KAAK,QAAQ,QAAQ,CAAC,aAAa;AAChD,UAAM,QAAQ,KAAK,aAAa,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,OAAO;AACrE,UAAM,SAAS,OAAO,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,QAAQ;AACpE,QAAI,CAAC,SAAS,CAAC,QAAQ;AACrB,YAAM,IAAI;AAAA,QACR;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACA,WAAO,MAAM,cACT,CAAC,IACD,CAAC,cAAc,OAAO,OAAO,KAAK,IAAI,SAAS,UAAU,CAAC,CAAC,CAAC;AAAA,EAClE,CAAC;AACD,SAAO,SAAS,QAAQ,SAAS,SAAS,KAAK,KAAK;AACtD;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/quote-client.ts"],
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
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/quote-response.ts"],
4
- "sourcesContent": ["// Quote responses load lazily with the quote client, outside the synchronous core.\nimport { ZappieError } from \"../errors\";\nimport { sumMoney } from \"../internal/money-math\";\nimport { money } from \"../money\";\nimport { mapMoney, record } from \"../transport/mappers\";\nimport type { CartFix, CartFulfilment, CartIssue, Quote } from \"./types\";\nfunction fail(): never {\n throw new ZappieError(\"server_error\", \"Invalid quote response\");\n}\nfunction text(value: unknown): string {\n if (typeof value !== \"string\") {\n return fail();\n }\n return value;\n}\nfunction list(value: unknown): unknown[] {\n if (!Array.isArray(value)) {\n return fail();\n }\n return value;\n}\n/** A fix newer than this SDK is dropped (undefined); a malformed known fix still fails. */\nfunction fix(value: unknown): CartFix | undefined {\n const v = record(value);\n switch (v.action) {\n case \"remove_line\":\n case \"accept_price\":\n case \"remove_promo\":\n case \"change_address\":\n case \"choose_region\":\n return { action: v.action };\n case \"choose_option\":\n case \"choose_other_option\":\n return { action: v.action, groupId: text(v.group_id) };\n case \"set_quantity\": {\n if (\n !Number.isInteger(v.quantity) ||\n Number(v.quantity) < 1 ||\n Number(v.quantity) > 99\n ) {\n return fail();\n }\n return { action: v.action, quantity: v.quantity as number };\n }\n case \"schedule\":\n return {\n action: v.action,\n ...(v.next_open_at ? { nextOpenAt: text(v.next_open_at) } : {}),\n ...(v.slots ? { slots: list(v.slots).map(text) } : {}),\n };\n case \"switch_fulfilment\": {\n const types = list(v.types)\n .map(text)\n .filter((t) => [\"pickup\", \"delivery\", \"dine_in\"].includes(t));\n return types.length\n ? { action: v.action, types: types as CartFulfilment[\"type\"][] }\n : undefined;\n }\n default:\n return undefined;\n }\n}\nconst codes = [\n \"item_unavailable\",\n \"item_not_found\",\n \"option_unavailable\",\n \"option_required\",\n \"option_limit\",\n \"quantity_limit\",\n \"price_changed\",\n \"branch_closed\",\n \"fulfilment_unavailable\",\n \"outside_delivery_zone\",\n \"delivery_region_required\",\n \"schedule_invalid\",\n \"promo_invalid\",\n \"promo_min_spend\",\n \"min_order\",\n \"menu_version_stale\",\n];\nexport function mapQuote(value: unknown, branchId: string): Quote {\n const v = record(value);\n if (\n v.branch_id !== branchId ||\n !Number.isFinite(Date.parse(text(v.expires_at)))\n ) {\n return fail();\n }\n const subtotal = mapMoney(v.subtotal);\n const checkout = record(v.checkout);\n if (\n typeof v.can_checkout !== \"boolean\" ||\n typeof checkout.ready !== \"boolean\" ||\n (checkout.reason !== undefined &&\n checkout.reason !== \"issues\" &&\n checkout.reason !== \"customer_required\")\n ) {\n return fail();\n }\n const amount = (raw: unknown) => {\n const result = mapMoney(raw);\n if (result.currency !== subtotal.currency) {\n return fail();\n }\n return result;\n };\n const charge = (raw: unknown) => {\n const c = record(raw);\n return {\n code: text(c.code),\n label: text(c.label),\n amount: amount(c.amount),\n };\n };\n const charges = list(v.charges).map(charge);\n const discounts = list(v.discounts).map(charge);\n const total = amount(v.total);\n if (\n sumMoney(\n [...charges, ...discounts].map((c) => c.amount),\n subtotal,\n ).amountMinor !== total.amountMinor\n ) {\n return fail();\n }\n const deliveryCharges = charges.filter((c) => c.code === \"delivery\");\n const fees = charges.filter((c) => c.code !== \"delivery\");\n const integer = (value: unknown) => {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n return fail();\n }\n return value as number;\n };\n const fulfilment =\n v.fulfilment === undefined ? undefined : record(v.fulfilment);\n if (\n v.menu_version_stale !== undefined &&\n typeof v.menu_version_stale !== \"boolean\"\n ) {\n return fail();\n }\n const lines = list(v.lines).map((raw) => {\n const l = record(raw);\n if (\n (l.unit_price == null || l.line_total == null) &&\n v.lines_unpriced !== true\n ) {\n return fail();\n }\n return {\n ...(l.item_id !== undefined ? { itemId: text(l.item_id) } : {}),\n ...(l.name !== undefined ? { name: text(l.name) } : {}),\n ...(l.quantity !== undefined ? { quantity: integer(l.quantity) } : {}),\n ...(l.status !== undefined ? { status: text(l.status) } : {}),\n ...(l.options_total !== undefined\n ? {\n optionsTotal:\n l.options_total === null ? null : amount(l.options_total),\n }\n : {}),\n lineId: text(l.line_id),\n unitPrice: l.unit_price == null ? null : amount(l.unit_price),\n total: l.line_total == null ? null : amount(l.line_total),\n };\n });\n if (\n v.lines_unpriced !== true &&\n sumMoney(\n lines.map((line) => line.total!),\n money(0, subtotal.currency),\n ).amountMinor !== subtotal.amountMinor\n ) {\n return fail();\n }\n return {\n ...(v.menu_version_stale !== undefined\n ? { menuVersionStale: v.menu_version_stale as boolean }\n : {}),\n ...(fulfilment\n ? {\n fulfilment: {\n type: text(fulfilment.type),\n scheduledFor:\n fulfilment.scheduled_for === null\n ? null\n : text(fulfilment.scheduled_for),\n ...(fulfilment.eta_minutes !== undefined\n ? { etaMinutes: list(fulfilment.eta_minutes).map(integer) }\n : {}),\n ...(fulfilment.delivery_region_id !== undefined\n ? { deliveryRegionId: text(fulfilment.delivery_region_id) }\n : {}),\n },\n }\n : {}),\n lines,\n ...(v.lines_unpriced === true ? { linesUnpriced: true } : {}),\n subtotal,\n total,\n fees,\n feesTotal: sumMoney(\n fees.map((c) => c.amount),\n money(0, subtotal.currency),\n ),\n discounts,\n ...(deliveryCharges.length\n ? {\n delivery: sumMoney(\n deliveryCharges.map((c) => c.amount),\n money(0, subtotal.currency),\n ),\n }\n : {}),\n menuVersion: text(v.menu_version),\n expiresAt: text(v.expires_at),\n issues: list(v.issues).flatMap((raw): CartIssue[] => {\n const i = record(raw);\n const code = text(i.code);\n const severity = text(i.severity);\n const known =\n codes.includes(code) &&\n [\"blocking\", \"warning\", \"info\"].includes(severity);\n const fixes = list(i.fixes)\n .map(fix)\n .filter((f): f is CartFix => f !== undefined);\n const lineId = i.line_id ? text(i.line_id) : undefined;\n if (!known && (severity === \"warning\" || severity === \"info\")) {\n console.warn(\n `Zappie quote issue \"${code}\" is newer than this SDK and was skipped`,\n );\n return [];\n }\n // A blocking (or unknown-severity) issue newer than the SDK keeps checkout blocked.\n return [\n {\n code: known ? (code as CartIssue[\"code\"]) : \"item_unavailable\",\n severity: known ? (severity as CartIssue[\"severity\"]) : \"blocking\",\n message: text(i.message),\n source: \"quote\",\n ...(lineId ? { lineId } : {}),\n ...(i.group_id ? { groupId: text(i.group_id) } : {}),\n ...(i.data || !known\n ? {\n data: {\n ...(i.data ? record(i.data) : {}),\n ...(known ? {} : { code }),\n },\n }\n : {}),\n fixes:\n !known && !fixes.length && lineId\n ? [{ action: \"remove_line\" }]\n : fixes,\n },\n ];\n }),\n canCheckout: v.can_checkout,\n checkout: {\n ready: checkout.ready,\n ...(checkout.reason !== undefined ? { reason: checkout.reason } : {}),\n },\n };\n}\n"],
5
4
  "mappings": "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",
6
5
  "names": ["value"]
7
6
  }
@@ -1,6 +1,6 @@
1
1
  import { Transport, RequestCtx } from '../index.js';
2
2
  import { QuoteRequest, Quote } from '../index.js';
3
- import '../models-tf9rNoki.js';
3
+ import '../models-C-kEg1Id.js';
4
4
 
5
5
  type QuoteClientOptions = {
6
6
  customerBase?: string | undefined;
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/reconcile.ts"],
4
- "sourcesContent": ["import { multiplyMoney } from \"../internal/money-math\";\nimport type { Branch, Menu } from \"../models\";\nimport type { Currency } from \"../money\";\nimport { format, money } from \"../money\";\nimport { estimateUnitPrice } from \"./price\";\nimport type { StoredLine } from \"./storage\";\nimport type { CartIssue, CartLine, CartLineInput } from \"./types\";\nimport {\n issue,\n normalizeInput,\n resolveVariant,\n validateLine,\n} from \"./validate\";\nexport function lineInput(line: CartLine): CartLineInput {\n return {\n itemId: line.itemId,\n ...(line.menuId !== undefined ? { menuId: line.menuId } : {}),\n quantity: line.quantity,\n choices: line.choices.map((c) => ({ ...c })),\n inputs: { ...line.inputs },\n ...(line.variantId ? { variantId: line.variantId } : {}),\n ...(line.note !== undefined ? { note: line.note } : {}),\n };\n}\nexport function freezeLine(line: CartLine): CartLine {\n return Object.freeze({\n ...line,\n choices: Object.freeze(line.choices.map((c) => Object.freeze({ ...c }))),\n inputs: Object.freeze({ ...line.inputs }),\n });\n}\nexport function reconcile(\n lines: readonly (CartLine | StoredLine)[],\n menu: Menu,\n branch: Branch,\n currency: Currency,\n previous: readonly CartIssue[] = [],\n) {\n const issues: CartIssue[] = [];\n let priced = true;\n const result = lines.map((old): CartLine => {\n const item = Object.hasOwn(menu.items, old.itemId)\n ? menu.items[old.itemId]\n : undefined;\n const raw = {\n ...old,\n choices: old.choices?.map((c) => ({ ...c })),\n inputs: { ...old.inputs },\n } as CartLineInput;\n const input = item ? normalizeInput(item, raw) : raw;\n issues.push(\n ...validateLine(item, input, { menu, branch }).map((i) => ({\n ...i,\n lineId: old.id,\n })),\n );\n const variantId =\n input.variantId ?? (item ? resolveVariant(item, input)?.id : undefined);\n let unitPrice = money(0, currency);\n let linePriced = true;\n try {\n if (!item) {\n throw new Error(\"Missing item\");\n }\n unitPrice = estimateUnitPrice(item, {\n choices: (input.choices ?? []).map((c) => ({\n ...c,\n quantity: c.quantity ?? 1,\n })),\n ...(variantId ? { variantId } : {}),\n });\n } catch {\n priced = false;\n linePriced = false;\n }\n if (\n old.unitPrice &&\n old.unitPrice.amountMinor !== unitPrice.amountMinor &&\n item &&\n linePriced\n ) {\n issues.push({\n ...issue(\n \"price_changed\",\n `${item.name} is now ${format.money(unitPrice)}`,\n [{ action: \"accept_price\" }, { action: \"remove_line\" }],\n ),\n severity: \"warning\",\n lineId: old.id,\n data: { previous: old.unitPrice, current: unitPrice },\n });\n }\n return freezeLine({\n id: old.id,\n itemId: old.itemId,\n ...(input.menuId !== undefined ? { menuId: input.menuId } : {}),\n name: item?.name ?? old.name,\n quantity: input.quantity ?? 1,\n choices: (input.choices ?? []).map((c) => ({\n ...c,\n quantity: c.quantity ?? 1,\n })),\n inputs: input.inputs ?? {},\n ...(variantId ? { variantId } : {}),\n ...(input.note !== undefined ? { note: input.note } : {}),\n unitPrice,\n lineSubtotal: multiplyMoney(unitPrice, input.quantity ?? 1),\n addedAt: old.addedAt,\n });\n });\n for (const pending of previous) {\n if (\n pending.code === \"price_changed\" &&\n result.some((l) => l.id === pending.lineId) &&\n !issues.some(\n (i) => i.code === pending.code && i.lineId === pending.lineId,\n )\n ) {\n issues.push(pending);\n }\n }\n return { lines: Object.freeze(result), issues, priced };\n}\n"],
5
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/source-menu.ts"],
4
- "sourcesContent": ["import type { Menu } from \"../models\";\n/** Never guess the first of several menus: their schedules may differ. */\nexport function resolveSourceMenu(\n menu: Menu,\n itemId: string,\n menuId?: string,\n): string | undefined {\n const categories = menu.categories.filter((c) => c.itemIds.includes(itemId));\n const sources = menu.menus ?? [\n { id: menu.id, categoryIds: menu.categories.map((c) => c.id) },\n ];\n const placements = menu.items[itemId]?.placements;\n const candidates = sources.filter(\n (source) =>\n (!placements ||\n placements.some(\n (p) =>\n p.menuId === source.id && source.categoryIds.includes(p.categoryId),\n )) &&\n source.categoryIds.some((id) => categories.some((c) => c.id === id)),\n );\n if (menuId !== undefined) {\n return typeof menuId === \"string\" &&\n menuId.trim().length > 0 &&\n menuId.length <= 256 &&\n candidates.some((source) => source.id === menuId)\n ? menuId\n : undefined;\n }\n return candidates.length === 1 ? candidates[0]!.id : undefined;\n}\n"],
5
4
  "mappings": ";AAEO,SAAS,kBACd,MACA,QACA,QACoB;AACpB,QAAM,aAAa,KAAK,WAAW,OAAO,CAAC,MAAM,EAAE,QAAQ,SAAS,MAAM,CAAC;AAC3E,QAAM,UAAU,KAAK,SAAS;AAAA,IAC5B,EAAE,IAAI,KAAK,IAAI,aAAa,KAAK,WAAW,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE;AAAA,EAC/D;AACA,QAAM,aAAa,KAAK,MAAM,MAAM,GAAG;AACvC,QAAM,aAAa,QAAQ;AAAA,IACzB,CAAC,YACE,CAAC,cACA,WAAW;AAAA,MACT,CAAC,MACC,EAAE,WAAW,OAAO,MAAM,OAAO,YAAY,SAAS,EAAE,UAAU;AAAA,IACtE,MACF,OAAO,YAAY,KAAK,CAAC,OAAO,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AAAA,EACvE;AACA,MAAI,WAAW,QAAW;AACxB,WAAO,OAAO,WAAW,YACvB,OAAO,KAAK,EAAE,SAAS,KACvB,OAAO,UAAU,OACjB,WAAW,KAAK,CAAC,WAAW,OAAO,OAAO,MAAM,IAC9C,SACA;AAAA,EACN;AACA,SAAO,WAAW,WAAW,IAAI,WAAW,CAAC,EAAG,KAAK;AACvD;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/storage.ts"],
4
- "sourcesContent": ["import type { StorageLike } from \"../config\";\nimport type { Money } from \"../money\";\nimport { money } from \"../money\";\nimport type { CartFulfilment, CartLineInput } from \"./types\";\nexport type StoredLine = CartLineInput & {\n id: string;\n name: string;\n addedAt: string;\n unitPrice?: Money;\n};\nexport type StoredCart = {\n v: 1;\n lines: StoredLine[];\n fulfilment: CartFulfilment | null;\n promoCode: string | null;\n menuVersion: string;\n updatedAt: number;\n};\nfunction storedMoney(value: Money | undefined): Money | undefined {\n try {\n return value && money(value.amountMinor, value.currency);\n } catch {\n return undefined;\n }\n}\nexport function parseCart(raw: string): StoredCart {\n const v = JSON.parse(raw) as StoredCart;\n if (\n !v ||\n v.v !== 1 ||\n !Array.isArray(v.lines) ||\n v.lines.length > 100 ||\n !Number.isFinite(v.updatedAt) ||\n typeof v.menuVersion !== \"string\" ||\n (v.promoCode !== null && typeof v.promoCode !== \"string\")\n ) {\n throw new Error(\"Invalid saved cart\");\n }\n const ids = new Set<string>();\n for (const line of v.lines) {\n if (\n !line ||\n typeof line.id !== \"string\" ||\n ids.has(line.id) ||\n typeof line.itemId !== \"string\" ||\n typeof line.name !== \"string\" ||\n !Number.isFinite(Date.parse(line.addedAt)) ||\n !Number.isInteger(line.quantity) ||\n line.quantity! < 1 ||\n line.quantity! > 99 ||\n (line.note !== undefined &&\n (typeof line.note !== \"string\" || line.note.length > 280)) ||\n (line.menuId !== undefined &&\n (typeof line.menuId !== \"string\" ||\n !line.menuId.trim() ||\n line.menuId.length > 256)) ||\n (line.variantId !== undefined && typeof line.variantId !== \"string\")\n ) {\n throw new Error(\"Invalid saved cart line\");\n }\n ids.add(line.id);\n if (\n !Array.isArray(line.choices) ||\n line.choices.length > 1000 ||\n line.choices.some(\n (c) =>\n !c ||\n typeof c.groupId !== \"string\" ||\n typeof c.choiceId !== \"string\" ||\n !Number.isInteger(c.quantity) ||\n c.quantity! < 1 ||\n c.quantity! > 99,\n )\n ) {\n throw new Error(\"Invalid saved choices\");\n }\n if (\n !line.inputs ||\n typeof line.inputs !== \"object\" ||\n Array.isArray(line.inputs) ||\n Object.values(line.inputs).some((t) => typeof t !== \"string\")\n ) {\n throw new Error(\"Invalid saved inputs\");\n }\n }\n if (v.fulfilment !== null && !validFulfilment(v.fulfilment)) {\n throw new Error(\"Invalid saved fulfilment\");\n }\n return {\n v: 1,\n lines: v.lines.map((l) => {\n const unitPrice = storedMoney(l.unitPrice);\n return {\n id: l.id,\n itemId: l.itemId,\n ...(l.menuId !== undefined ? { menuId: l.menuId } : {}),\n name: l.name,\n addedAt: l.addedAt,\n ...(unitPrice ? { unitPrice } : {}),\n quantity: l.quantity!,\n choices: l.choices!,\n inputs: l.inputs!,\n ...(l.variantId ? { variantId: l.variantId } : {}),\n ...(l.note !== undefined ? { note: l.note } : {}),\n };\n }),\n fulfilment: v.fulfilment,\n promoCode: v.promoCode,\n menuVersion: v.menuVersion,\n updatedAt: v.updatedAt,\n };\n}\nexport function validFulfilment(f: CartFulfilment): boolean {\n if (\n !f ||\n ![\"pickup\", \"delivery\", \"dine_in\"].includes(f.type) ||\n typeof f.branchId !== \"string\"\n ) {\n return false;\n }\n if (\n \"scheduledFor\" in f &&\n f.scheduledFor !== undefined &&\n !Number.isFinite(Date.parse(f.scheduledFor))\n ) {\n return false;\n }\n if (f.type === \"delivery\") {\n const a = f.address;\n if (!a || typeof a.line1 !== \"string\" || !a.line1.trim()) {\n return false;\n }\n if (\n [a.line2, a.city, a.placeId, a.instructions, f.deliveryRegionId].some(\n (s) => s !== undefined && typeof s !== \"string\",\n )\n ) {\n return false;\n }\n if (\n a.coordinates &&\n (!Number.isFinite(a.coordinates.lat) ||\n !Number.isFinite(a.coordinates.lng) ||\n Math.abs(a.coordinates.lat) > 90 ||\n Math.abs(a.coordinates.lng) > 180)\n ) {\n return false;\n }\n }\n return (\n f.type !== \"dine_in\" || f.table === undefined || typeof f.table === \"string\"\n );\n}\n/** Lazy access: constructing a client or rendering it never reads browser storage. */\nexport function createCartStorage(\n provided: StorageLike | undefined,\n warn: (message: string) => void,\n) {\n let storage: StorageLike | undefined;\n let initialized = false;\n let failed = false;\n let warned = false;\n const memory = new Map<string, string>();\n const warning = (message: string) => {\n if (!warned) {\n warned = true;\n warn(message);\n }\n };\n const access = <T>(fn: (storage: StorageLike) => T, fallback: () => T): T => {\n try {\n if (!initialized) {\n initialized = true;\n storage =\n provided ??\n (typeof window === \"undefined\" ? undefined : window.localStorage);\n }\n if (storage && !failed) {\n return fn(storage);\n }\n } catch {\n failed = true;\n warning(\"Cart storage unavailable; using memory for this client\");\n }\n return fallback();\n };\n return {\n warning,\n read(key: string): string | null {\n return access(\n (s) => {\n const value = s.getItem(key);\n if (value !== null) {\n memory.set(key, value);\n } else {\n memory.delete(key);\n }\n return value;\n },\n () => memory.get(key) ?? null,\n );\n },\n write(key: string, value: string) {\n memory.set(key, value);\n access(\n (s) => s.setItem(key, value),\n () => {},\n );\n },\n remove(key: string) {\n memory.delete(key);\n access(\n (s) => s.removeItem(key),\n () => {},\n );\n },\n accepts(area: Storage | null) {\n return !failed && (!area || area === storage);\n },\n sweep(prefix: string, current: string, ttl: number) {\n access(\n (s) => {\n const keys = Array.from({ length: s.length ?? 0 }, (_, index) =>\n s.key?.(index),\n );\n for (const key of keys) {\n if (!key || key === current || !key.startsWith(prefix)) {\n continue;\n }\n try {\n const raw = s.getItem(key);\n if (raw && Date.now() - parseCart(raw).updatedAt > ttl) {\n s.removeItem(key);\n }\n } catch {\n // A malformed sibling belongs to this cart namespace and cannot be restored.\n s.removeItem(key);\n }\n }\n },\n () => {},\n );\n },\n };\n}\n"],
5
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": [],
4
- "sourcesContent": [],
5
4
  "mappings": "",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/validate.ts"],
4
- "sourcesContent": ["import type { Branch, Item, Menu, OptionGroup } from \"../models\";\nimport { resolveSourceMenu } from \"./source-menu\";\nimport type { CartFix, CartIssue, CartIssueCode, CartLineInput } from \"./types\";\nexport function issue(\n code: CartIssueCode,\n message: string,\n fixes: CartFix[] = [],\n groupId?: string,\n): CartIssue {\n return {\n code,\n severity: \"blocking\",\n message,\n fixes,\n source: \"local\",\n ...(groupId ? { groupId } : {}),\n };\n}\n/** Conditions override base rules in declaration order, exactly like resolveEffectiveAddons. */\nexport function effectiveGroups(\n item: Item,\n input: CartLineInput,\n): OptionGroup[] {\n const selected = new Map<string, Set<string>>();\n for (const choice of input.choices ?? []) {\n const ids = selected.get(choice.groupId) ?? new Set<string>();\n ids.add(choice.choiceId);\n selected.set(choice.groupId, ids);\n }\n return item.optionGroups.map((group) => {\n let required = group.required;\n let { min, max } = group.selection;\n for (const rule of group.conditions ?? []) {\n const chosen = selected.get(rule.groupId) ?? new Set<string>();\n const matches = rule.count\n ? rule.count.op === \"eq\"\n ? chosen.size === rule.count.value\n : rule.count.op === \"gte\"\n ? chosen.size >= rule.count.value\n : chosen.size <= rule.count.value\n : chosen.size > 0 &&\n rule.choiceIds.length > 0 &&\n (rule.match === \"all\"\n ? rule.choiceIds.every((id) => chosen.has(id))\n : rule.choiceIds.some((id) => chosen.has(id)));\n if (!matches) {\n continue;\n }\n required = rule.setRequired ?? required;\n min = rule.setMin ?? min;\n if (rule.setMax != null) {\n max = rule.setMax > 0 ? rule.setMax : undefined;\n }\n }\n return {\n ...group,\n required,\n selection: { min, ...(max !== undefined ? { max } : {}) },\n };\n });\n}\nexport function normalizeInput(\n item: Item,\n input: CartLineInput,\n): CartLineInput {\n const inactive = new Set(\n item.optionGroups.filter((g) => g.isAvailable === false).map((g) => g.id),\n );\n return {\n ...input,\n quantity: input.quantity ?? item.quantity.min,\n choices: (input.choices ?? [])\n .filter((c) => !inactive.has(c.groupId))\n .map((c) => ({ ...c, quantity: c.quantity ?? 1 })),\n inputs: Object.fromEntries(\n Object.entries(input.inputs ?? {}).filter(([id]) => !inactive.has(id)),\n ),\n };\n}\nexport function resolveVariant(item: Item, input: CartLineInput) {\n const attrs = item.optionGroups.filter((g) => g.isAttribute);\n const matches = item.variants.filter(\n (variant) =>\n (!input.variantId || variant.id === input.variantId) &&\n attrs.every((group) => {\n const selected =\n input.choices?.filter((c) => c.groupId === group.id) ?? [];\n return (\n selected.length === 1 &&\n variant.attributeChoices[group.id] === selected[0]!.choiceId\n );\n }),\n );\n return matches.length === 1 ? matches[0] : undefined;\n}\nfunction validInput(kind: OptionGroup[\"kind\"], value: string): boolean {\n switch (kind) {\n case \"number\":\n return Number.isFinite(Number(value));\n case \"date\":\n return (\n /^\\d{4}-\\d{2}-\\d{2}$/.test(value) &&\n Number.isFinite(Date.parse(value)) &&\n new Date(value).toISOString().slice(0, 10) === value\n );\n case \"time\":\n return /^([01]\\d|2[0-3]):[0-5]\\d(:[0-5]\\d)?$/.test(value);\n case \"toggle\":\n return [\"true\", \"false\"].includes(value.toLowerCase());\n default:\n return true;\n }\n}\n/**\n * Check a cart line against catalogue membership, availability, quantities and option rules.\n * Applies conditional group rules and checks that the selection resolves to an available variant.\n *\n * @param item - The current item, or undefined if it is no longer available.\n * @param raw - The shopper's proposed line.\n * @param ctx - The menu and branch context for validation.\n * @returns Local blocking issues with suggested fixes, or an empty array for a valid line.\n */\nexport function validateLine(\n item: Item | undefined,\n raw: CartLineInput,\n ctx: { menu: Menu; branch: Branch },\n): CartIssue[] {\n if (\n !item ||\n item.id !== raw.itemId ||\n !Object.hasOwn(ctx.menu.items, raw.itemId)\n ) {\n return [\n issue(\"item_unavailable\", \"This item is no longer on the menu\", [\n { action: \"remove_line\" },\n ]),\n ];\n }\n const issues: CartIssue[] = [];\n if (!resolveSourceMenu(ctx.menu, raw.itemId, raw.menuId)) {\n // Shoppers can't pick a menu from the cart, so the message names the fix.\n issues.push(\n issue(\n \"item_unavailable\",\n raw.menuId === undefined\n ? `${item.name} is on more than one menu. Remove it and add it again from the menu you want.`\n : `${item.name} is no longer on the menu it was added from.`,\n [{ action: \"remove_line\" }],\n ),\n );\n }\n if (!item.isAvailable) {\n issues.push(\n issue(\"item_unavailable\", `${item.name} is unavailable`, [\n { action: \"remove_line\" },\n ]),\n );\n }\n const input = normalizeInput(item, raw);\n const quantity = input.quantity!;\n const { min, step } = item.quantity;\n const max = Math.min(item.quantity.max ?? 99, 99);\n if (\n !Number.isInteger(quantity) ||\n quantity < min ||\n quantity > max ||\n quantity % step !== 0\n ) {\n const lower = Math.ceil(min / step) * step;\n const upper = Math.floor(max / step) * step;\n const nearest = Math.max(\n lower,\n Math.min(\n upper,\n Math.round((Number.isFinite(quantity) ? quantity : min) / step) * step,\n ),\n );\n issues.push(\n issue(\n \"quantity_limit\",\n `Choose a valid quantity of ${item.name} (${min}\u2013${max}, step ${step})`,\n lower <= upper ? [{ action: \"set_quantity\", quantity: nearest }] : [],\n ),\n );\n }\n if ((input.note?.length ?? 0) > 280) {\n issues.push(issue(\"option_limit\", \"Notes must be at most 280 characters\"));\n }\n for (const choice of input.choices ?? []) {\n if (!item.optionGroups.some((g) => g.id === choice.groupId)) {\n issues.push(\n issue(\n \"option_unavailable\",\n \"This option group no longer exists\",\n [{ action: \"remove_line\" }],\n choice.groupId,\n ),\n );\n }\n }\n for (const id of Object.keys(input.inputs ?? {})) {\n if (!item.optionGroups.some((g) => g.id === id)) {\n issues.push(\n issue(\n \"option_unavailable\",\n \"This input group no longer exists\",\n [{ action: \"remove_line\" }],\n id,\n ),\n );\n }\n }\n const groups = effectiveGroups(item, input);\n const missing = groups.filter(\n (g) =>\n g.isAvailable !== false &&\n g.required &&\n !(input.choices ?? []).some((c) => c.groupId === g.id) &&\n !(input.inputs?.[g.id] ?? \"\").trim(),\n );\n // The host reports missing required groups before checking counts of selected options.\n if (missing.length) {\n return [\n ...issues,\n ...missing.map((g) =>\n issue(\n \"option_required\",\n `Choose ${g.name}`,\n [{ action: \"choose_option\", groupId: g.id }],\n g.id,\n ),\n ),\n ];\n }\n for (const group of groups) {\n if (group.isAvailable === false) {\n continue;\n }\n const choices = input.choices?.filter((c) => c.groupId === group.id) ?? [];\n const text = input.inputs?.[group.id] ?? \"\";\n const value = text.trim();\n const hybrid = group.isInformational && group.kind === \"select\";\n const isInput =\n group.kind !== \"select\" || (hybrid && !group.choices.length);\n const fix: CartFix[] = [{ action: \"choose_option\", groupId: group.id }];\n if (group.required && !choices.length && !value) {\n issues.push(\n issue(\"option_required\", `Choose ${group.name}`, fix, group.id),\n );\n }\n if (value && ((!isInput && !hybrid) || choices.length > 0)) {\n issues.push(\n issue(\n \"option_limit\",\n `Choose either an option or a response for ${group.name}`,\n fix,\n group.id,\n ),\n );\n }\n if (\n (isInput || hybrid) &&\n (text.length > (group.input?.maxLength ?? 500) ||\n (value && !validInput(group.kind, value)))\n ) {\n issues.push(\n issue(\n \"option_limit\",\n `Enter a valid response for ${group.name}`,\n fix,\n group.id,\n ),\n );\n }\n const count = choices.reduce((sum, c) => sum + (c.quantity ?? 1), 0);\n if (\n choices.length &&\n (isInput ||\n count < group.selection.min ||\n count > (group.selection.max ?? Infinity) ||\n new Set(choices.map((c) => c.choiceId)).size !== choices.length)\n ) {\n issues.push(\n issue(\n \"option_limit\",\n `Check the number of options for ${group.name}`,\n fix,\n group.id,\n ),\n );\n }\n for (const selected of choices) {\n const choice = group.choices.find((c) => c.id === selected.choiceId);\n if (!choice?.isAvailable) {\n issues.push(\n issue(\n \"option_unavailable\",\n `An option in ${group.name} is unavailable`,\n [\n { action: \"choose_other_option\", groupId: group.id },\n { action: \"remove_line\" },\n ],\n group.id,\n ),\n );\n }\n const n = selected.quantity ?? 1;\n if (\n !Number.isInteger(n) ||\n n < (choice?.quantity?.min ?? 1) ||\n n > (choice?.quantity?.max ?? 99)\n ) {\n issues.push(\n issue(\n \"option_limit\",\n `Check the option quantity for ${group.name}`,\n fix,\n group.id,\n ),\n );\n }\n }\n }\n const variant = resolveVariant(item, input);\n if (!variant?.isAvailable) {\n const groupId = item.optionGroups.find((g) => g.isAttribute)?.id;\n issues.push(\n issue(\n \"option_limit\",\n \"Choose an available variant\",\n groupId\n ? [{ action: \"choose_option\", groupId }]\n : [{ action: \"remove_line\" }],\n groupId,\n ),\n );\n }\n return issues;\n}\n"],
5
4
  "mappings": ";AACA,SAAS,yBAAyB;AAE3B,SAAS,MACd,MACA,SACA,QAAmB,CAAC,GACpB,SACW;AACX,SAAO;AAAA,IACL;AAAA,IACA,UAAU;AAAA,IACV;AAAA,IACA;AAAA,IACA,QAAQ;AAAA,IACR,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;AAAA,EAC/B;AACF;AAEO,SAAS,gBACd,MACA,OACe;AACf,QAAM,WAAW,oBAAI,IAAyB;AAC9C,aAAW,UAAU,MAAM,WAAW,CAAC,GAAG;AACxC,UAAM,MAAM,SAAS,IAAI,OAAO,OAAO,KAAK,oBAAI,IAAY;AAC5D,QAAI,IAAI,OAAO,QAAQ;AACvB,aAAS,IAAI,OAAO,SAAS,GAAG;AAAA,EAClC;AACA,SAAO,KAAK,aAAa,IAAI,CAAC,UAAU;AACtC,QAAI,WAAW,MAAM;AACrB,QAAI,EAAE,KAAK,IAAI,IAAI,MAAM;AACzB,eAAW,QAAQ,MAAM,cAAc,CAAC,GAAG;AACzC,YAAM,SAAS,SAAS,IAAI,KAAK,OAAO,KAAK,oBAAI,IAAY;AAC7D,YAAM,UAAU,KAAK,QACjB,KAAK,MAAM,OAAO,OAChB,OAAO,SAAS,KAAK,MAAM,QAC3B,KAAK,MAAM,OAAO,QAChB,OAAO,QAAQ,KAAK,MAAM,QAC1B,OAAO,QAAQ,KAAK,MAAM,QAC9B,OAAO,OAAO,KACd,KAAK,UAAU,SAAS,MACvB,KAAK,UAAU,QACZ,KAAK,UAAU,MAAM,CAAC,OAAO,OAAO,IAAI,EAAE,CAAC,IAC3C,KAAK,UAAU,KAAK,CAAC,OAAO,OAAO,IAAI,EAAE,CAAC;AAClD,UAAI,CAAC,SAAS;AACZ;AAAA,MACF;AACA,iBAAW,KAAK,eAAe;AAC/B,YAAM,KAAK,UAAU;AACrB,UAAI,KAAK,UAAU,MAAM;AACvB,cAAM,KAAK,SAAS,IAAI,KAAK,SAAS;AAAA,MACxC;AAAA,IACF;AACA,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,WAAW,EAAE,KAAK,GAAI,QAAQ,SAAY,EAAE,IAAI,IAAI,CAAC,EAAG;AAAA,IAC1D;AAAA,EACF,CAAC;AACH;AACO,SAAS,eACd,MACA,OACe;AACf,QAAM,WAAW,IAAI;AAAA,IACnB,KAAK,aAAa,OAAO,CAAC,MAAM,EAAE,gBAAgB,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,EAAE;AAAA,EAC1E;AACA,SAAO;AAAA,IACL,GAAG;AAAA,IACH,UAAU,MAAM,YAAY,KAAK,SAAS;AAAA,IAC1C,UAAU,MAAM,WAAW,CAAC,GACzB,OAAO,CAAC,MAAM,CAAC,SAAS,IAAI,EAAE,OAAO,CAAC,EACtC,IAAI,CAAC,OAAO,EAAE,GAAG,GAAG,UAAU,EAAE,YAAY,EAAE,EAAE;AAAA,IACnD,QAAQ,OAAO;AAAA,MACb,OAAO,QAAQ,MAAM,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,SAAS,IAAI,EAAE,CAAC;AAAA,IACvE;AAAA,EACF;AACF;AACO,SAAS,eAAe,MAAY,OAAsB;AAC/D,QAAM,QAAQ,KAAK,aAAa,OAAO,CAAC,MAAM,EAAE,WAAW;AAC3D,QAAM,UAAU,KAAK,SAAS;AAAA,IAC5B,CAAC,aACE,CAAC,MAAM,aAAa,QAAQ,OAAO,MAAM,cAC1C,MAAM,MAAM,CAAC,UAAU;AACrB,YAAM,WACJ,MAAM,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,KAAK,CAAC;AAC3D,aACE,SAAS,WAAW,KACpB,QAAQ,iBAAiB,MAAM,EAAE,MAAM,SAAS,CAAC,EAAG;AAAA,IAExD,CAAC;AAAA,EACL;AACA,SAAO,QAAQ,WAAW,IAAI,QAAQ,CAAC,IAAI;AAC7C;AACA,SAAS,WAAW,MAA2B,OAAwB;AACrE,UAAQ,MAAM;AAAA,IACZ,KAAK;AACH,aAAO,OAAO,SAAS,OAAO,KAAK,CAAC;AAAA,IACtC,KAAK;AACH,aACE,sBAAsB,KAAK,KAAK,KAChC,OAAO,SAAS,KAAK,MAAM,KAAK,CAAC,KACjC,IAAI,KAAK,KAAK,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE,MAAM;AAAA,IAEnD,KAAK;AACH,aAAO,uCAAuC,KAAK,KAAK;AAAA,IAC1D,KAAK;AACH,aAAO,CAAC,QAAQ,OAAO,EAAE,SAAS,MAAM,YAAY,CAAC;AAAA,IACvD;AACE,aAAO;AAAA,EACX;AACF;AAUO,SAAS,aACd,MACA,KACA,KACa;AACb,MACE,CAAC,QACD,KAAK,OAAO,IAAI,UAChB,CAAC,OAAO,OAAO,IAAI,KAAK,OAAO,IAAI,MAAM,GACzC;AACA,WAAO;AAAA,MACL,MAAM,oBAAoB,sCAAsC;AAAA,QAC9D,EAAE,QAAQ,cAAc;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,SAAsB,CAAC;AAC7B,MAAI,CAAC,kBAAkB,IAAI,MAAM,IAAI,QAAQ,IAAI,MAAM,GAAG;AAExD,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,IAAI,WAAW,SACX,GAAG,KAAK,IAAI,kFACZ,GAAG,KAAK,IAAI;AAAA,QAChB,CAAC,EAAE,QAAQ,cAAc,CAAC;AAAA,MAC5B;AAAA,IACF;AAAA,EACF;AACA,MAAI,CAAC,KAAK,aAAa;AACrB,WAAO;AAAA,MACL,MAAM,oBAAoB,GAAG,KAAK,IAAI,mBAAmB;AAAA,QACvD,EAAE,QAAQ,cAAc;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,EACF;AACA,QAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,QAAM,WAAW,MAAM;AACvB,QAAM,EAAE,KAAK,KAAK,IAAI,KAAK;AAC3B,QAAM,MAAM,KAAK,IAAI,KAAK,SAAS,OAAO,IAAI,EAAE;AAChD,MACE,CAAC,OAAO,UAAU,QAAQ,KAC1B,WAAW,OACX,WAAW,OACX,WAAW,SAAS,GACpB;AACA,UAAM,QAAQ,KAAK,KAAK,MAAM,IAAI,IAAI;AACtC,UAAM,QAAQ,KAAK,MAAM,MAAM,IAAI,IAAI;AACvC,UAAM,UAAU,KAAK;AAAA,MACnB;AAAA,MACA,KAAK;AAAA,QACH;AAAA,QACA,KAAK,OAAO,OAAO,SAAS,QAAQ,IAAI,WAAW,OAAO,IAAI,IAAI;AAAA,MACpE;AAAA,IACF;AACA,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA,8BAA8B,KAAK,IAAI,KAAK,GAAG,SAAI,GAAG,UAAU,IAAI;AAAA,QACpE,SAAS,QAAQ,CAAC,EAAE,QAAQ,gBAAgB,UAAU,QAAQ,CAAC,IAAI,CAAC;AAAA,MACtE;AAAA,IACF;AAAA,EACF;AACA,OAAK,MAAM,MAAM,UAAU,KAAK,KAAK;AACnC,WAAO,KAAK,MAAM,gBAAgB,sCAAsC,CAAC;AAAA,EAC3E;AACA,aAAW,UAAU,MAAM,WAAW,CAAC,GAAG;AACxC,QAAI,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,EAAE,OAAO,OAAO,OAAO,GAAG;AAC3D,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,UACA,CAAC,EAAE,QAAQ,cAAc,CAAC;AAAA,UAC1B,OAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,aAAW,MAAM,OAAO,KAAK,MAAM,UAAU,CAAC,CAAC,GAAG;AAChD,QAAI,CAAC,KAAK,aAAa,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG;AAC/C,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA;AAAA,UACA,CAAC,EAAE,QAAQ,cAAc,CAAC;AAAA,UAC1B;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,SAAS,gBAAgB,MAAM,KAAK;AAC1C,QAAM,UAAU,OAAO;AAAA,IACrB,CAAC,MACC,EAAE,gBAAgB,SAClB,EAAE,YACF,EAAE,MAAM,WAAW,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,KACrD,EAAE,MAAM,SAAS,EAAE,EAAE,KAAK,IAAI,KAAK;AAAA,EACvC;AAEA,MAAI,QAAQ,QAAQ;AAClB,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG,QAAQ;AAAA,QAAI,CAAC,MACd;AAAA,UACE;AAAA,UACA,UAAU,EAAE,IAAI;AAAA,UAChB,CAAC,EAAE,QAAQ,iBAAiB,SAAS,EAAE,GAAG,CAAC;AAAA,UAC3C,EAAE;AAAA,QACJ;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,aAAW,SAAS,QAAQ;AAC1B,QAAI,MAAM,gBAAgB,OAAO;AAC/B;AAAA,IACF;AACA,UAAM,UAAU,MAAM,SAAS,OAAO,CAAC,MAAM,EAAE,YAAY,MAAM,EAAE,KAAK,CAAC;AACzE,UAAM,OAAO,MAAM,SAAS,MAAM,EAAE,KAAK;AACzC,UAAM,QAAQ,KAAK,KAAK;AACxB,UAAM,SAAS,MAAM,mBAAmB,MAAM,SAAS;AACvD,UAAM,UACJ,MAAM,SAAS,YAAa,UAAU,CAAC,MAAM,QAAQ;AACvD,UAAM,MAAiB,CAAC,EAAE,QAAQ,iBAAiB,SAAS,MAAM,GAAG,CAAC;AACtE,QAAI,MAAM,YAAY,CAAC,QAAQ,UAAU,CAAC,OAAO;AAC/C,aAAO;AAAA,QACL,MAAM,mBAAmB,UAAU,MAAM,IAAI,IAAI,KAAK,MAAM,EAAE;AAAA,MAChE;AAAA,IACF;AACA,QAAI,UAAW,CAAC,WAAW,CAAC,UAAW,QAAQ,SAAS,IAAI;AAC1D,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,6CAA6C,MAAM,IAAI;AAAA,UACvD;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,SACG,WAAW,YACX,KAAK,UAAU,MAAM,OAAO,aAAa,QACvC,SAAS,CAAC,WAAW,MAAM,MAAM,KAAK,IACzC;AACA,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,8BAA8B,MAAM,IAAI;AAAA,UACxC;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,QAAQ,QAAQ,OAAO,CAAC,KAAK,MAAM,OAAO,EAAE,YAAY,IAAI,CAAC;AACnE,QACE,QAAQ,WACP,WACC,QAAQ,MAAM,UAAU,OACxB,SAAS,MAAM,UAAU,OAAO,aAChC,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,SAAS,QAAQ,SAC3D;AACA,aAAO;AAAA,QACL;AAAA,UACE;AAAA,UACA,mCAAmC,MAAM,IAAI;AAAA,UAC7C;AAAA,UACA,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,eAAW,YAAY,SAAS;AAC9B,YAAM,SAAS,MAAM,QAAQ,KAAK,CAAC,MAAM,EAAE,OAAO,SAAS,QAAQ;AACnE,UAAI,CAAC,QAAQ,aAAa;AACxB,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,gBAAgB,MAAM,IAAI;AAAA,YAC1B;AAAA,cACE,EAAE,QAAQ,uBAAuB,SAAS,MAAM,GAAG;AAAA,cACnD,EAAE,QAAQ,cAAc;AAAA,YAC1B;AAAA,YACA,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AACA,YAAM,IAAI,SAAS,YAAY;AAC/B,UACE,CAAC,OAAO,UAAU,CAAC,KACnB,KAAK,QAAQ,UAAU,OAAO,MAC9B,KAAK,QAAQ,UAAU,OAAO,KAC9B;AACA,eAAO;AAAA,UACL;AAAA,YACE;AAAA,YACA,iCAAiC,MAAM,IAAI;AAAA,YAC3C;AAAA,YACA,MAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,QAAM,UAAU,eAAe,MAAM,KAAK;AAC1C,MAAI,CAAC,SAAS,aAAa;AACzB,UAAM,UAAU,KAAK,aAAa,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG;AAC9D,WAAO;AAAA,MACL;AAAA,QACE;AAAA,QACA;AAAA,QACA,UACI,CAAC,EAAE,QAAQ,iBAAiB,QAAQ,CAAC,IACrC,CAAC,EAAE,QAAQ,cAAc,CAAC;AAAA,QAC9B;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/wire.ts"],
4
- "sourcesContent": ["import type {\n CartFulfilment,\n CartLine,\n WireFulfilment,\n WireLine,\n} from \"./types\";\nexport function wireLine(line: CartLine): WireLine {\n return {\n line_id: line.id,\n item_id: line.itemId,\n ...(line.menuId !== undefined ? { menu_id: line.menuId } : {}),\n quantity: line.quantity,\n ...(line.variantId ? { variant_id: line.variantId } : {}),\n options: line.choices.map((c) => ({\n group_id: c.groupId,\n choice_id: c.choiceId,\n quantity: c.quantity,\n })),\n inputs: { ...line.inputs },\n ...(line.note !== undefined ? { note: line.note } : {}),\n };\n}\n/**\n * Convert a cart fulfilment selection to the API field names used by quotes and checkout.\n * Includes delivery address details, a schedule or a dine-in table when present.\n *\n * @param f - The shopper's selected fulfilment.\n * @returns Fulfilment fields without the branch ID. Checkout sessions accept pickup or delivery only.\n */\nexport function wireFulfilment(f: CartFulfilment): WireFulfilment {\n return {\n type: f.type,\n ...(\"scheduledFor\" in f && f.scheduledFor\n ? { scheduled_for: f.scheduledFor }\n : {}),\n ...(f.type === \"dine_in\" && f.table ? { table: f.table } : {}),\n ...(f.type === \"delivery\"\n ? {\n ...(f.deliveryRegionId !== undefined\n ? { delivery_region_id: f.deliveryRegionId }\n : {}),\n address: {\n line1: f.address.line1,\n ...(f.address.line2 ? { line2: f.address.line2 } : {}),\n ...(f.address.city ? { city: f.address.city } : {}),\n ...(f.address.placeId ? { place_id: f.address.placeId } : {}),\n ...(f.address.instructions\n ? { instructions: f.address.instructions }\n : {}),\n ...(f.address.coordinates\n ? {\n lat: f.address.coordinates.lat,\n lng: f.address.coordinates.lng,\n }\n : {}),\n },\n }\n : {}),\n };\n}\n"],
5
4
  "mappings": ";AAMO,SAAS,SAAS,MAA0B;AACjD,SAAO;AAAA,IACL,SAAS,KAAK;AAAA,IACd,SAAS,KAAK;AAAA,IACd,GAAI,KAAK,WAAW,SAAY,EAAE,SAAS,KAAK,OAAO,IAAI,CAAC;AAAA,IAC5D,UAAU,KAAK;AAAA,IACf,GAAI,KAAK,YAAY,EAAE,YAAY,KAAK,UAAU,IAAI,CAAC;AAAA,IACvD,SAAS,KAAK,QAAQ,IAAI,CAAC,OAAO;AAAA,MAChC,UAAU,EAAE;AAAA,MACZ,WAAW,EAAE;AAAA,MACb,UAAU,EAAE;AAAA,IACd,EAAE;AAAA,IACF,QAAQ,EAAE,GAAG,KAAK,OAAO;AAAA,IACzB,GAAI,KAAK,SAAS,SAAY,EAAE,MAAM,KAAK,KAAK,IAAI,CAAC;AAAA,EACvD;AACF;AAQO,SAAS,eAAe,GAAmC;AAChE,SAAO;AAAA,IACL,MAAM,EAAE;AAAA,IACR,GAAI,kBAAkB,KAAK,EAAE,eACzB,EAAE,eAAe,EAAE,aAAa,IAChC,CAAC;AAAA,IACL,GAAI,EAAE,SAAS,aAAa,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAAA,IAC5D,GAAI,EAAE,SAAS,aACX;AAAA,MACE,GAAI,EAAE,qBAAqB,SACvB,EAAE,oBAAoB,EAAE,iBAAiB,IACzC,CAAC;AAAA,MACL,SAAS;AAAA,QACP,OAAO,EAAE,QAAQ;AAAA,QACjB,GAAI,EAAE,QAAQ,QAAQ,EAAE,OAAO,EAAE,QAAQ,MAAM,IAAI,CAAC;AAAA,QACpD,GAAI,EAAE,QAAQ,OAAO,EAAE,MAAM,EAAE,QAAQ,KAAK,IAAI,CAAC;AAAA,QACjD,GAAI,EAAE,QAAQ,UAAU,EAAE,UAAU,EAAE,QAAQ,QAAQ,IAAI,CAAC;AAAA,QAC3D,GAAI,EAAE,QAAQ,eACV,EAAE,cAAc,EAAE,QAAQ,aAAa,IACvC,CAAC;AAAA,QACL,GAAI,EAAE,QAAQ,cACV;AAAA,UACE,KAAK,EAAE,QAAQ,YAAY;AAAA,UAC3B,KAAK,EAAE,QAAQ,YAAY;AAAA,QAC7B,IACA,CAAC;AAAA,MACP;AAAA,IACF,IACA,CAAC;AAAA,EACP;AACF;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/cart/working-set.ts"],
4
- "sourcesContent": ["import type { MenuResource, StoreResource } from \"../client\";\nimport { ZappieError } from \"../errors\";\nimport type { Item, Menu } from \"../models\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\n\n/** Cart-only catalogue projection. Never installed in the complete-menu cache. */\nexport type CartWorkingSet = Menu & {\n kind: \"working-set\";\n completeness: \"partial\";\n};\nexport function createWorkingSet(deps: {\n menu: MenuResource;\n store: StoreResource;\n transport: Transport;\n context: () => RequestCtx;\n peekItem: (id: string, branch: string) => Item | undefined;\n readItem: (id: string, branch: string, fresh?: boolean) => Promise<Item>;\n}) {\n const compose = (\n branchId: string,\n ids: readonly string[],\n metadata?: Menu,\n ): CartWorkingSet => {\n const source = metadata ?? deps.menu.peek(branchId);\n const items = Object.fromEntries(\n [...new Set(ids)].flatMap((id) => {\n const item = deps.peekItem(id, branchId) ?? source?.items[id];\n return item ? [[id, item]] : [];\n }),\n );\n return {\n id: `branch:${branchId}`,\n name: \"Cart working set\",\n branchId,\n version: \"\",\n ...source,\n kind: \"working-set\",\n completeness: \"partial\",\n items,\n categories: (source?.categories ?? []).map((category) => ({\n ...category,\n itemIds: Object.values(items)\n .filter((item) =>\n item.placements\n ? item.placements.some(\n (p) =>\n p.categoryId === category.id &&\n (\n source?.menus ?? [\n { id: source?.id, categoryIds: [category.id] },\n ]\n ).some(\n (m) =>\n m.id === p.menuId &&\n m.categoryIds.includes(category.id),\n ),\n )\n : category.itemIds.includes(item.id),\n )\n .map((item) => item.id),\n })),\n };\n };\n const peek = (branchId: string, ids: readonly string[]) => {\n const value = deps.menu.peek(branchId);\n return value && value.completeness !== \"partial\"\n ? value\n : compose(branchId, ids);\n };\n return {\n peek,\n async read(\n branchId: string,\n ids: readonly string[],\n fresh = false,\n ): Promise<Menu> {\n const cached = peek(branchId, ids);\n if (!ids.length || (!fresh && cached.completeness !== \"partial\")) {\n return cached;\n }\n const response = fresh\n ? await deps.transport.getMenu({\n ...deps.context(),\n branchId,\n metadataOnly: true,\n })\n : undefined;\n const metadata =\n response && \"menu\" in response\n ? response.menu\n : await deps.menu.get({ branch: branchId, metadataOnly: true });\n if (metadata.branchId !== branchId) {\n throw new ZappieError(\n \"server_error\",\n \"Cart metadata belongs to another branch\",\n );\n }\n deps.menu.hydrate(metadata);\n if (metadata.completeness !== \"partial\") {\n return metadata;\n }\n await Promise.all(\n [...new Set(ids)].map(async (id) => {\n try {\n await deps.readItem(id, branchId, fresh);\n } catch (error) {\n if ((error as { code?: string }).code !== \"item_not_found\") {\n throw error;\n }\n }\n }),\n );\n return compose(branchId, ids, metadata);\n },\n };\n}\n"],
5
4
  "mappings": ";AACA,SAAS,mBAAmB;AASrB,SAAS,iBAAiB,MAO9B;AACD,QAAM,UAAU,CACd,UACA,KACA,aACmB;AACnB,UAAM,SAAS,YAAY,KAAK,KAAK,KAAK,QAAQ;AAClD,UAAM,QAAQ,OAAO;AAAA,MACnB,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,EAAE,QAAQ,CAAC,OAAO;AAChC,cAAM,OAAO,KAAK,SAAS,IAAI,QAAQ,KAAK,QAAQ,MAAM,EAAE;AAC5D,eAAO,OAAO,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC;AAAA,MAChC,CAAC;AAAA,IACH;AACA,WAAO;AAAA,MACL,IAAI,UAAU,QAAQ;AAAA,MACtB,MAAM;AAAA,MACN;AAAA,MACA,SAAS;AAAA,MACT,GAAG;AAAA,MACH,MAAM;AAAA,MACN,cAAc;AAAA,MACd;AAAA,MACA,aAAa,QAAQ,cAAc,CAAC,GAAG,IAAI,CAAC,cAAc;AAAA,QACxD,GAAG;AAAA,QACH,SAAS,OAAO,OAAO,KAAK,EACzB;AAAA,UAAO,CAAC,SACP,KAAK,aACD,KAAK,WAAW;AAAA,YACd,CAAC,MACC,EAAE,eAAe,SAAS,OAExB,QAAQ,SAAS;AAAA,cACf,EAAE,IAAI,QAAQ,IAAI,aAAa,CAAC,SAAS,EAAE,EAAE;AAAA,YAC/C,GACA;AAAA,cACA,CAAC,MACC,EAAE,OAAO,EAAE,UACX,EAAE,YAAY,SAAS,SAAS,EAAE;AAAA,YACtC;AAAA,UACJ,IACA,SAAS,QAAQ,SAAS,KAAK,EAAE;AAAA,QACvC,EACC,IAAI,CAAC,SAAS,KAAK,EAAE;AAAA,MAC1B,EAAE;AAAA,IACJ;AAAA,EACF;AACA,QAAM,OAAO,CAAC,UAAkB,QAA2B;AACzD,UAAM,QAAQ,KAAK,KAAK,KAAK,QAAQ;AACrC,WAAO,SAAS,MAAM,iBAAiB,YACnC,QACA,QAAQ,UAAU,GAAG;AAAA,EAC3B;AACA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,KACJ,UACA,KACA,QAAQ,OACO;AACf,YAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAI,CAAC,IAAI,UAAW,CAAC,SAAS,OAAO,iBAAiB,WAAY;AAChE,eAAO;AAAA,MACT;AACA,YAAM,WAAW,QACb,MAAM,KAAK,UAAU,QAAQ;AAAA,QAC3B,GAAG,KAAK,QAAQ;AAAA,QAChB;AAAA,QACA,cAAc;AAAA,MAChB,CAAC,IACD;AACJ,YAAM,WACJ,YAAY,UAAU,WAClB,SAAS,OACT,MAAM,KAAK,KAAK,IAAI,EAAE,QAAQ,UAAU,cAAc,KAAK,CAAC;AAClE,UAAI,SAAS,aAAa,UAAU;AAClC,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,WAAK,KAAK,QAAQ,QAAQ;AAC1B,UAAI,SAAS,iBAAiB,WAAW;AACvC,eAAO;AAAA,MACT;AACA,YAAM,QAAQ;AAAA,QACZ,CAAC,GAAG,IAAI,IAAI,GAAG,CAAC,EAAE,IAAI,OAAO,OAAO;AAClC,cAAI;AACF,kBAAM,KAAK,SAAS,IAAI,UAAU,KAAK;AAAA,UACzC,SAAS,OAAO;AACd,gBAAK,MAA4B,SAAS,kBAAkB;AAC1D,oBAAM;AAAA,YACR;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH;AACA,aAAO,QAAQ,UAAU,KAAK,QAAQ;AAAA,IACxC;AAAA,EACF;AACF;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/client.ts"],
4
- "sourcesContent": ["import { apiError, requestWithRetry, wait } from \"../internal/customer-http\";\nimport { CheckoutError } from \"./error\";\nimport { ZappieError } from \"./sdk\";\nimport { mapCheckoutSession } from \"./session\";\nimport type {\n AwaitCompletionOptions,\n CheckoutClientOptions,\n CheckoutCompletion,\n CheckoutRequest,\n CheckoutSession,\n OpenCheckoutSession,\n} from \"./types\";\n\nconst DEFAULT_CUSTOMER_BASE = \"/_zappie/api\";\n\nasync function error(response: Response): Promise<CheckoutError> {\n const value = await apiError(\n response,\n `The checkout service answered ${response.status}`,\n );\n return new CheckoutError(\n response.status,\n value.apiCode,\n value.message,\n value.param,\n value.issues,\n );\n}\n\n// REST reads the rider note from fulfilment.instructions and accepts only its listed address\n// fields, while a cart's wire fulfilment keeps the note on the address.\nfunction checkoutBody(body: CheckoutRequest): CheckoutRequest {\n const address = body.fulfilment.address as\n | (CheckoutRequest[\"fulfilment\"][\"address\"] & {\n line2?: string;\n instructions?: string;\n })\n | undefined;\n if (!address) {\n return body;\n }\n const { line2: _line2, instructions, ...rest } = address;\n return {\n ...body,\n fulfilment: {\n ...body.fulfilment,\n ...(body.fulfilment.instructions === undefined && instructions\n ? { instructions }\n : {}),\n address: rest,\n },\n };\n}\n\n/**\n * Create a client that opens checkout sessions, reads them and polls for completion.\n *\n * @param options - Override the default `/_zappie/api` base or fetch implementation.\n * @returns A checkout client. Retain each idempotency key when retrying the same cart.\n */\nexport function createCheckout(options: CheckoutClientOptions = {}) {\n const base = (options.customerBase ?? DEFAULT_CUSTOMER_BASE).replace(\n /\\/+$/,\n \"\",\n );\n const fetcher = options.fetch ?? globalThis.fetch;\n const request = async (\n path: string,\n init: RequestInit,\n ): Promise<CheckoutSession> => {\n const response = await requestWithRetry(\n fetcher,\n base + path,\n init,\n \"Could not reach checkout\",\n );\n if (!response.ok) {\n throw await error(response);\n }\n return mapCheckoutSession(await response.json());\n };\n const read = (id: string, signal?: AbortSignal) =>\n request(`/checkout/sessions/${encodeURIComponent(id)}`, {\n method: \"GET\",\n ...(signal ? { signal } : {}),\n });\n return {\n /** The caller retains this key and reuses it when retrying the same cart. */\n async open(\n body: CheckoutRequest,\n idempotencyKey: string,\n ): Promise<OpenCheckoutSession> {\n const session = await request(\"/checkout/sessions\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n },\n body: JSON.stringify(checkoutBody(body)),\n });\n if (!session.url) {\n throw new ZappieError(\n \"server_error\",\n \"Checkout session has no payment URL\",\n );\n }\n globalThis.__zappieEmit?.(\"checkout:open\", session);\n return { ...session, url: session.url };\n },\n session(id: string): Promise<CheckoutSession> {\n return read(id);\n },\n async awaitCompletion(\n id: string,\n options: AwaitCompletionOptions = {},\n ): Promise<CheckoutCompletion> {\n const interval = options.intervalMs ?? 3_000;\n if (!Number.isFinite(interval) || interval < 0) {\n throw new ZappieError(\n \"invalid_request\",\n \"intervalMs cannot be negative\",\n );\n }\n for (;;) {\n options.signal?.throwIfAborted();\n try {\n const session = await read(id, options.signal);\n if (session.status === \"completed\" && session.order_id) {\n globalThis.__zappieEmit?.(\"checkout:completed\", session);\n return {\n ...session,\n status: \"completed\",\n order_id: session.order_id,\n };\n }\n if (session.status === \"expired\" || session.status === \"cancelled\") {\n return { ...session, status: session.status };\n }\n } catch (failure) {\n options.signal?.throwIfAborted();\n if (\n failure instanceof ZappieError &&\n failure.status !== undefined &&\n failure.status >= 400 &&\n failure.status < 500\n ) {\n throw failure;\n }\n }\n await wait(interval, options.signal);\n }\n },\n };\n}\n\n/**\n * The session creation, lookup and completion methods returned by createCheckout.\n */\nexport type CheckoutClient = ReturnType<typeof createCheckout>;\n"],
5
4
  "mappings": "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",
6
5
  "names": ["options"]
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/embed.ts"],
4
- "sourcesContent": ["import type { CheckoutClient } from \"./client\";\nimport { ZappieError } from \"./sdk\";\nimport type { OpenCheckoutSession } from \"./types\";\n\n/** How checkout opens. Auto redirects in in-app browsers and framed pages, else a modal on desktop and a sheet on mobile. */\nexport type CheckoutPresentation =\n \"auto\" | \"modal\" | \"sheet\" | \"fullscreen\" | \"redirect\";\n\n/** The checkout look from toCheckoutTheme in @zappie/tokens/checkout. The checkout validates it before use. */\nexport type CheckoutTheme = {\n version: 1;\n tokens: Partial<Record<`--z-${string}`, string>>;\n logo?: { url: string; alt: string };\n fonts?: { family: string; role: \"body\" | \"display\"; weights?: number[] }[];\n copy?: { payButton?: string; successTitle?: string };\n};\n\n/**\n * Why checkout can't go on. `code` is `session_expired`, `session_invalid` or `internal`. When `retryable` is true,\n * checkout stays open and offers to try again.\n */\nexport type CheckoutEmbedError = {\n code: string;\n message: string;\n retryable: boolean;\n};\n\n/** Presentation, theme, step and error reporting for an embedded checkout. */\nexport type EmbedOptions = {\n presentation?: CheckoutPresentation;\n theme?: CheckoutTheme;\n /** Called with each checkout step, and whether a payment has started. */\n onStep?: (step: string, paying: boolean) => void;\n /** Called when checkout can't go on. A retryable error keeps it open, and any other error closes it with its code as the reason. */\n onError?: (error: CheckoutEmbedError) => void;\n};\n\n/** How an embedded checkout ended. A completed result is confirmed by the server first. */\nexport type CheckoutResult =\n | { status: \"completed\"; orderId: string }\n | { status: \"cancelled\"; reason: string }\n | { status: \"redirected\" };\n\nconst PARAM = \"zappie_checkout\";\nconst finished = new Set<string>();\nlet request: (() => void) | undefined;\nconst media = (query: string) => matchMedia(query).matches;\n\n/** Resolve auto to the presentation this browser gets. */\nexport function checkoutPresentation(\n presentation: CheckoutPresentation = \"auto\",\n): Exclude<CheckoutPresentation, \"auto\"> {\n if (presentation !== \"auto\") {\n return presentation;\n }\n if (\n window.top !== window ||\n /FBA[NV]|Instagram|TikTok|musical_ly|Bytedance|Line\\//.test(\n navigator.userAgent,\n )\n ) {\n return \"redirect\";\n }\n return media(\"(min-width:640px) and (pointer:fine),(min-width:1024px)\")\n ? \"modal\"\n : \"sheet\";\n}\n\n/** Ask the open checkout to close. Mid-payment it asks the shopper first. */\nexport function closeCheckout(): void {\n request?.();\n}\n\n/** On load, drop a stale checkout entry from the address and read its session. It never reopens checkout. */\nexport async function resumeCheckout(\n checkout: CheckoutClient,\n): Promise<CheckoutResult | null> {\n const url = new URL(location.href);\n const id = url.searchParams.get(PARAM);\n if (!id) {\n return null;\n }\n url.searchParams.delete(PARAM);\n history.replaceState(history.state, \"\", url);\n const session = await checkout.session(id);\n return session.status === \"completed\" && session.order_id\n ? { status: \"completed\", orderId: session.order_id }\n : null;\n}\n\n/**\n * Open a checkout session over the page and settle when it ends. Only Zappie's checkout, or one on this machine, is framed. Back and Escape ask the checkout to step back or\n * close. A completed result waits for the server to confirm the session. A completed session can't be reopened.\n */\nexport function embedCheckout(\n checkout: CheckoutClient,\n session: OpenCheckoutSession,\n options: EmbedOptions = {},\n): Promise<CheckoutResult> {\n const url = new URL(session.url);\n if (\n request ||\n session.status !== \"open\" ||\n finished.has(session.id) ||\n !(\n /^https:\\/\\/checkout\\.(stg\\.)?zappie\\.ai$/.test(url.origin) ||\n /^http:\\/\\/(localhost|127\\.0\\.0\\.1)(:\\d+)?$/.test(url.origin)\n )\n ) {\n return Promise.reject(\n new ZappieError(\n \"invalid_request\",\n \"This checkout session can't be opened\",\n ),\n );\n }\n const shown = checkoutPresentation(options.presentation);\n if (shown === \"redirect\") {\n location.assign(session.url);\n return Promise.resolve({ status: \"redirected\" });\n }\n url.pathname = `/embed/${encodeURIComponent(session.id)}`;\n // The frame gets no referrer, so the checkout learns this page's origin from its address. It checks it first.\n url.searchParams.set(\"origin\", location.origin);\n const doc = document;\n const body = doc.body;\n const root = doc.createElement(\"div\");\n const panel = doc.createElement(\"div\");\n const handle = doc.createElement(\"div\");\n const frame = doc.createElement(\"iframe\");\n const sheet = shown === \"sheet\";\n const still = media(\"(prefers-reduced-motion:reduce)\");\n const opener = doc.activeElement as HTMLElement | null;\n const y = scrollY;\n const bodyStyle = body.style.cssText;\n const restoration = history.scrollRestoration;\n const inert = [...body.children].filter(\n (el): el is HTMLElement => !(el as HTMLElement).inert,\n );\n const abort = new AbortController();\n const vv = window.visualViewport;\n let ready = false;\n let paying = false;\n let height = 640;\n let settle: (result: CheckoutResult) => void = () => {};\n\n root.setAttribute(\"data-zappie-checkout\", shown);\n root.setAttribute(\"role\", \"dialog\");\n root.setAttribute(\"aria-modal\", \"true\");\n root.setAttribute(\"aria-label\", \"Checkout\");\n root.style.cssText =\n \"position:fixed;inset:0;z-index:2147483647;background:var(--z-checkout-backdrop,rgb(0 0 0/.5))\";\n panel.style.cssText = `position:absolute;overflow:hidden;display:flex;flex-direction:column;background:var(--z-surface,#fff);${\n shown === \"fullscreen\"\n ? \"inset:0\"\n : sheet\n ? \"left:0;right:0;border-radius:var(--z-checkout-radius,16px) var(--z-checkout-radius,16px) 0 0\"\n : \"inset:0;margin:auto;width:min(480px,100vw - 32px);border-radius:var(--z-checkout-radius,16px)\"\n }`;\n handle.style.cssText =\n \"flex:none;height:24px;touch-action:none;cursor:grab;background:radial-gradient(closest-side,var(--z-border,#ccc) 99%,#0000) 50%/40px 5px no-repeat\";\n frame.title = \"Checkout\";\n frame.src = url.href;\n frame.allow = \"payment 'src'; publickey-credentials-get 'src'\";\n frame.referrerPolicy = \"no-referrer\";\n frame.style.cssText = \"flex:1;width:100%;border:0;display:block\";\n if (sheet) {\n panel.append(handle);\n }\n panel.append(frame);\n root.append(panel);\n\n const layout = () => {\n const view = vv ?? { height: innerHeight, offsetTop: 0 };\n if (sheet) {\n panel.style.height = `${Math.round(view.height * 0.92)}px`;\n panel.style.bottom = `${Math.max(0, innerHeight - view.offsetTop - view.height)}px`;\n } else if (shown === \"modal\") {\n panel.style.height = `${Math.min(height, view.height - 32)}px`;\n }\n };\n const post = (type: string, payload: object = {}) =>\n frame.contentWindow?.postMessage(\n { source: \"zappie-checkout\", v: 1, session: session.id, type, payload },\n url.origin,\n );\n const finish = (result: CheckoutResult, popped?: boolean) => {\n abort.abort();\n request = undefined;\n removeEventListener(\"message\", onMessage);\n removeEventListener(\"popstate\", onPop);\n removeEventListener(\"keydown\", onKey);\n vv?.removeEventListener(\"resize\", layout);\n vv?.removeEventListener(\"scroll\", layout);\n root.remove();\n inert.forEach((el) => (el.inert = false));\n body.style.cssText = bodyStyle;\n // WebKit scrolls the page again after popstate, so the scroll is set once more a task later.\n const restore = () => {\n scrollTo(0, y);\n setTimeout(() => {\n scrollTo(0, y);\n history.scrollRestoration = restoration;\n });\n };\n restore();\n opener?.focus({ preventScroll: true });\n if (!popped && history.state?.[PARAM] === session.id) {\n history.scrollRestoration = \"manual\";\n addEventListener(\"popstate\", restore, { once: true });\n history.back();\n }\n settle(result);\n };\n const close = () =>\n ready\n ? post(\"close_request\")\n : finish({ status: \"cancelled\", reason: \"user\" });\n const onKey = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") {\n close();\n }\n };\n const onPop = () => {\n if (!ready) {\n return finish({ status: \"cancelled\", reason: \"user\" }, true);\n }\n history.pushState(\n { ...history.state, [PARAM]: session.id },\n \"\",\n location.href,\n );\n post(\"close_request\");\n };\n const onMessage = (event: MessageEvent) => {\n const data = event.data;\n if (\n event.origin !== url.origin ||\n event.source !== frame.contentWindow ||\n data?.source !== \"zappie-checkout\" ||\n data.v !== 1 ||\n data.session !== session.id\n ) {\n return;\n }\n const payload = Object(data.payload);\n if (data.type === \"ready\" || data.type === \"step\") {\n if (data.type === \"ready\") {\n ready = true;\n frame.focus();\n if (options.theme) {\n post(\"theme\", options.theme);\n }\n }\n paying = payload.paying === true;\n if (typeof payload.step === \"string\") {\n options.onStep?.(payload.step, paying);\n }\n } else if (data.type === \"resize\" && Number.isFinite(payload.height)) {\n height = payload.height;\n layout();\n } else if (data.type === \"completed\") {\n checkout\n .awaitCompletion(session.id, { signal: abort.signal, intervalMs: 1500 })\n .then(\n (done) => {\n if (done.status === \"completed\") {\n finished.add(session.id);\n finish({ status: \"completed\", orderId: done.order_id });\n } else {\n finish({ status: \"cancelled\", reason: done.status });\n }\n },\n () => {},\n );\n } else if (data.type === \"cancelled\" || data.type === \"error\") {\n const retry = data.type === \"error\" && payload.retryable === true;\n if (data.type === \"error\") {\n options.onError?.({\n code: payload.code,\n message: payload.message,\n retryable: retry,\n });\n }\n if (retry) {\n // The checkout shows Try again, and its next ready picks up from there. Until then Back and Escape close.\n ready = paying = false;\n } else {\n finish({\n status: \"cancelled\",\n reason: String(payload.reason ?? payload.code ?? \"user\"),\n });\n }\n }\n };\n\n let start = 0;\n handle.onpointerdown = (event) => {\n if (paying) {\n return;\n }\n start = event.clientY;\n handle.setPointerCapture?.(event.pointerId);\n };\n handle.onpointermove = (event) => {\n if (start) {\n panel.style.transform = `translateY(${Math.max(0, event.clientY - start)}px)`;\n }\n };\n handle.onpointerup = handle.onpointercancel = (event) => {\n const moved = start ? event.clientY - start : 0;\n start = 0;\n panel.style.transform = \"\";\n if (!paying && moved > panel.offsetHeight / 4) {\n finish({ status: \"cancelled\", reason: \"user\" });\n }\n };\n\n history.pushState(\n { ...history.state, [PARAM]: session.id },\n \"\",\n (() => {\n const here = new URL(location.href);\n here.searchParams.set(PARAM, session.id);\n return here;\n })(),\n );\n addEventListener(\"message\", onMessage);\n addEventListener(\"popstate\", onPop);\n addEventListener(\"keydown\", onKey);\n vv?.addEventListener(\"resize\", layout);\n vv?.addEventListener(\"scroll\", layout);\n inert.forEach((el) => (el.inert = true));\n history.scrollRestoration = \"manual\";\n body.style.cssText += `;position:fixed;top:${-y}px;left:0;right:0;overflow:hidden`;\n body.append(root);\n layout();\n if (!still) {\n panel.animate?.(\n sheet\n ? [{ transform: \"translateY(100%)\" }, { transform: \"none\" }]\n : [{ opacity: 0 }, { opacity: 1 }],\n { duration: sheet ? 280 : 160, easing: \"cubic-bezier(.2,.8,.2,1)\" },\n );\n }\n request = close;\n return new Promise((resolve) => (settle = resolve));\n}\n"],
5
4
  "mappings": "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",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/error.ts"],
4
- "sourcesContent": ["import { stableErrorCode } from \"../internal/customer-http\";\nimport { ZappieError } from \"./sdk\";\n\n/**\n * A checkout API failure with its HTTP status, API code and optional validation issues.\n * Statuses 409, 429 and 5xx are marked retryable.\n */\nexport class CheckoutError extends ZappieError {\n readonly issues?: unknown;\n\n constructor(\n status: number,\n readonly apiCode: string,\n message: string,\n param?: string,\n issues?: unknown,\n ) {\n super(stableErrorCode(status), message, {\n status,\n // 409 means the same idempotency key is still being processed; retrying with it is safe.\n retryable: status === 409 || status === 429 || status >= 500,\n ...(param !== undefined ? { param } : {}),\n });\n if (issues !== undefined) {\n this.issues = issues;\n }\n }\n}\n"],
5
4
  "mappings": ";AAAA,SAAS,uBAAuB;AAChC,SAAS,mBAAmB;AAMrB,IAAM,gBAAN,cAA4B,YAAY;AAAA,EAG7C,YACE,QACS,SACT,SACA,OACA,QACA;AACA,UAAM,gBAAgB,MAAM,GAAG,SAAS;AAAA,MACtC;AAAA;AAAA,MAEA,WAAW,WAAW,OAAO,WAAW,OAAO,UAAU;AAAA,MACzD,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,IACzC,CAAC;AAVQ;AAWT,QAAI,WAAW,QAAW;AACxB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AACF;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/index.ts"],
4
- "sourcesContent": ["export { createCheckout } from \"./client\";\nexport type { CheckoutClient } from \"./client\";\nexport { CheckoutError } from \"./error\";\nexport { isContactPhoneValid, payReadiness } from \"./readiness\";\nexport type { PayReadiness, PayReadinessQuoteState } from \"./readiness\";\nexport { checkoutFulfilment } from \"./sdk\";\nexport type * from \"./types\";\n"],
5
4
  "mappings": ";AAAA,SAAS,sBAAsB;AAE/B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB,oBAAoB;AAElD,SAAS,0BAA0B;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/react.ts"],
4
- "sourcesContent": ["\"use client\";\nimport { useCallback, useState } from \"react\";\nimport type { CheckoutClient } from \"./client\";\nimport {\n closeCheckout,\n embedCheckout,\n type CheckoutResult,\n type EmbedOptions,\n} from \"./embed\";\nimport type { CheckoutRequest } from \"./types\";\n\n/**\n * Open checkout for a cart and follow it. `open` creates the session, then embeds or redirects it as\n * `presentation` decides, and resolves with how it ended. Retain the idempotency key when retrying a cart.\n */\nexport function useCheckout(checkout: CheckoutClient) {\n const [status, setStatus] = useState<\n \"idle\" | \"opening\" | \"open\" | CheckoutResult[\"status\"]\n >(\"idle\");\n const [step, setStep] = useState<string>();\n const open = useCallback(\n async (body: CheckoutRequest, key: string, options: EmbedOptions = {}) => {\n setStatus(\"opening\");\n try {\n const session = await checkout.open(body, key);\n setStatus(\"open\");\n const result = await embedCheckout(checkout, session, {\n ...options,\n onStep: (next, paying) => {\n setStep(next);\n options.onStep?.(next, paying);\n },\n });\n setStatus(result.status);\n return result;\n } catch (failure) {\n setStatus(\"idle\");\n throw failure;\n }\n },\n [checkout],\n );\n return { open, close: closeCheckout, status, step };\n}\n"],
5
4
  "mappings": ";;;AACA,SAAS,aAAa,gBAAgB;AAEtC;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAOA,SAAS,YAAY,UAA0B;AACpD,QAAM,CAAC,QAAQ,SAAS,IAAI,SAE1B,MAAM;AACR,QAAM,CAAC,MAAM,OAAO,IAAI,SAAiB;AACzC,QAAM,OAAO;AAAA,IACX,OAAO,MAAuB,KAAa,UAAwB,CAAC,MAAM;AACxE,gBAAU,SAAS;AACnB,UAAI;AACF,cAAM,UAAU,MAAM,SAAS,KAAK,MAAM,GAAG;AAC7C,kBAAU,MAAM;AAChB,cAAM,SAAS,MAAM,cAAc,UAAU,SAAS;AAAA,UACpD,GAAG;AAAA,UACH,QAAQ,CAAC,MAAM,WAAW;AACxB,oBAAQ,IAAI;AACZ,oBAAQ,SAAS,MAAM,MAAM;AAAA,UAC/B;AAAA,QACF,CAAC;AACD,kBAAU,OAAO,MAAM;AACvB,eAAO;AAAA,MACT,SAAS,SAAS;AAChB,kBAAU,MAAM;AAChB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,IACA,CAAC,QAAQ;AAAA,EACX;AACA,SAAO,EAAE,MAAM,OAAO,eAAe,QAAQ,KAAK;AACpD;",
6
5
  "names": []
7
6
  }
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/checkout/readiness.ts"],
4
- "sourcesContent": ["import type { Quote } from \"./sdk\";\n\n/**\n * The next action your payment UI should present, from fixing an address to paying.\n */\nexport type PayReadiness =\n | \"address\"\n | \"quoting\"\n | \"retry\"\n | \"choose_area\"\n | \"fix_issues\"\n | \"sign_in\"\n | \"phone\"\n | \"pay\";\n\n/**\n * The quote loading state and, when ready, the quote used to decide payment readiness.\n */\nexport type PayReadinessQuoteState =\n | { status: \"idle\" | \"loading\" }\n | { status: \"error\" }\n | { status: \"ready\"; quote: Quote };\n\n/**\n * Check whether a phone is blank or contains 7 to 15 digits with an optional leading plus.\n * Whitespace within a nonblank phone is ignored. This does not verify that the number exists.\n *\n * @param phone - The contact phone entered by the shopper.\n * @returns Whether the phone passes this optional-field format check.\n */\nexport function isContactPhoneValid(phone: string): boolean {\n return (\n phone.trim() === \"\" || /^\\+?[0-9]{7,15}$/.test(phone.replace(/\\s+/g, \"\"))\n );\n}\n\n/**\n * Choose the next payment action from address validity, quote state and contact phone validity.\n * Address and quote issues take priority over sign-in and phone prompts.\n *\n * @returns The action you should display in your payment UI.\n */\nexport function payReadiness(\n state: PayReadinessQuoteState,\n contactPhoneValid: boolean,\n addressValid = true,\n): PayReadiness {\n if (!addressValid) {\n return \"address\";\n }\n switch (state.status) {\n case \"idle\":\n case \"loading\":\n return \"quoting\";\n case \"error\":\n return \"retry\";\n }\n if (\n state.quote.issues.some(\n (issue) => issue.code === \"delivery_region_required\",\n )\n ) {\n return \"choose_area\";\n }\n if (!state.quote.canCheckout || state.quote.checkout.reason === \"issues\") {\n return \"fix_issues\";\n }\n if (state.quote.checkout.reason === \"customer_required\") {\n return \"sign_in\";\n }\n if (!contactPhoneValid) {\n return \"phone\";\n }\n return \"pay\";\n}\n"],
5
4
  "mappings": ";AA8BO,SAAS,oBAAoB,OAAwB;AAC1D,SACE,MAAM,KAAK,MAAM,MAAM,mBAAmB,KAAK,MAAM,QAAQ,QAAQ,EAAE,CAAC;AAE5E;AAQO,SAAS,aACd,OACA,mBACA,eAAe,MACD;AACd,MAAI,CAAC,cAAc;AACjB,WAAO;AAAA,EACT;AACA,UAAQ,MAAM,QAAQ;AAAA,IACpB,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,EACX;AACA,MACE,MAAM,MAAM,OAAO;AAAA,IACjB,CAAC,UAAU,MAAM,SAAS;AAAA,EAC5B,GACA;AACA,WAAO;AAAA,EACT;AACA,MAAI,CAAC,MAAM,MAAM,eAAe,MAAM,MAAM,SAAS,WAAW,UAAU;AACxE,WAAO;AAAA,EACT;AACA,MAAI,MAAM,MAAM,SAAS,WAAW,qBAAqB;AACvD,WAAO;AAAA,EACT;AACA,MAAI,CAAC,mBAAmB;AACtB,WAAO;AAAA,EACT;AACA,SAAO;AACT;",
6
5
  "names": []
7
6
  }