@zappie/sdk 0.1.1 → 0.1.2

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 (188) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/cart/errors.js +13 -0
  3. package/dist/cart/errors.js.map +7 -0
  4. package/dist/cart/index.js +768 -0
  5. package/dist/cart/index.js.map +7 -0
  6. package/dist/cart/item.js +12 -1
  7. package/dist/cart/item.js.map +7 -1
  8. package/dist/cart/preview.js +32 -0
  9. package/dist/cart/preview.js.map +7 -0
  10. package/dist/cart/price.js +25 -0
  11. package/dist/cart/price.js.map +7 -0
  12. package/dist/cart/quote-client.js +76 -0
  13. package/dist/cart/quote-client.js.map +7 -0
  14. package/dist/cart/quote-response.js +178 -0
  15. package/dist/cart/quote-response.js.map +7 -0
  16. package/dist/cart/reconcile.js +108 -0
  17. package/dist/cart/reconcile.js.map +7 -0
  18. package/dist/cart/source-menu.js +21 -0
  19. package/dist/cart/source-menu.js.map +7 -0
  20. package/dist/cart/storage.js +174 -0
  21. package/dist/cart/storage.js.map +7 -0
  22. package/dist/cart/types.js +1 -0
  23. package/dist/cart/types.js.map +7 -0
  24. package/dist/cart/validate.js +265 -0
  25. package/dist/cart/validate.js.map +7 -0
  26. package/dist/cart/wire.js +42 -0
  27. package/dist/cart/wire.js.map +7 -0
  28. package/dist/cart/working-set.js +80 -0
  29. package/dist/cart/working-set.js.map +7 -0
  30. package/dist/checkout/client.js +102 -0
  31. package/dist/checkout/client.js.map +7 -0
  32. package/dist/checkout/error.js +21 -0
  33. package/dist/checkout/error.js.map +7 -0
  34. package/dist/checkout/index.js +13 -1
  35. package/dist/checkout/index.js.map +7 -1
  36. package/dist/checkout/readiness.js +36 -0
  37. package/dist/checkout/readiness.js.map +7 -0
  38. package/dist/checkout/sdk.js +9 -0
  39. package/dist/checkout/sdk.js.map +7 -0
  40. package/dist/checkout/session.js +58 -0
  41. package/dist/checkout/session.js.map +7 -0
  42. package/dist/checkout/types.js +1 -0
  43. package/dist/checkout/types.js.map +7 -0
  44. package/dist/client.js +253 -0
  45. package/dist/client.js.map +7 -0
  46. package/dist/config/index.js +13 -1
  47. package/dist/config/index.js.map +7 -0
  48. package/dist/config.js +28 -0
  49. package/dist/config.js.map +7 -0
  50. package/dist/customer/client.js +149 -0
  51. package/dist/customer/client.js.map +7 -0
  52. package/dist/customer/error.js +20 -0
  53. package/dist/customer/error.js.map +7 -0
  54. package/dist/customer/index.js +8 -3
  55. package/dist/customer/index.js.map +7 -1
  56. package/dist/customer/navigation.js +45 -0
  57. package/dist/customer/navigation.js.map +7 -0
  58. package/dist/customer/react.js +67 -2
  59. package/dist/customer/react.js.map +7 -1
  60. package/dist/customer/request.js +37 -0
  61. package/dist/customer/request.js.map +7 -0
  62. package/dist/customer/sdk.js +6 -0
  63. package/dist/customer/sdk.js.map +7 -0
  64. package/dist/customer/types.js +1 -0
  65. package/dist/customer/types.js.map +7 -0
  66. package/dist/customer/watch-order.js +80 -0
  67. package/dist/customer/watch-order.js.map +7 -0
  68. package/dist/debug.js +78 -1
  69. package/dist/debug.js.map +7 -1
  70. package/dist/errors.js +69 -0
  71. package/dist/errors.js.map +7 -0
  72. package/dist/index.js +29 -1
  73. package/dist/index.js.map +7 -1
  74. package/dist/internal/abort.js +29 -0
  75. package/dist/internal/abort.js.map +7 -0
  76. package/dist/internal/cache.js +142 -0
  77. package/dist/internal/cache.js.map +7 -0
  78. package/dist/internal/customer-http.js +74 -0
  79. package/dist/internal/customer-http.js.map +7 -0
  80. package/dist/internal/digest.js +15 -0
  81. package/dist/internal/digest.js.map +7 -0
  82. package/dist/internal/emitter.js +27 -0
  83. package/dist/internal/emitter.js.map +7 -0
  84. package/dist/internal/money-math.js +30 -0
  85. package/dist/internal/money-math.js.map +7 -0
  86. package/dist/internal.js +9 -1
  87. package/dist/internal.js.map +7 -1
  88. package/dist/models.js +1 -0
  89. package/dist/models.js.map +7 -0
  90. package/dist/money.js +58 -0
  91. package/dist/money.js.map +7 -0
  92. package/dist/persist/catalogue.js +206 -2
  93. package/dist/persist/catalogue.js.map +7 -1
  94. package/dist/places/client.js +97 -0
  95. package/dist/places/client.js.map +7 -0
  96. package/dist/places/error.js +20 -0
  97. package/dist/places/error.js.map +7 -0
  98. package/dist/places/index.js +8 -1
  99. package/dist/places/index.js.map +7 -1
  100. package/dist/places/request.js +40 -0
  101. package/dist/places/request.js.map +7 -0
  102. package/dist/places/sdk.js +10 -0
  103. package/dist/places/sdk.js.map +7 -0
  104. package/dist/places/search.js +80 -0
  105. package/dist/places/search.js.map +7 -0
  106. package/dist/places/types.js +1 -0
  107. package/dist/places/types.js.map +7 -0
  108. package/dist/react/cart.js +30 -0
  109. package/dist/react/cart.js.map +7 -0
  110. package/dist/react/hooks.js +91 -0
  111. package/dist/react/hooks.js.map +7 -0
  112. package/dist/react/index.js +18 -1
  113. package/dist/react/index.js.map +7 -1
  114. package/dist/react/provider.js +34 -0
  115. package/dist/react/provider.js.map +7 -0
  116. package/dist/server/index.js +32 -2
  117. package/dist/server/index.js.map +7 -1
  118. package/dist/server/storefront-url/build-v1.js +75 -0
  119. package/dist/server/storefront-url/build-v1.js.map +7 -0
  120. package/dist/server/storefront-url/build-v2.js +79 -0
  121. package/dist/server/storefront-url/build-v2.js.map +7 -0
  122. package/dist/server/storefront-url/build.js +19 -0
  123. package/dist/server/storefront-url/build.js.map +7 -0
  124. package/dist/server/storefront-url/contract.js +25 -0
  125. package/dist/server/storefront-url/contract.js.map +7 -0
  126. package/dist/server/storefront-url/index.js +16 -0
  127. package/dist/server/storefront-url/index.js.map +7 -0
  128. package/dist/server/storefront-url/installation.js +58 -0
  129. package/dist/server/storefront-url/installation.js.map +7 -0
  130. package/dist/server/storefront-url/params.js +72 -0
  131. package/dist/server/storefront-url/params.js.map +7 -0
  132. package/dist/server/storefront-url/parse-v1.js +135 -0
  133. package/dist/server/storefront-url/parse-v1.js.map +7 -0
  134. package/dist/server/storefront-url/parse-v2.js +139 -0
  135. package/dist/server/storefront-url/parse-v2.js.map +7 -0
  136. package/dist/server/storefront-url/parse.js +9 -0
  137. package/dist/server/storefront-url/parse.js.map +7 -0
  138. package/dist/server/storefront-url/redirect.js +30 -0
  139. package/dist/server/storefront-url/redirect.js.map +7 -0
  140. package/dist/server/storefront-url/sign-in.js +17 -0
  141. package/dist/server/storefront-url/sign-in.js.map +7 -0
  142. package/dist/server/storefront-url/types.js +55 -0
  143. package/dist/server/storefront-url/types.js.map +7 -0
  144. package/dist/server/storefront-url/url.js +61 -0
  145. package/dist/server/storefront-url/url.js.map +7 -0
  146. package/dist/server/webhook.js +96 -0
  147. package/dist/server/webhook.js.map +7 -0
  148. package/dist/site-config/helpers.js +59 -0
  149. package/dist/site-config/helpers.js.map +7 -0
  150. package/dist/site-config/sections.js +105 -0
  151. package/dist/site-config/sections.js.map +7 -0
  152. package/dist/site-config/types.js +31 -0
  153. package/dist/site-config/types.js.map +7 -0
  154. package/dist/site-config/validate.js +165 -0
  155. package/dist/site-config/validate.js.map +7 -0
  156. package/dist/template/index.js +46 -3
  157. package/dist/template/index.js.map +7 -1
  158. package/dist/template/react.js +81 -2
  159. package/dist/template/react.js.map +7 -1
  160. package/dist/testing/index.js +451 -2
  161. package/dist/testing/index.js.map +7 -1
  162. package/dist/transport/category-page.js +21 -2
  163. package/dist/transport/category-page.js.map +7 -1
  164. package/dist/transport/mappers.js +326 -0
  165. package/dist/transport/mappers.js.map +7 -0
  166. package/dist/transport/rest.js +313 -0
  167. package/dist/transport/rest.js.map +7 -0
  168. package/dist/transport/search.js +32 -2
  169. package/dist/transport/search.js.map +7 -1
  170. package/dist/transport/selected-menu.js +79 -2
  171. package/dist/transport/selected-menu.js.map +7 -1
  172. package/dist/transport/store.js +120 -2
  173. package/dist/transport/store.js.map +7 -1
  174. package/dist/transport/types.js +1 -0
  175. package/dist/transport/types.js.map +7 -0
  176. package/dist/url/index.js +16 -2
  177. package/dist/url/index.js.map +7 -1
  178. package/dist/visits/index.js +62 -1
  179. package/dist/visits/index.js.map +7 -1
  180. package/dist/visits/page-views.js +103 -0
  181. package/dist/visits/page-views.js.map +7 -0
  182. package/package.json +3 -3
  183. package/dist/cart/quote.js +0 -1
  184. package/dist/cart/quote.js.map +0 -1
  185. package/dist/chunk-I55A5QXJ.js +0 -2
  186. package/dist/chunk-I55A5QXJ.js.map +0 -1
  187. package/dist/chunk-LFBQICYU.js +0 -2
  188. package/dist/chunk-LFBQICYU.js.map +0 -1
@@ -0,0 +1,80 @@
1
+ // src/cart/working-set.ts
2
+ import { ZappieError } from "../errors.js";
3
+ function createWorkingSet(deps) {
4
+ const compose = (branchId, ids, metadata) => {
5
+ const source = metadata ?? deps.menu.peek(branchId);
6
+ const items = Object.fromEntries(
7
+ [...new Set(ids)].flatMap((id) => {
8
+ const item = deps.peekItem(id, branchId) ?? source?.items[id];
9
+ return item ? [[id, item]] : [];
10
+ })
11
+ );
12
+ return {
13
+ id: `branch:${branchId}`,
14
+ name: "Cart working set",
15
+ branchId,
16
+ version: "",
17
+ ...source,
18
+ kind: "working-set",
19
+ completeness: "partial",
20
+ items,
21
+ categories: (source?.categories ?? []).map((category) => ({
22
+ ...category,
23
+ itemIds: Object.values(items).filter(
24
+ (item) => item.placements ? item.placements.some(
25
+ (p) => p.categoryId === category.id && (source?.menus ?? [
26
+ { id: source?.id, categoryIds: [category.id] }
27
+ ]).some(
28
+ (m) => m.id === p.menuId && m.categoryIds.includes(category.id)
29
+ )
30
+ ) : category.itemIds.includes(item.id)
31
+ ).map((item) => item.id)
32
+ }))
33
+ };
34
+ };
35
+ const peek = (branchId, ids) => {
36
+ const value = deps.menu.peek(branchId);
37
+ return value && value.completeness !== "partial" ? value : compose(branchId, ids);
38
+ };
39
+ return {
40
+ peek,
41
+ async read(branchId, ids, fresh = false) {
42
+ const cached = peek(branchId, ids);
43
+ if (!ids.length || !fresh && cached.completeness !== "partial") {
44
+ return cached;
45
+ }
46
+ const response = fresh ? await deps.transport.getMenu({
47
+ ...deps.context(),
48
+ branchId,
49
+ metadataOnly: true
50
+ }) : void 0;
51
+ const metadata = response && "menu" in response ? response.menu : await deps.menu.get({ branch: branchId, metadataOnly: true });
52
+ if (metadata.branchId !== branchId) {
53
+ throw new ZappieError(
54
+ "server_error",
55
+ "Cart metadata belongs to another branch"
56
+ );
57
+ }
58
+ deps.menu.hydrate(metadata);
59
+ if (metadata.completeness !== "partial") {
60
+ return metadata;
61
+ }
62
+ await Promise.all(
63
+ [...new Set(ids)].map(async (id) => {
64
+ try {
65
+ await deps.readItem(id, branchId, fresh);
66
+ } catch (error) {
67
+ if (error.code !== "item_not_found") {
68
+ throw error;
69
+ }
70
+ }
71
+ })
72
+ );
73
+ return compose(branchId, ids, metadata);
74
+ }
75
+ };
76
+ }
77
+ export {
78
+ createWorkingSet
79
+ };
80
+ //# sourceMappingURL=working-set.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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
+ "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
+ "names": []
7
+ }
@@ -0,0 +1,102 @@
1
+ // src/checkout/client.ts
2
+ import { apiError, requestWithRetry, wait } from "../internal/customer-http.js";
3
+ import { CheckoutError } from "./error.js";
4
+ import { ZappieError } from "./sdk.js";
5
+ import { mapCheckoutSession } from "./session.js";
6
+ var DEFAULT_CUSTOMER_BASE = "/_zappie/api";
7
+ async function error(response) {
8
+ const value = await apiError(
9
+ response,
10
+ `The checkout service answered ${response.status}`
11
+ );
12
+ return new CheckoutError(
13
+ response.status,
14
+ value.apiCode,
15
+ value.message,
16
+ value.param,
17
+ value.issues
18
+ );
19
+ }
20
+ function createCheckout(options = {}) {
21
+ const base = (options.customerBase ?? DEFAULT_CUSTOMER_BASE).replace(
22
+ /\/+$/,
23
+ ""
24
+ );
25
+ const fetcher = options.fetch ?? globalThis.fetch;
26
+ const request = async (path, init) => {
27
+ const response = await requestWithRetry(
28
+ fetcher,
29
+ base + path,
30
+ init,
31
+ "Could not reach checkout"
32
+ );
33
+ if (!response.ok) {
34
+ throw await error(response);
35
+ }
36
+ return mapCheckoutSession(await response.json());
37
+ };
38
+ const read = (id, signal) => request(`/checkout/sessions/${encodeURIComponent(id)}`, {
39
+ method: "GET",
40
+ ...signal ? { signal } : {}
41
+ });
42
+ return {
43
+ /** The caller retains this key and reuses it when retrying the same cart. */
44
+ async open(body, idempotencyKey) {
45
+ const session = await request("/checkout/sessions", {
46
+ method: "POST",
47
+ headers: {
48
+ "Content-Type": "application/json",
49
+ "Idempotency-Key": idempotencyKey
50
+ },
51
+ body: JSON.stringify(body)
52
+ });
53
+ if (!session.url) {
54
+ throw new ZappieError(
55
+ "server_error",
56
+ "Checkout session has no payment URL"
57
+ );
58
+ }
59
+ globalThis.__zappieEmit?.("checkout:open", session);
60
+ return { ...session, url: session.url };
61
+ },
62
+ session(id) {
63
+ return read(id);
64
+ },
65
+ async awaitCompletion(id, options2 = {}) {
66
+ const interval = options2.intervalMs ?? 3e3;
67
+ if (!Number.isFinite(interval) || interval < 0) {
68
+ throw new ZappieError(
69
+ "invalid_request",
70
+ "intervalMs cannot be negative"
71
+ );
72
+ }
73
+ for (; ; ) {
74
+ options2.signal?.throwIfAborted();
75
+ try {
76
+ const session = await read(id, options2.signal);
77
+ if (session.status === "completed" && session.order_id) {
78
+ globalThis.__zappieEmit?.("checkout:completed", session);
79
+ return {
80
+ ...session,
81
+ status: "completed",
82
+ order_id: session.order_id
83
+ };
84
+ }
85
+ if (session.status === "expired" || session.status === "cancelled") {
86
+ return { ...session, status: session.status };
87
+ }
88
+ } catch (failure) {
89
+ options2.signal?.throwIfAborted();
90
+ if (failure instanceof ZappieError && failure.status !== void 0 && failure.status >= 400 && failure.status < 500) {
91
+ throw failure;
92
+ }
93
+ }
94
+ await wait(interval, options2.signal);
95
+ }
96
+ }
97
+ };
98
+ }
99
+ export {
100
+ createCheckout
101
+ };
102
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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/**\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(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
+ "mappings": ";AAAA,SAAS,UAAU,kBAAkB,YAAY;AACjD,SAAS,qBAAqB;AAC9B,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AAUnC,IAAM,wBAAwB;AAE9B,eAAe,MAAM,UAA4C;AAC/D,QAAM,QAAQ,MAAM;AAAA,IAClB;AAAA,IACA,iCAAiC,SAAS,MAAM;AAAA,EAClD;AACA,SAAO,IAAI;AAAA,IACT,SAAS;AAAA,IACT,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR;AACF;AAQO,SAAS,eAAe,UAAiC,CAAC,GAAG;AAClE,QAAM,QAAQ,QAAQ,gBAAgB,uBAAuB;AAAA,IAC3D;AAAA,IACA;AAAA,EACF;AACA,QAAM,UAAU,QAAQ,SAAS,WAAW;AAC5C,QAAM,UAAU,OACd,MACA,SAC6B;AAC7B,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,MACP;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,MAAM,MAAM,QAAQ;AAAA,IAC5B;AACA,WAAO,mBAAmB,MAAM,SAAS,KAAK,CAAC;AAAA,EACjD;AACA,QAAM,OAAO,CAAC,IAAY,WACxB,QAAQ,sBAAsB,mBAAmB,EAAE,CAAC,IAAI;AAAA,IACtD,QAAQ;AAAA,IACR,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AAAA,EAC7B,CAAC;AACH,SAAO;AAAA;AAAA,IAEL,MAAM,KACJ,MACA,gBAC8B;AAC9B,YAAM,UAAU,MAAM,QAAQ,sBAAsB;AAAA,QAClD,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,mBAAmB;AAAA,QACrB;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AACD,UAAI,CAAC,QAAQ,KAAK;AAChB,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,iBAAW,eAAe,iBAAiB,OAAO;AAClD,aAAO,EAAE,GAAG,SAAS,KAAK,QAAQ,IAAI;AAAA,IACxC;AAAA,IACA,QAAQ,IAAsC;AAC5C,aAAO,KAAK,EAAE;AAAA,IAChB;AAAA,IACA,MAAM,gBACJ,IACAA,WAAkC,CAAC,GACN;AAC7B,YAAM,WAAWA,SAAQ,cAAc;AACvC,UAAI,CAAC,OAAO,SAAS,QAAQ,KAAK,WAAW,GAAG;AAC9C,cAAM,IAAI;AAAA,UACR;AAAA,UACA;AAAA,QACF;AAAA,MACF;AACA,iBAAS;AACP,QAAAA,SAAQ,QAAQ,eAAe;AAC/B,YAAI;AACF,gBAAM,UAAU,MAAM,KAAK,IAAIA,SAAQ,MAAM;AAC7C,cAAI,QAAQ,WAAW,eAAe,QAAQ,UAAU;AACtD,uBAAW,eAAe,sBAAsB,OAAO;AACvD,mBAAO;AAAA,cACL,GAAG;AAAA,cACH,QAAQ;AAAA,cACR,UAAU,QAAQ;AAAA,YACpB;AAAA,UACF;AACA,cAAI,QAAQ,WAAW,aAAa,QAAQ,WAAW,aAAa;AAClE,mBAAO,EAAE,GAAG,SAAS,QAAQ,QAAQ,OAAO;AAAA,UAC9C;AAAA,QACF,SAAS,SAAS;AAChB,UAAAA,SAAQ,QAAQ,eAAe;AAC/B,cACE,mBAAmB,eACnB,QAAQ,WAAW,UACnB,QAAQ,UAAU,OAClB,QAAQ,SAAS,KACjB;AACA,kBAAM;AAAA,UACR;AAAA,QACF;AACA,cAAM,KAAK,UAAUA,SAAQ,MAAM;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AACF;",
6
+ "names": ["options"]
7
+ }
@@ -0,0 +1,21 @@
1
+ // src/checkout/error.ts
2
+ import { stableErrorCode } from "../internal/customer-http.js";
3
+ import { ZappieError } from "./sdk.js";
4
+ var CheckoutError = class extends ZappieError {
5
+ constructor(status, apiCode, message, param, issues) {
6
+ super(stableErrorCode(status), message, {
7
+ status,
8
+ // 409 means the same idempotency key is still being processed; retrying with it is safe.
9
+ retryable: status === 409 || status === 429 || status >= 500,
10
+ ...param !== void 0 ? { param } : {}
11
+ });
12
+ this.apiCode = apiCode;
13
+ if (issues !== void 0) {
14
+ this.issues = issues;
15
+ }
16
+ }
17
+ };
18
+ export {
19
+ CheckoutError
20
+ };
21
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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
+ "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
+ "names": []
7
+ }
@@ -1 +1,13 @@
1
- import {ZappieError,money}from'@zappie/sdk';export{wireFulfilment as checkoutFulfilment}from'@zappie/sdk/internal';function l(e){return e===400||e===422?"invalid_request":e===401?"unauthorized":e===404?"not_found":e===429?"rate_limited":"server_error"}async function h(e,r){let t=await e.json().catch(()=>({})),s=t&&typeof t=="object"?t:{},o="error"in s&&s.error&&typeof s.error=="object"?s.error:{};return {apiCode:"code"in o&&typeof o.code=="string"?o.code:"server_error",message:"message"in o&&typeof o.message=="string"?o.message:r,..."param"in o&&typeof o.param=="string"?{param:o.param}:{},..."issues"in o?{issues:o.issues}:{}}}function m(e,r){return r?.throwIfAborted(),new Promise((t,s)=>{let i=setTimeout(()=>{r?.removeEventListener("abort",n),t();},e),n=()=>{clearTimeout(i),r?.removeEventListener("abort",n),s(r?.reason??new DOMException("Aborted","AbortError"));};r?.addEventListener("abort",n,{once:true});})}async function y(e,r,t,s){for(let o=0;o<2;o++)try{return await e(r,{...t,credentials:"same-origin",headers:{Accept:"application/json",...t.headers}})}catch(i){if(t.signal?.aborted)throw t.signal.reason??i;if(o===1)throw new ZappieError("network_error",s,{cause:i,retryable:true});await m(400,t.signal??void 0);}throw new ZappieError("network_error",s,{retryable:true})}var p=class extends ZappieError{constructor(t,s,o,i,n){super(l(t),o,{status:t,retryable:t===409||t===429||t>=500,...i!==void 0?{param:i}:{}});this.apiCode=s;n!==void 0&&(this.issues=n);}};function k(e){if(!e||typeof e!="object"||Array.isArray(e))throw new ZappieError("server_error","Invalid checkout session response");return e}function d(e){if(typeof e!="string")throw new ZappieError("server_error","Invalid checkout session response");return e}function C(e){try{return money(0,d(e)).currency}catch{throw new ZappieError("server_error","Invalid checkout session response")}}function g(e){let r=k(e),t=k(r.amount),s=d(r.status);if(!["open","completed","expired","cancelled"].includes(s))throw new ZappieError("server_error","Invalid checkout session response");let o=d(r.expires_at);if(!Number.isFinite(Date.parse(o)))throw new ZappieError("server_error","Invalid checkout session response");if(!Number.isSafeInteger(t.amount_minor))throw new ZappieError("server_error","Invalid checkout session response");if(r.order_id!==null&&typeof r.order_id!="string")throw new ZappieError("server_error","Invalid checkout session response");return {id:d(r.id),status:s,...typeof r.url=="string"?{url:r.url}:{},amount:{amount_minor:t.amount_minor,currency:C(t.currency)},order_id:r.order_id,return_url:d(r.return_url),...typeof r.cancel_url=="string"?{cancel_url:r.cancel_url}:{},expires_at:o}}var b="/_zappie/api";async function x(e){let r=await h(e,`The checkout service answered ${e.status}`);return new p(e.status,r.apiCode,r.message,r.param,r.issues)}function v(e={}){let r=(e.customerBase??b).replace(/\/+$/,""),t=e.fetch??globalThis.fetch,s=async(i,n)=>{let c=await y(t,r+i,n,"Could not reach checkout");if(!c.ok)throw await x(c);return g(await c.json())},o=(i,n)=>s(`/checkout/sessions/${encodeURIComponent(i)}`,{method:"GET",...n?{signal:n}:{}});return {async open(i,n){let c=await s("/checkout/sessions",{method:"POST",headers:{"Content-Type":"application/json","Idempotency-Key":n},body:JSON.stringify(i)});if(!c.url)throw new ZappieError("server_error","Checkout session has no payment URL");return globalThis.__zappieEmit?.("checkout:open",c),{...c,url:c.url}},session(i){return o(i)},async awaitCompletion(i,n={}){let c=n.intervalMs??3e3;if(!Number.isFinite(c)||c<0)throw new ZappieError("invalid_request","intervalMs cannot be negative");for(;;){n.signal?.throwIfAborted();try{let a=await o(i,n.signal);if(a.status==="completed"&&a.order_id)return globalThis.__zappieEmit?.("checkout:completed",a),{...a,status:"completed",order_id:a.order_id};if(a.status==="expired"||a.status==="cancelled")return {...a,status:a.status}}catch(a){if(n.signal?.throwIfAborted(),a instanceof ZappieError&&a.status!==void 0&&a.status>=400&&a.status<500)throw a}await m(c,n.signal);}}}}function E(e){return e.trim()===""||/^\+?[0-9]{7,15}$/.test(e.replace(/\s+/g,""))}function R(e,r,t=true){if(!t)return "address";switch(e.status){case "idle":case "loading":return "quoting";case "error":return "retry"}return e.quote.issues.some(s=>s.code==="delivery_region_required")?"choose_area":!e.quote.canCheckout||e.quote.checkout.reason==="issues"?"fix_issues":e.quote.checkout.reason==="customer_required"?"sign_in":r?"pay":"phone"}export{p as CheckoutError,v as createCheckout,E as isContactPhoneValid,R as payReadiness};//# sourceMappingURL=index.js.map
1
+ // src/checkout/index.ts
2
+ import { createCheckout } from "./client.js";
3
+ import { CheckoutError } from "./error.js";
4
+ import { isContactPhoneValid, payReadiness } from "./readiness.js";
5
+ import { checkoutFulfilment } from "./sdk.js";
6
+ export {
7
+ CheckoutError,
8
+ checkoutFulfilment,
9
+ createCheckout,
10
+ isContactPhoneValid,
11
+ payReadiness
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../../src/internal/customer-http.ts","../../src/checkout/error.ts","../../src/checkout/session.ts","../../src/checkout/client.ts","../../src/checkout/readiness.ts"],"names":["stableErrorCode","status","apiError","response","fallback","body","envelope","value","wait","ms","signal","resolve","reject","timer","aborted","requestWithRetry","fetcher","input","init","message","attempt","cause","ZappieError","CheckoutError","apiCode","param","issues","object","string","currency","money","mapCheckoutSession","session","amount","expiresAt","DEFAULT_CUSTOMER_BASE","error","createCheckout","options","base","request","path","read","id","idempotencyKey","interval","failure","isContactPhoneValid","phone","payReadiness","state","contactPhoneValid","addressValid","issue"],"mappings":"mHAWO,SAASA,EAAgBC,CAAAA,CAAgB,CAC9C,OAAIA,CAAAA,GAAW,GAAA,EAAOA,CAAAA,GAAW,IACxB,iBAAA,CAELA,CAAAA,GAAW,GAAA,CACN,cAAA,CAELA,CAAAA,GAAW,GAAA,CACN,YAELA,CAAAA,GAAW,GAAA,CACN,cAAA,CAEF,cACT,CAEA,eAAsBC,EACpBC,CAAAA,CACAC,CAAAA,CAC0B,CAC1B,IAAMC,CAAAA,CAAO,MAAMF,CAAAA,CAAS,IAAA,EAAK,CAAE,KAAA,CAAM,KAAO,GAAG,CAAA,CAC7CG,CAAAA,CAAWD,CAAAA,EAAQ,OAAOA,CAAAA,EAAS,QAAA,CAAWA,EAAO,EAAC,CACtDE,CAAAA,CACJ,OAAA,GAAWD,CAAAA,EAAYA,CAAAA,CAAS,OAAS,OAAOA,CAAAA,CAAS,OAAU,QAAA,CAC/DA,CAAAA,CAAS,MACT,EAAC,CACP,OAAO,CACL,OAAA,CACE,MAAA,GAAUC,GAAS,OAAOA,CAAAA,CAAM,IAAA,EAAS,QAAA,CACrCA,CAAAA,CAAM,IAAA,CACN,eACN,OAAA,CACE,SAAA,GAAaA,CAAAA,EAAS,OAAOA,CAAAA,CAAM,OAAA,EAAY,SAC3CA,CAAAA,CAAM,OAAA,CACNH,EACN,GAAI,OAAA,GAAWG,GAAS,OAAOA,CAAAA,CAAM,KAAA,EAAU,QAAA,CAC3C,CAAE,KAAA,CAAOA,EAAM,KAAM,CAAA,CACrB,EAAC,CACL,GAAI,QAAA,GAAYA,EAAQ,CAAE,MAAA,CAAQA,CAAAA,CAAM,MAAO,CAAA,CAAI,EACrD,CACF,CAEO,SAASC,CAAAA,CAAKC,CAAAA,CAAYC,EAAqC,CACpE,OAAAA,CAAAA,EAAQ,cAAA,EAAe,CAChB,IAAI,QAAQ,CAACC,CAAAA,CAASC,CAAAA,GAAW,CAKtC,IAAMC,CAAAA,CAAQ,WAJD,IAAM,CACjBH,CAAAA,EAAQ,mBAAA,CAAoB,OAAA,CAASI,CAAO,EAC5CH,CAAAA,GACF,EAC+BF,CAAE,CAAA,CAC3BK,EAAU,IAAM,CACpB,YAAA,CAAaD,CAAK,CAAA,CAClBH,CAAAA,EAAQ,oBAAoB,OAAA,CAASI,CAAO,CAAA,CAC5CF,CAAAA,CAAOF,CAAAA,EAAQ,MAAA,EAAU,IAAI,YAAA,CAAa,SAAA,CAAW,YAAY,CAAC,EACpE,CAAA,CACAA,GAAQ,gBAAA,CAAiB,OAAA,CAASI,EAAS,CAAE,IAAA,CAAM,IAAK,CAAC,EAC3D,CAAC,CACH,CAEA,eAAsBC,EACpBC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACAC,CAAAA,CACmB,CACnB,IAAA,IAASC,EAAU,CAAA,CAAGA,CAAAA,CAAU,CAAA,CAAGA,CAAAA,EAAAA,CACjC,GAAI,CACF,OAAO,MAAMJ,CAAAA,CAAQC,EAAO,CAC1B,GAAGC,EACH,WAAA,CAAa,aAAA,CACb,OAAA,CAAS,CAAE,MAAA,CAAQ,kBAAA,CAAoB,GAAGA,CAAAA,CAAK,OAAQ,CACzD,CAAC,CACH,CAAA,MAASG,EAAO,CACd,GAAIH,CAAAA,CAAK,MAAA,EAAQ,OAAA,CACf,MAAMA,EAAK,MAAA,CAAO,MAAA,EAAUG,EAE9B,GAAID,CAAAA,GAAY,EACd,MAAM,IAAIE,WAAAA,CAAY,eAAA,CAAiBH,CAAAA,CAAS,CAC9C,MAAAE,CAAAA,CACA,SAAA,CAAW,IACb,CAAC,CAAA,CAEH,MAAMb,EAAK,GAAA,CAAKU,CAAAA,CAAK,MAAA,EAAU,MAAS,EAC1C,CAEF,MAAM,IAAII,WAAAA,CAAY,gBAAiBH,CAAAA,CAAS,CAAE,UAAW,IAAK,CAAC,CACrE,CC1FO,IAAMI,CAAAA,CAAN,cAA4BD,WAAY,CAG7C,WAAA,CACErB,EACSuB,CAAAA,CACTL,CAAAA,CACAM,EACAC,CAAAA,CACA,CACA,MAAM1B,CAAAA,CAAgBC,CAAM,CAAA,CAAGkB,CAAAA,CAAS,CACtC,MAAA,CAAAlB,EAEA,SAAA,CAAWA,CAAAA,GAAW,GAAA,EAAOA,CAAAA,GAAW,GAAA,EAAOA,CAAAA,EAAU,IACzD,GAAIwB,CAAAA,GAAU,MAAA,CAAY,CAAE,KAAA,CAAAA,CAAM,EAAI,EACxC,CAAC,CAAA,CAVQ,IAAA,CAAA,OAAA,CAAAD,EAWLE,CAAAA,GAAW,MAAA,GACb,IAAA,CAAK,MAAA,CAASA,CAAAA,EAElB,CACF,ECxBA,SAASC,CAAAA,CAAOpB,CAAAA,CAAyC,CACvD,GAAI,CAACA,GAAS,OAAOA,CAAAA,EAAU,QAAA,EAAY,KAAA,CAAM,OAAA,CAAQA,CAAK,EAC5D,MAAM,IAAIe,YAAY,cAAA,CAAgB,mCAAmC,EAE3E,OAAOf,CACT,CAEA,SAASqB,CAAAA,CAAOrB,CAAAA,CAAwB,CACtC,GAAI,OAAOA,CAAAA,EAAU,QAAA,CACnB,MAAM,IAAIe,YAAY,cAAA,CAAgB,mCAAmC,CAAA,CAE3E,OAAOf,CACT,CAEA,SAASsB,CAAAA,CAAStB,CAAAA,CAA0B,CAC1C,GAAI,CACF,OAAOuB,KAAAA,CAAM,CAAA,CAAGF,CAAAA,CAAOrB,CAAK,CAAC,CAAA,CAAE,QACjC,CAAA,KAAQ,CACN,MAAM,IAAIe,WAAAA,CAAY,cAAA,CAAgB,mCAAmC,CAC3E,CACF,CAEO,SAASS,CAAAA,CAAmBxB,CAAAA,CAAiC,CAClE,IAAMyB,CAAAA,CAAUL,EAAOpB,CAAK,CAAA,CACtB0B,EAASN,CAAAA,CAAOK,CAAAA,CAAQ,MAAM,CAAA,CAC9B/B,CAAAA,CAAS2B,CAAAA,CAAOI,EAAQ,MAAM,CAAA,CACpC,GACE,CAAE,CAAC,MAAA,CAAQ,YAAa,SAAA,CAAW,WAAW,CAAA,CAAe,QAAA,CAC3D/B,CACF,CAAA,CAEA,MAAM,IAAIqB,WAAAA,CAAY,cAAA,CAAgB,mCAAmC,CAAA,CAE3E,IAAMY,EAAYN,CAAAA,CAAOI,CAAAA,CAAQ,UAAU,CAAA,CAC3C,GAAI,CAAC,OAAO,QAAA,CAAS,IAAA,CAAK,KAAA,CAAME,CAAS,CAAC,CAAA,CACxC,MAAM,IAAIZ,WAAAA,CAAY,cAAA,CAAgB,mCAAmC,CAAA,CAE3E,GAAI,CAAC,MAAA,CAAO,aAAA,CAAcW,EAAO,YAAY,CAAA,CAC3C,MAAM,IAAIX,WAAAA,CAAY,cAAA,CAAgB,mCAAmC,CAAA,CAE3E,GAAIU,EAAQ,QAAA,GAAa,IAAA,EAAQ,OAAOA,CAAAA,CAAQ,QAAA,EAAa,QAAA,CAC3D,MAAM,IAAIV,WAAAA,CAAY,cAAA,CAAgB,mCAAmC,CAAA,CAE3E,OAAO,CACL,EAAA,CAAIM,CAAAA,CAAOI,EAAQ,EAAE,CAAA,CACrB,OAAQ/B,CAAAA,CACR,GAAI,OAAO+B,CAAAA,CAAQ,GAAA,EAAQ,QAAA,CAAW,CAAE,GAAA,CAAKA,CAAAA,CAAQ,GAAI,CAAA,CAAI,EAAC,CAC9D,OAAQ,CACN,YAAA,CAAcC,CAAAA,CAAO,YAAA,CACrB,QAAA,CAAUJ,CAAAA,CAASI,EAAO,QAAQ,CACpC,EACA,QAAA,CAAUD,CAAAA,CAAQ,SAClB,UAAA,CAAYJ,CAAAA,CAAOI,CAAAA,CAAQ,UAAU,CAAA,CACrC,GAAI,OAAOA,CAAAA,CAAQ,UAAA,EAAe,QAAA,CAC9B,CAAE,UAAA,CAAYA,CAAAA,CAAQ,UAAW,CAAA,CACjC,EAAC,CACL,UAAA,CAAYE,CACd,CACF,CChDA,IAAMC,CAAAA,CAAwB,eAE9B,eAAeC,CAAAA,CAAMjC,EAA4C,CAC/D,IAAMI,CAAAA,CAAQ,MAAML,CAAAA,CAClBC,CAAAA,CACA,iCAAiCA,CAAAA,CAAS,MAAM,CAAA,CAClD,CAAA,CACA,OAAO,IAAIoB,EACTpB,CAAAA,CAAS,MAAA,CACTI,CAAAA,CAAM,OAAA,CACNA,CAAAA,CAAM,OAAA,CACNA,EAAM,KAAA,CACNA,CAAAA,CAAM,MACR,CACF,CAQO,SAAS8B,CAAAA,CAAeC,CAAAA,CAAiC,EAAC,CAAG,CAClE,IAAMC,GAAQD,CAAAA,CAAQ,YAAA,EAAgBH,CAAAA,EAAuB,OAAA,CAC3D,MAAA,CACA,EACF,EACMnB,CAAAA,CAAUsB,CAAAA,CAAQ,KAAA,EAAS,UAAA,CAAW,KAAA,CACtCE,CAAAA,CAAU,MACdC,CAAAA,CACAvB,CAAAA,GAC6B,CAC7B,IAAMf,CAAAA,CAAW,MAAMY,CAAAA,CACrBC,CAAAA,CACAuB,CAAAA,CAAOE,CAAAA,CACPvB,CAAAA,CACA,0BACF,EACA,GAAI,CAACf,CAAAA,CAAS,EAAA,CACZ,MAAM,MAAMiC,EAAMjC,CAAQ,CAAA,CAE5B,OAAO4B,CAAAA,CAAmB,MAAM5B,CAAAA,CAAS,MAAM,CACjD,EACMuC,CAAAA,CAAO,CAACC,EAAYjC,CAAAA,GACxB8B,CAAAA,CAAQ,CAAA,mBAAA,EAAsB,kBAAA,CAAmBG,CAAE,CAAC,GAAI,CACtD,MAAA,CAAQ,KAAA,CACR,GAAIjC,CAAAA,CAAS,CAAE,OAAAA,CAAO,CAAA,CAAI,EAC5B,CAAC,CAAA,CACH,OAAO,CAEL,MAAM,IAAA,CACJL,CAAAA,CACAuC,CAAAA,CAC8B,CAC9B,IAAMZ,CAAAA,CAAU,MAAMQ,CAAAA,CAAQ,oBAAA,CAAsB,CAClD,MAAA,CAAQ,OACR,OAAA,CAAS,CACP,cAAA,CAAgB,kBAAA,CAChB,iBAAA,CAAmBI,CACrB,EACA,IAAA,CAAM,IAAA,CAAK,SAAA,CAAUvC,CAAI,CAC3B,CAAC,EACD,GAAI,CAAC2B,EAAQ,GAAA,CACX,MAAM,IAAIV,WAAAA,CACR,cAAA,CACA,qCACF,CAAA,CAEF,OAAA,UAAA,CAAW,YAAA,GAAe,gBAAiBU,CAAO,CAAA,CAC3C,CAAE,GAAGA,CAAAA,CAAS,GAAA,CAAKA,EAAQ,GAAI,CACxC,CAAA,CACA,OAAA,CAAQW,CAAAA,CAAsC,CAC5C,OAAOD,CAAAA,CAAKC,CAAE,CAChB,CAAA,CACA,MAAM,gBACJA,CAAAA,CACAL,CAAAA,CAAkC,EAAC,CACN,CAC7B,IAAMO,EAAWP,CAAAA,CAAQ,UAAA,EAAc,GAAA,CACvC,GAAI,CAAC,MAAA,CAAO,SAASO,CAAQ,CAAA,EAAKA,CAAAA,CAAW,CAAA,CAC3C,MAAM,IAAIvB,YACR,iBAAA,CACA,+BACF,EAEF,OAAS,CACPgB,EAAQ,MAAA,EAAQ,cAAA,EAAe,CAC/B,GAAI,CACF,IAAMN,EAAU,MAAMU,CAAAA,CAAKC,CAAAA,CAAIL,CAAAA,CAAQ,MAAM,CAAA,CAC7C,GAAIN,CAAAA,CAAQ,MAAA,GAAW,WAAA,EAAeA,CAAAA,CAAQ,QAAA,CAC5C,OAAA,UAAA,CAAW,eAAe,oBAAA,CAAsBA,CAAO,EAChD,CACL,GAAGA,EACH,MAAA,CAAQ,WAAA,CACR,QAAA,CAAUA,CAAAA,CAAQ,QACpB,CAAA,CAEF,GAAIA,CAAAA,CAAQ,MAAA,GAAW,SAAA,EAAaA,CAAAA,CAAQ,MAAA,GAAW,WAAA,CACrD,OAAO,CAAE,GAAGA,CAAAA,CAAS,MAAA,CAAQA,CAAAA,CAAQ,MAAO,CAEhD,CAAA,MAASc,CAAAA,CAAS,CAEhB,GADAR,CAAAA,CAAQ,QAAQ,cAAA,EAAe,CAE7BQ,CAAAA,YAAmBxB,WAAAA,EACnBwB,CAAAA,CAAQ,MAAA,GAAW,QACnBA,CAAAA,CAAQ,MAAA,EAAU,GAAA,EAClBA,CAAAA,CAAQ,MAAA,CAAS,GAAA,CAEjB,MAAMA,CAEV,CACA,MAAMtC,CAAAA,CAAKqC,CAAAA,CAAUP,CAAAA,CAAQ,MAAM,EACrC,CACF,CACF,CACF,CClGO,SAASS,CAAAA,CAAoBC,CAAAA,CAAwB,CAC1D,OACEA,CAAAA,CAAM,IAAA,KAAW,EAAA,EAAM,kBAAA,CAAmB,IAAA,CAAKA,CAAAA,CAAM,OAAA,CAAQ,MAAA,CAAQ,EAAE,CAAC,CAE5E,CAQO,SAASC,CAAAA,CACdC,CAAAA,CACAC,EACAC,CAAAA,CAAe,IAAA,CACD,CACd,GAAI,CAACA,EACH,OAAO,SAAA,CAET,OAAQF,CAAAA,CAAM,MAAA,EACZ,KAAK,MAAA,CACL,KAAK,SAAA,CACH,OAAO,SAAA,CACT,KAAK,QACH,OAAO,OACX,CACA,OACEA,CAAAA,CAAM,KAAA,CAAM,OAAO,IAAA,CAChBG,CAAAA,EAAUA,CAAAA,CAAM,IAAA,GAAS,0BAC5B,CAAA,CAEO,cAEL,CAACH,CAAAA,CAAM,KAAA,CAAM,WAAA,EAAeA,CAAAA,CAAM,KAAA,CAAM,SAAS,MAAA,GAAW,QAAA,CACvD,YAAA,CAELA,CAAAA,CAAM,KAAA,CAAM,QAAA,CAAS,SAAW,mBAAA,CAC3B,SAAA,CAEJC,CAAAA,CAGE,KAAA,CAFE,OAGX","file":"index.js","sourcesContent":["// Isolated customer-facing bundles import the installed core so error identity is shared.\n// eslint-disable-next-line no-restricted-imports\nimport { ZappieError } from \"@zappie/sdk\";\n\nexport type ApiErrorDetails = {\n apiCode: string;\n message: string;\n param?: string;\n issues?: unknown;\n};\n\nexport function stableErrorCode(status: number) {\n if (status === 400 || status === 422) {\n return \"invalid_request\" as const;\n }\n if (status === 401) {\n return \"unauthorized\" as const;\n }\n if (status === 404) {\n return \"not_found\" as const;\n }\n if (status === 429) {\n return \"rate_limited\" as const;\n }\n return \"server_error\" as const;\n}\n\nexport async function apiError(\n response: Response,\n fallback: string,\n): Promise<ApiErrorDetails> {\n const body = await response.json().catch(() => ({}));\n const envelope = body && typeof body === \"object\" ? body : {};\n const value =\n \"error\" in envelope && envelope.error && typeof envelope.error === \"object\"\n ? envelope.error\n : {};\n return {\n apiCode:\n \"code\" in value && typeof value.code === \"string\"\n ? value.code\n : \"server_error\",\n message:\n \"message\" in value && typeof value.message === \"string\"\n ? value.message\n : fallback,\n ...(\"param\" in value && typeof value.param === \"string\"\n ? { param: value.param }\n : {}),\n ...(\"issues\" in value ? { issues: value.issues } : {}),\n };\n}\n\nexport function wait(ms: number, signal?: AbortSignal): Promise<void> {\n signal?.throwIfAborted();\n return new Promise((resolve, reject) => {\n const done = () => {\n signal?.removeEventListener(\"abort\", aborted);\n resolve();\n };\n const timer = setTimeout(done, ms);\n const aborted = () => {\n clearTimeout(timer);\n signal?.removeEventListener(\"abort\", aborted);\n reject(signal?.reason ?? new DOMException(\"Aborted\", \"AbortError\"));\n };\n signal?.addEventListener(\"abort\", aborted, { once: true });\n });\n}\n\nexport async function requestWithRetry(\n fetcher: typeof fetch,\n input: string,\n init: RequestInit,\n message: string,\n): Promise<Response> {\n for (let attempt = 0; attempt < 2; attempt++) {\n try {\n return await fetcher(input, {\n ...init,\n credentials: \"same-origin\",\n headers: { Accept: \"application/json\", ...init.headers },\n });\n } catch (cause) {\n if (init.signal?.aborted) {\n throw init.signal.reason ?? cause;\n }\n if (attempt === 1) {\n throw new ZappieError(\"network_error\", message, {\n cause,\n retryable: true,\n });\n }\n await wait(400, init.signal ?? undefined);\n }\n }\n throw new ZappieError(\"network_error\", message, { retryable: true });\n}\n","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","import { type Currency, money, ZappieError } from \"./sdk\";\nimport type { CheckoutSession } from \"./types\";\n\nfunction object(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return value as Record<string, unknown>;\n}\n\nfunction string(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return value;\n}\n\nfunction currency(value: unknown): Currency {\n try {\n return money(0, string(value)).currency;\n } catch {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n}\n\nexport function mapCheckoutSession(value: unknown): CheckoutSession {\n const session = object(value);\n const amount = object(session.amount);\n const status = string(session.status);\n if (\n !([\"open\", \"completed\", \"expired\", \"cancelled\"] as string[]).includes(\n status,\n )\n ) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n const expiresAt = string(session.expires_at);\n if (!Number.isFinite(Date.parse(expiresAt))) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n if (!Number.isSafeInteger(amount.amount_minor)) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n if (session.order_id !== null && typeof session.order_id !== \"string\") {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return {\n id: string(session.id),\n status: status as CheckoutSession[\"status\"],\n ...(typeof session.url === \"string\" ? { url: session.url } : {}),\n amount: {\n amount_minor: amount.amount_minor as number,\n currency: currency(amount.currency),\n },\n order_id: session.order_id,\n return_url: string(session.return_url),\n ...(typeof session.cancel_url === \"string\"\n ? { cancel_url: session.cancel_url }\n : {}),\n expires_at: expiresAt,\n };\n}\n","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/**\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(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","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"]}
1
+ {
2
+ "version": 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
+ "mappings": ";AAAA,SAAS,sBAAsB;AAE/B,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB,oBAAoB;AAElD,SAAS,0BAA0B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,36 @@
1
+ // src/checkout/readiness.ts
2
+ function isContactPhoneValid(phone) {
3
+ return phone.trim() === "" || /^\+?[0-9]{7,15}$/.test(phone.replace(/\s+/g, ""));
4
+ }
5
+ function payReadiness(state, contactPhoneValid, addressValid = true) {
6
+ if (!addressValid) {
7
+ return "address";
8
+ }
9
+ switch (state.status) {
10
+ case "idle":
11
+ case "loading":
12
+ return "quoting";
13
+ case "error":
14
+ return "retry";
15
+ }
16
+ if (state.quote.issues.some(
17
+ (issue) => issue.code === "delivery_region_required"
18
+ )) {
19
+ return "choose_area";
20
+ }
21
+ if (!state.quote.canCheckout || state.quote.checkout.reason === "issues") {
22
+ return "fix_issues";
23
+ }
24
+ if (state.quote.checkout.reason === "customer_required") {
25
+ return "sign_in";
26
+ }
27
+ if (!contactPhoneValid) {
28
+ return "phone";
29
+ }
30
+ return "pay";
31
+ }
32
+ export {
33
+ isContactPhoneValid,
34
+ payReadiness
35
+ };
36
+ //# sourceMappingURL=readiness.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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
+ "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
+ "names": []
7
+ }
@@ -0,0 +1,9 @@
1
+ // src/checkout/sdk.ts
2
+ import { ZappieError, money } from "@zappie/sdk";
3
+ import { wireFulfilment } from "@zappie/sdk/internal";
4
+ export {
5
+ ZappieError,
6
+ wireFulfilment as checkoutFulfilment,
7
+ money
8
+ };
9
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/checkout/sdk.ts"],
4
+ "sourcesContent": ["// The isolated checkout bundle imports the installed core so errors retain their identity.\n// eslint-disable-next-line no-restricted-imports\nexport { ZappieError, money } from \"@zappie/sdk\";\n// eslint-disable-next-line no-restricted-imports\nexport type { Currency, Quote, WireLine, WireMoney } from \"@zappie/sdk\";\n// The checkout entry's public name for the cart's wire fulfilment, shared with the core rather than bundled twice.\n// eslint-disable-next-line no-restricted-imports\nexport { wireFulfilment as checkoutFulfilment } from \"@zappie/sdk/internal\";\n"],
5
+ "mappings": ";AAEA,SAAS,aAAa,aAAa;AAKnC,SAA2B,sBAA0B;",
6
+ "names": []
7
+ }
@@ -0,0 +1,58 @@
1
+ // src/checkout/session.ts
2
+ import { money, ZappieError } from "./sdk.js";
3
+ function object(value) {
4
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
5
+ throw new ZappieError("server_error", "Invalid checkout session response");
6
+ }
7
+ return value;
8
+ }
9
+ function string(value) {
10
+ if (typeof value !== "string") {
11
+ throw new ZappieError("server_error", "Invalid checkout session response");
12
+ }
13
+ return value;
14
+ }
15
+ function currency(value) {
16
+ try {
17
+ return money(0, string(value)).currency;
18
+ } catch {
19
+ throw new ZappieError("server_error", "Invalid checkout session response");
20
+ }
21
+ }
22
+ function mapCheckoutSession(value) {
23
+ const session = object(value);
24
+ const amount = object(session.amount);
25
+ const status = string(session.status);
26
+ if (!["open", "completed", "expired", "cancelled"].includes(
27
+ status
28
+ )) {
29
+ throw new ZappieError("server_error", "Invalid checkout session response");
30
+ }
31
+ const expiresAt = string(session.expires_at);
32
+ if (!Number.isFinite(Date.parse(expiresAt))) {
33
+ throw new ZappieError("server_error", "Invalid checkout session response");
34
+ }
35
+ if (!Number.isSafeInteger(amount.amount_minor)) {
36
+ throw new ZappieError("server_error", "Invalid checkout session response");
37
+ }
38
+ if (session.order_id !== null && typeof session.order_id !== "string") {
39
+ throw new ZappieError("server_error", "Invalid checkout session response");
40
+ }
41
+ return {
42
+ id: string(session.id),
43
+ status,
44
+ ...typeof session.url === "string" ? { url: session.url } : {},
45
+ amount: {
46
+ amount_minor: amount.amount_minor,
47
+ currency: currency(amount.currency)
48
+ },
49
+ order_id: session.order_id,
50
+ return_url: string(session.return_url),
51
+ ...typeof session.cancel_url === "string" ? { cancel_url: session.cancel_url } : {},
52
+ expires_at: expiresAt
53
+ };
54
+ }
55
+ export {
56
+ mapCheckoutSession
57
+ };
58
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/checkout/session.ts"],
4
+ "sourcesContent": ["import { type Currency, money, ZappieError } from \"./sdk\";\nimport type { CheckoutSession } from \"./types\";\n\nfunction object(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return value as Record<string, unknown>;\n}\n\nfunction string(value: unknown): string {\n if (typeof value !== \"string\") {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return value;\n}\n\nfunction currency(value: unknown): Currency {\n try {\n return money(0, string(value)).currency;\n } catch {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n}\n\nexport function mapCheckoutSession(value: unknown): CheckoutSession {\n const session = object(value);\n const amount = object(session.amount);\n const status = string(session.status);\n if (\n !([\"open\", \"completed\", \"expired\", \"cancelled\"] as string[]).includes(\n status,\n )\n ) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n const expiresAt = string(session.expires_at);\n if (!Number.isFinite(Date.parse(expiresAt))) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n if (!Number.isSafeInteger(amount.amount_minor)) {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n if (session.order_id !== null && typeof session.order_id !== \"string\") {\n throw new ZappieError(\"server_error\", \"Invalid checkout session response\");\n }\n return {\n id: string(session.id),\n status: status as CheckoutSession[\"status\"],\n ...(typeof session.url === \"string\" ? { url: session.url } : {}),\n amount: {\n amount_minor: amount.amount_minor as number,\n currency: currency(amount.currency),\n },\n order_id: session.order_id,\n return_url: string(session.return_url),\n ...(typeof session.cancel_url === \"string\"\n ? { cancel_url: session.cancel_url }\n : {}),\n expires_at: expiresAt,\n };\n}\n"],
5
+ "mappings": ";AAAA,SAAwB,OAAO,mBAAmB;AAGlD,SAAS,OAAO,OAAyC;AACvD,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,SAAS,OAAO,OAAwB;AACtC,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,SAAO;AACT;AAEA,SAAS,SAAS,OAA0B;AAC1C,MAAI;AACF,WAAO,MAAM,GAAG,OAAO,KAAK,CAAC,EAAE;AAAA,EACjC,QAAQ;AACN,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACF;AAEO,SAAS,mBAAmB,OAAiC;AAClE,QAAM,UAAU,OAAO,KAAK;AAC5B,QAAM,SAAS,OAAO,QAAQ,MAAM;AACpC,QAAM,SAAS,OAAO,QAAQ,MAAM;AACpC,MACE,CAAE,CAAC,QAAQ,aAAa,WAAW,WAAW,EAAe;AAAA,IAC3D;AAAA,EACF,GACA;AACA,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,QAAM,YAAY,OAAO,QAAQ,UAAU;AAC3C,MAAI,CAAC,OAAO,SAAS,KAAK,MAAM,SAAS,CAAC,GAAG;AAC3C,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,MAAI,CAAC,OAAO,cAAc,OAAO,YAAY,GAAG;AAC9C,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,MAAI,QAAQ,aAAa,QAAQ,OAAO,QAAQ,aAAa,UAAU;AACrE,UAAM,IAAI,YAAY,gBAAgB,mCAAmC;AAAA,EAC3E;AACA,SAAO;AAAA,IACL,IAAI,OAAO,QAAQ,EAAE;AAAA,IACrB;AAAA,IACA,GAAI,OAAO,QAAQ,QAAQ,WAAW,EAAE,KAAK,QAAQ,IAAI,IAAI,CAAC;AAAA,IAC9D,QAAQ;AAAA,MACN,cAAc,OAAO;AAAA,MACrB,UAAU,SAAS,OAAO,QAAQ;AAAA,IACpC;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,YAAY,OAAO,QAAQ,UAAU;AAAA,IACrC,GAAI,OAAO,QAAQ,eAAe,WAC9B,EAAE,YAAY,QAAQ,WAAW,IACjC,CAAC;AAAA,IACL,YAAY;AAAA,EACd;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [],
5
+ "mappings": "",
6
+ "names": []
7
+ }