@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
@@ -1,2 +1,206 @@
1
- var C=864e5,x=16777216;function A(s){return JSON.stringify(["catalogue:v1",s.store,s.branchId,s.orderContext,s.menuId])}function S(s,d={}){let m=d.maxAgeMs??864e5,l=d.maxBytes??16777216;function g(){return new Promise(t=>{let e=false,n=setTimeout(()=>o(),1e3);function o(r){if(e){r?.close();return}e=true,clearTimeout(n),t(r);}try{let r=indexedDB.open(`zappie:catalogue:v1:${s}`,1);r.onupgradeneeded=()=>{r.result.createObjectStore("catalogues",{keyPath:"key"});},r.onerror=()=>o(),r.onblocked=()=>o(),r.onsuccess=()=>o(r.result);}catch{o();}})}function i(t){typeof requestIdleCallback=="function"?requestIdleCallback(t,{timeout:2e3}):setTimeout(t,0);}function c(t){i(()=>{g().then(e=>{if(e)try{let n=e.transaction("catalogues","readwrite");n.oncomplete=n.onabort=n.onerror=()=>e.close(),t(n.objectStore("catalogues"));}catch{e.close();}});});}return {async read(t){if(t.store!==s)return;let e=await g();if(e)return new Promise(n=>{let o=A(t);try{let r=e.transaction("catalogues","readonly");r.oncomplete=()=>e.close(),r.onabort=r.onerror=()=>{e.close(),n(void 0);};let p=r.objectStore("catalogues").get(o);p.onsuccess=()=>{let a=p.result,f=Date.now();if(!a||!Number.isFinite(a.savedAt)||f<a.savedAt||f-a.savedAt>=m||a.menu?.branchId!==t.branchId||a.scope?.store!==s||A(a.scope)!==o||!Array.isArray(a.coverage?.menuIds)||a.coverage.menuIds.length!==1||a.coverage.menuIds[0]!==t.menuId||!a.etag){a&&c(u=>u.delete(o)),n(void 0);return}c(u=>{let y=u.get(o);y.onsuccess=()=>{if(y.result)try{u.put({...y.result,usedAt:f});}catch{}};}),n(a);};}catch{e.close(),n(void 0);}})},save(t){t.scope.store===s&&c(e=>{try{let n=new TextEncoder().encode(JSON.stringify(t)).length;if(n>l)return;let o=A(t.scope),r=e.getAll();r.onsuccess=()=>{let p=Date.now(),a=r.result.filter(u=>u.key!==o).sort((u,y)=>u.usedAt-y.usedAt),f=a.reduce((u,y)=>u+y.bytes,n);for(let u of a)(p-u.savedAt>=m||f>l)&&(e.delete(u.key),f-=u.bytes);try{e.put({...t,key:o,bytes:n,usedAt:p});}catch{}};}catch{}});}}}async function b(s){let d=c=>Array.isArray(c)?c.map(d):c&&typeof c=="object"?Object.fromEntries(Object.entries(c).sort(([t],[e])=>t.localeCompare(e)).map(([t,e])=>[t,d(e)])):c,{version:m,...l}=s,g=new TextEncoder().encode(JSON.stringify(d(l))),i=await crypto.subtle.digest("SHA-256",g);return Array.from(new Uint8Array(i),c=>c.toString(16).padStart(2,"0")).join("")}function h(s,d){let m=S(d.store),l=A(d),g;return {async restore(){let i=await m.read(d);return i&&(g=b(i.menu),s._internal.cache.set(l,i,i.etag)),i},async publish(i){let c=g,t=b(i.menu);g=t;let e=await t,n=e!==await c,o={...i,etag:e};return n&&s._internal.cache.set(l,o,e),m.save(o),n}}}export{C as CATALOGUE_MAX_AGE_MS,x as CATALOGUE_MAX_BYTES,b as catalogueDigest,A as catalogueKey,S as createCatalogueStorage,h as createSavedCatalogue};//# sourceMappingURL=catalogue.js.map
2
- //# sourceMappingURL=catalogue.js.map
1
+ // src/persist/catalogue.ts
2
+ var CATALOGUE_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
3
+ var CATALOGUE_MAX_BYTES = 16 * 1024 * 1024;
4
+ function catalogueKey(scope) {
5
+ return JSON.stringify([
6
+ "catalogue:v1",
7
+ scope.store,
8
+ scope.branchId,
9
+ scope.orderContext,
10
+ scope.menuId
11
+ ]);
12
+ }
13
+ function createCatalogueStorage(store, options = {}) {
14
+ const maxAge = options.maxAgeMs ?? CATALOGUE_MAX_AGE_MS;
15
+ const maxBytes = options.maxBytes ?? CATALOGUE_MAX_BYTES;
16
+ function open() {
17
+ return new Promise((resolve) => {
18
+ let settled = false;
19
+ const timer = setTimeout(() => finish(), 1e3);
20
+ function finish(db) {
21
+ if (settled) {
22
+ db?.close();
23
+ return;
24
+ }
25
+ settled = true;
26
+ clearTimeout(timer);
27
+ resolve(db);
28
+ }
29
+ try {
30
+ const request = indexedDB.open(`zappie:catalogue:v1:${store}`, 1);
31
+ request.onupgradeneeded = () => {
32
+ request.result.createObjectStore("catalogues", { keyPath: "key" });
33
+ };
34
+ request.onerror = () => finish();
35
+ request.onblocked = () => finish();
36
+ request.onsuccess = () => finish(request.result);
37
+ } catch {
38
+ finish();
39
+ }
40
+ });
41
+ }
42
+ function idle(work) {
43
+ if (typeof requestIdleCallback === "function") {
44
+ requestIdleCallback(work, { timeout: 2e3 });
45
+ } else {
46
+ setTimeout(work, 0);
47
+ }
48
+ }
49
+ function mutate(work) {
50
+ idle(() => {
51
+ void open().then((db) => {
52
+ if (!db) {
53
+ return;
54
+ }
55
+ try {
56
+ const tx = db.transaction("catalogues", "readwrite");
57
+ tx.oncomplete = tx.onabort = tx.onerror = () => db.close();
58
+ work(tx.objectStore("catalogues"));
59
+ } catch {
60
+ db.close();
61
+ }
62
+ });
63
+ });
64
+ }
65
+ return {
66
+ async read(scope) {
67
+ if (scope.store !== store) {
68
+ return;
69
+ }
70
+ const db = await open();
71
+ if (!db) {
72
+ return;
73
+ }
74
+ return new Promise((resolve) => {
75
+ const key = catalogueKey(scope);
76
+ try {
77
+ const tx = db.transaction("catalogues", "readonly");
78
+ tx.oncomplete = () => db.close();
79
+ tx.onabort = tx.onerror = () => {
80
+ db.close();
81
+ resolve(void 0);
82
+ };
83
+ const request = tx.objectStore("catalogues").get(key);
84
+ request.onsuccess = () => {
85
+ const value = request.result;
86
+ const now = Date.now();
87
+ if (!value || !Number.isFinite(value.savedAt) || now < value.savedAt || now - value.savedAt >= maxAge || value.menu?.branchId !== scope.branchId || value.scope?.store !== store || catalogueKey(value.scope) !== key || !Array.isArray(value.coverage?.menuIds) || value.coverage.menuIds.length !== 1 || value.coverage.menuIds[0] !== scope.menuId || !value.etag) {
88
+ if (value) {
89
+ mutate((table) => table.delete(key));
90
+ }
91
+ resolve(void 0);
92
+ return;
93
+ }
94
+ mutate((table) => {
95
+ const latest = table.get(key);
96
+ latest.onsuccess = () => {
97
+ if (latest.result) {
98
+ try {
99
+ table.put({ ...latest.result, usedAt: now });
100
+ } catch {
101
+ }
102
+ }
103
+ };
104
+ });
105
+ resolve(value);
106
+ };
107
+ } catch {
108
+ db.close();
109
+ resolve(void 0);
110
+ }
111
+ });
112
+ },
113
+ save(value) {
114
+ if (value.scope.store !== store) {
115
+ return;
116
+ }
117
+ mutate((table) => {
118
+ try {
119
+ const bytes = new TextEncoder().encode(JSON.stringify(value)).length;
120
+ if (bytes > maxBytes) {
121
+ return;
122
+ }
123
+ const key = catalogueKey(value.scope);
124
+ const request = table.getAll();
125
+ request.onsuccess = () => {
126
+ const now = Date.now();
127
+ const entries = request.result.filter((entry) => entry.key !== key).sort((a, b) => a.usedAt - b.usedAt);
128
+ let total = entries.reduce(
129
+ (sum, entry) => sum + entry.bytes,
130
+ bytes
131
+ );
132
+ for (const entry of entries) {
133
+ if (now - entry.savedAt >= maxAge || total > maxBytes) {
134
+ table.delete(entry.key);
135
+ total -= entry.bytes;
136
+ }
137
+ }
138
+ try {
139
+ table.put({ ...value, key, bytes, usedAt: now });
140
+ } catch {
141
+ }
142
+ };
143
+ } catch {
144
+ }
145
+ });
146
+ }
147
+ };
148
+ }
149
+ async function catalogueDigest(menu) {
150
+ const canonical = (value) => {
151
+ if (Array.isArray(value)) {
152
+ return value.map(canonical);
153
+ }
154
+ if (value && typeof value === "object") {
155
+ return Object.fromEntries(
156
+ Object.entries(value).sort(([a], [b]) => a.localeCompare(b)).map(([key, entry]) => [key, canonical(entry)])
157
+ );
158
+ }
159
+ return value;
160
+ };
161
+ const { version: _version, ...content } = menu;
162
+ const bytes = new TextEncoder().encode(JSON.stringify(canonical(content)));
163
+ const hash = await crypto.subtle.digest("SHA-256", bytes);
164
+ return Array.from(
165
+ new Uint8Array(hash),
166
+ (byte) => byte.toString(16).padStart(2, "0")
167
+ ).join("");
168
+ }
169
+ function createSavedCatalogue(client, scope) {
170
+ const storage = createCatalogueStorage(scope.store);
171
+ const key = catalogueKey(scope);
172
+ let lastDigest;
173
+ return {
174
+ async restore() {
175
+ const saved = await storage.read(scope);
176
+ if (saved) {
177
+ lastDigest = catalogueDigest(saved.menu);
178
+ client._internal.cache.set(key, saved, saved.etag);
179
+ }
180
+ return saved;
181
+ },
182
+ /** Save in the background and return whether the content changed. */
183
+ async publish(value) {
184
+ const previous = lastDigest;
185
+ const next = catalogueDigest(value.menu);
186
+ lastDigest = next;
187
+ const digest = await next;
188
+ const changed = digest !== await previous;
189
+ const saved = { ...value, etag: digest };
190
+ if (changed) {
191
+ client._internal.cache.set(key, saved, digest);
192
+ }
193
+ storage.save(saved);
194
+ return changed;
195
+ }
196
+ };
197
+ }
198
+ export {
199
+ CATALOGUE_MAX_AGE_MS,
200
+ CATALOGUE_MAX_BYTES,
201
+ catalogueDigest,
202
+ catalogueKey,
203
+ createCatalogueStorage,
204
+ createSavedCatalogue
205
+ };
206
+ //# sourceMappingURL=catalogue.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../../src/persist/catalogue.ts"],"names":["CATALOGUE_MAX_AGE_MS","CATALOGUE_MAX_BYTES","catalogueKey","scope","createCatalogueStorage","store","options","maxAge","maxBytes","open","resolve","settled","timer","finish","db","request","idle","work","mutate","tx","key","value","now","table","latest","bytes","entries","entry","a","b","total","sum","catalogueDigest","menu","canonical","_version","content","hash","byte","createSavedCatalogue","client","storage","lastDigest","saved","previous","next","digest","changed"],"mappings":"AAiCO,IAAMA,EAAuB,KAAA,CAIvBC,CAAAA,CAAsB,SAI5B,SAASC,CAAAA,CAAaC,EAAuB,CAClD,OAAO,IAAA,CAAK,SAAA,CAAU,CACpB,cAAA,CACAA,CAAAA,CAAM,MACNA,CAAAA,CAAM,QAAA,CACNA,EAAM,YAAA,CACNA,CAAAA,CAAM,MACR,CAAC,CACH,CAEO,SAASC,EACdC,CAAAA,CACAC,CAAAA,CAAoD,EAAC,CACrD,CACA,IAAMC,CAAAA,CAASD,EAAQ,QAAA,EAAY,KAAA,CAC7BE,EAAWF,CAAAA,CAAQ,QAAA,EAAY,SACrC,SAASG,CAAAA,EAAyC,CAChD,OAAO,IAAI,OAAA,CAASC,CAAAA,EAAY,CAC9B,IAAIC,CAAAA,CAAU,MACRC,CAAAA,CAAQ,UAAA,CAAW,IAAMC,CAAAA,GAAU,GAAI,CAAA,CAC7C,SAASA,CAAAA,CAAOC,CAAAA,CAAkB,CAChC,GAAIH,CAAAA,CAAS,CACXG,CAAAA,EAAI,OAAM,CACV,MACF,CACAH,CAAAA,CAAU,IAAA,CACV,aAAaC,CAAK,CAAA,CAClBF,CAAAA,CAAQI,CAAE,EACZ,CACA,GAAI,CACF,IAAMC,CAAAA,CAAU,UAAU,IAAA,CAAK,CAAA,oBAAA,EAAuBV,CAAK,CAAA,CAAA,CAAI,CAAC,CAAA,CAChEU,CAAAA,CAAQ,gBAAkB,IAAM,CAC9BA,EAAQ,MAAA,CAAO,iBAAA,CAAkB,YAAA,CAAc,CAAE,QAAS,KAAM,CAAC,EACnE,CAAA,CACAA,CAAAA,CAAQ,QAAU,IAAMF,CAAAA,EAAO,CAC/BE,CAAAA,CAAQ,UAAY,IAAMF,CAAAA,GAC1BE,CAAAA,CAAQ,SAAA,CAAY,IAAMF,CAAAA,CAAOE,CAAAA,CAAQ,MAAM,EACjD,MAAQ,CACNF,CAAAA,GACF,CACF,CAAC,CACH,CACA,SAASG,CAAAA,CAAKC,CAAAA,CAAkB,CAC1B,OAAO,mBAAA,EAAwB,WACjC,mBAAA,CAAoBA,CAAAA,CAAM,CAAE,OAAA,CAAS,GAAK,CAAC,CAAA,CAE3C,WAAWA,CAAAA,CAAM,CAAC,EAEtB,CACA,SAASC,EAAOD,CAAAA,CAAuC,CACrDD,CAAAA,CAAK,IAAM,CACJP,CAAAA,EAAK,CAAE,KAAMK,CAAAA,EAAO,CACvB,GAAKA,CAAAA,CAGL,GAAI,CACF,IAAMK,EAAKL,CAAAA,CAAG,WAAA,CAAY,aAAc,WAAW,CAAA,CACnDK,EAAG,UAAA,CAAaA,CAAAA,CAAG,OAAA,CAAUA,CAAAA,CAAG,QAAU,IAAML,CAAAA,CAAG,OAAM,CACzDG,CAAAA,CAAKE,EAAG,WAAA,CAAY,YAAY,CAAC,EACnC,MAAQ,CACNL,CAAAA,CAAG,QACL,CACF,CAAC,EACH,CAAC,EACH,CACA,OAAO,CACL,MAAM,KAAKX,CAAAA,CAA4D,CACrE,GAAIA,CAAAA,CAAM,KAAA,GAAUE,CAAAA,CAClB,OAEF,IAAMS,CAAAA,CAAK,MAAML,GAAK,CACtB,GAAKK,EAGL,OAAO,IAAI,OAAA,CAASJ,CAAAA,EAAY,CAC9B,IAAMU,CAAAA,CAAMlB,EAAaC,CAAK,CAAA,CAC9B,GAAI,CACF,IAAMgB,CAAAA,CAAKL,CAAAA,CAAG,YAAY,YAAA,CAAc,UAAU,EAClDK,CAAAA,CAAG,UAAA,CAAa,IAAML,CAAAA,CAAG,KAAA,EAAM,CAC/BK,CAAAA,CAAG,QAAUA,CAAAA,CAAG,OAAA,CAAU,IAAM,CAC9BL,CAAAA,CAAG,OAAM,CACTJ,CAAAA,CAAQ,KAAA,CAAS,EACnB,EACA,IAAMK,CAAAA,CAAUI,EAAG,WAAA,CAAY,YAAY,EAAE,GAAA,CAAIC,CAAG,CAAA,CACpDL,CAAAA,CAAQ,UAAY,IAAM,CACxB,IAAMM,CAAAA,CAAQN,CAAAA,CAAQ,OAChBO,CAAAA,CAAM,IAAA,CAAK,GAAA,EAAI,CACrB,GACE,CAACD,CAAAA,EACD,CAAC,MAAA,CAAO,QAAA,CAASA,EAAM,OAAO,CAAA,EAC9BC,CAAAA,CAAMD,CAAAA,CAAM,SACZC,CAAAA,CAAMD,CAAAA,CAAM,SAAWd,CAAAA,EACvBc,CAAAA,CAAM,MAAM,QAAA,GAAalB,CAAAA,CAAM,QAAA,EAC/BkB,CAAAA,CAAM,OAAO,KAAA,GAAUhB,CAAAA,EACvBH,EAAamB,CAAAA,CAAM,KAAK,IAAMD,CAAAA,EAC9B,CAAC,KAAA,CAAM,OAAA,CAAQC,EAAM,QAAA,EAAU,OAAO,GACtCA,CAAAA,CAAM,QAAA,CAAS,QAAQ,MAAA,GAAW,CAAA,EAClCA,CAAAA,CAAM,QAAA,CAAS,QAAQ,CAAC,CAAA,GAAMlB,EAAM,MAAA,EACpC,CAACkB,EAAM,IAAA,CACP,CACIA,CAAAA,EACFH,CAAAA,CAAQK,GAAUA,CAAAA,CAAM,MAAA,CAAOH,CAAG,CAAC,CAAA,CAErCV,EAAQ,KAAA,CAAS,CAAA,CACjB,MACF,CACAQ,CAAAA,CAAQK,GAAU,CAChB,IAAMC,EAASD,CAAAA,CAAM,GAAA,CAAIH,CAAG,CAAA,CAC5BI,CAAAA,CAAO,SAAA,CAAY,IAAM,CACvB,GAAIA,CAAAA,CAAO,OACT,GAAI,CACFD,EAAM,GAAA,CAAI,CAAE,GAAGC,CAAAA,CAAO,OAAQ,MAAA,CAAQF,CAAI,CAAC,EAC7C,CAAA,KAAQ,CAER,CAEJ,EACF,CAAC,CAAA,CACDZ,EAAQW,CAAK,EACf,EACF,CAAA,KAAQ,CACNP,EAAG,KAAA,EAAM,CACTJ,CAAAA,CAAQ,MAAS,EACnB,CACF,CAAC,CACH,CAAA,CACA,IAAA,CAAKW,EAAuB,CACtBA,CAAAA,CAAM,KAAA,CAAM,KAAA,GAAUhB,GAG1Ba,CAAAA,CAAQK,CAAAA,EAAU,CAChB,GAAI,CACF,IAAME,CAAAA,CAAQ,IAAI,WAAA,EAAY,CAAE,OAAO,IAAA,CAAK,SAAA,CAAUJ,CAAK,CAAC,CAAA,CAAE,OAC9D,GAAII,CAAAA,CAAQjB,CAAAA,CACV,OAEF,IAAMY,CAAAA,CAAMlB,CAAAA,CAAamB,EAAM,KAAK,CAAA,CAC9BN,EAAUQ,CAAAA,CAAM,MAAA,EAAO,CAC7BR,CAAAA,CAAQ,UAAY,IAAM,CACxB,IAAMO,CAAAA,CAAM,IAAA,CAAK,KAAI,CACfI,CAAAA,CAAWX,CAAAA,CAAQ,MAAA,CACtB,OAAQY,CAAAA,EAAUA,CAAAA,CAAM,MAAQP,CAAG,CAAA,CACnC,KAAK,CAACQ,CAAAA,CAAGC,CAAAA,GAAMD,CAAAA,CAAE,OAASC,CAAAA,CAAE,MAAM,EACjCC,CAAAA,CAAQJ,CAAAA,CAAQ,OAClB,CAACK,CAAAA,CAAKJ,CAAAA,GAAUI,CAAAA,CAAMJ,EAAM,KAAA,CAC5BF,CACF,EACA,IAAA,IAAWE,CAAAA,IAASD,GACdJ,CAAAA,CAAMK,CAAAA,CAAM,OAAA,EAAWpB,CAAAA,EAAUuB,EAAQtB,CAAAA,IAC3Ce,CAAAA,CAAM,OAAOI,CAAAA,CAAM,GAAG,EACtBG,CAAAA,EAASH,CAAAA,CAAM,KAAA,CAAA,CAGnB,GAAI,CACFJ,CAAAA,CAAM,GAAA,CAAI,CAAE,GAAGF,CAAAA,CAAO,IAAAD,CAAAA,CAAK,KAAA,CAAAK,CAAAA,CAAO,MAAA,CAAQH,CAAI,CAAC,EACjD,MAAQ,CAER,CACF,EACF,CAAA,KAAQ,CAER,CACF,CAAC,EACH,CACF,CACF,CAGA,eAAsBU,CAAAA,CAAgBC,EAA6B,CACjE,IAAMC,EAAab,CAAAA,EACb,KAAA,CAAM,QAAQA,CAAK,CAAA,CACdA,EAAM,GAAA,CAAIa,CAAS,EAExBb,CAAAA,EAAS,OAAOA,CAAAA,EAAU,QAAA,CACrB,OAAO,WAAA,CACZ,MAAA,CAAO,QAAQA,CAAK,CAAA,CACjB,KAAK,CAAC,CAACO,CAAC,CAAA,CAAG,CAACC,CAAC,CAAA,GAAMD,EAAE,aAAA,CAAcC,CAAC,CAAC,CAAA,CACrC,GAAA,CAAI,CAAC,CAACT,EAAKO,CAAK,CAAA,GAAM,CAACP,CAAAA,CAAKc,CAAAA,CAAUP,CAAK,CAAC,CAAC,CAClD,CAAA,CAEKN,EAEH,CAAE,OAAA,CAASc,EAAU,GAAGC,CAAQ,EAAIH,CAAAA,CACpCR,CAAAA,CAAQ,IAAI,WAAA,GAAc,MAAA,CAAO,IAAA,CAAK,UAAUS,CAAAA,CAAUE,CAAO,CAAC,CAAC,CAAA,CACnEC,CAAAA,CAAO,MAAM,OAAO,MAAA,CAAO,MAAA,CAAO,UAAWZ,CAAK,CAAA,CACxD,OAAO,KAAA,CAAM,IAAA,CAAK,IAAI,UAAA,CAAWY,CAAI,CAAA,CAAIC,CAAAA,EACvCA,EAAK,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,CAAG,GAAG,CACnC,EAAE,IAAA,CAAK,EAAE,CACX,CAEO,SAASC,EACdC,CAAAA,CACArC,CAAAA,CACA,CACA,IAAMsC,EAAUrC,CAAAA,CAAuBD,CAAAA,CAAM,KAAK,CAAA,CAC5CiB,CAAAA,CAAMlB,EAAaC,CAAK,CAAA,CAE1BuC,CAAAA,CACJ,OAAO,CACL,MAAM,OAAA,EAAU,CACd,IAAMC,CAAAA,CAAQ,MAAMF,CAAAA,CAAQ,IAAA,CAAKtC,CAAK,CAAA,CACtC,OAAIwC,CAAAA,GACFD,CAAAA,CAAaV,EAAgBW,CAAAA,CAAM,IAAI,EACvCH,CAAAA,CAAO,SAAA,CAAU,KAAA,CAAM,GAAA,CAAIpB,EAAKuB,CAAAA,CAAOA,CAAAA,CAAM,IAAI,CAAA,CAAA,CAE5CA,CACT,EAEA,MAAM,OAAA,CAAQtB,CAAAA,CAAuB,CACnC,IAAMuB,CAAAA,CAAWF,CAAAA,CACXG,EAAOb,CAAAA,CAAgBX,CAAAA,CAAM,IAAI,CAAA,CACvCqB,CAAAA,CAAaG,CAAAA,CACb,IAAMC,EAAS,MAAMD,CAAAA,CACfE,EAAUD,CAAAA,GAAY,MAAMF,EAC5BD,CAAAA,CAAQ,CAAE,GAAGtB,CAAAA,CAAO,KAAMyB,CAAO,CAAA,CACvC,OAAIC,CAAAA,EACFP,CAAAA,CAAO,UAAU,KAAA,CAAM,GAAA,CAAIpB,EAAKuB,CAAAA,CAAOG,CAAM,EAE/CL,CAAAA,CAAQ,IAAA,CAAKE,CAAK,CAAA,CACXI,CACT,CACF,CACF","file":"catalogue.js","sourcesContent":["import type { CategoryPage, Menu } from \"../models\";\n\n/**\n * The store, branch, order context and source menu that identify a saved catalogue.\n */\nexport type CatalogueScope = {\n store: string;\n branchId: string;\n orderContext: \"delivery\" | \"pickup\" | \"dineIn\";\n menuId: string;\n};\n/** The saved coverage. A complete source menu still covers only part of the branch. */\nexport type SavedCatalogue = {\n scope: CatalogueScope;\n menu: Menu;\n coverage: { menuIds: string[]; complete: boolean };\n pages: { categoryId: string; cursor?: string; page: CategoryPage }[];\n etag: string;\n savedAt: number;\n /**\n * The host's catalogue revision when saved. An unchanged revision means the\n * saved copy is current and needs no background refresh.\n */\n revision?: string;\n};\ntype RecordValue = SavedCatalogue & {\n key: string;\n bytes: number;\n usedAt: number;\n};\n/**\n * Default saved-catalogue lifetime in milliseconds: 24 hours.\n */\nexport const CATALOGUE_MAX_AGE_MS = 24 * 60 * 60 * 1000;\n/**\n * Default per-store catalogue storage budget in serialized bytes: 16 MiB.\n */\nexport const CATALOGUE_MAX_BYTES = 16 * 1024 * 1024;\n/**\n * Build a versioned JSON storage key from the store, branch, order context and menu ID.\n */\nexport function catalogueKey(scope: CatalogueScope) {\n return JSON.stringify([\n \"catalogue:v1\",\n scope.store,\n scope.branchId,\n scope.orderContext,\n scope.menuId,\n ]);\n}\n/** Opt-in browser persistence. Storage failures never escape into shopper UI. */\nexport function createCatalogueStorage(\n store: string,\n options: { maxAgeMs?: number; maxBytes?: number } = {},\n) {\n const maxAge = options.maxAgeMs ?? CATALOGUE_MAX_AGE_MS;\n const maxBytes = options.maxBytes ?? CATALOGUE_MAX_BYTES;\n function open(): Promise<IDBDatabase | undefined> {\n return new Promise((resolve) => {\n let settled = false;\n const timer = setTimeout(() => finish(), 1000);\n function finish(db?: IDBDatabase) {\n if (settled) {\n db?.close();\n return;\n }\n settled = true;\n clearTimeout(timer);\n resolve(db);\n }\n try {\n const request = indexedDB.open(`zappie:catalogue:v1:${store}`, 1);\n request.onupgradeneeded = () => {\n request.result.createObjectStore(\"catalogues\", { keyPath: \"key\" });\n };\n request.onerror = () => finish();\n request.onblocked = () => finish();\n request.onsuccess = () => finish(request.result);\n } catch {\n finish();\n }\n });\n }\n function idle(work: () => void) {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(work, { timeout: 2000 });\n } else {\n setTimeout(work, 0);\n }\n }\n function mutate(work: (table: IDBObjectStore) => void) {\n idle(() => {\n void open().then((db) => {\n if (!db) {\n return;\n }\n try {\n const tx = db.transaction(\"catalogues\", \"readwrite\");\n tx.oncomplete = tx.onabort = tx.onerror = () => db.close();\n work(tx.objectStore(\"catalogues\"));\n } catch {\n db.close();\n }\n });\n });\n }\n return {\n async read(scope: CatalogueScope): Promise<SavedCatalogue | undefined> {\n if (scope.store !== store) {\n return;\n }\n const db = await open();\n if (!db) {\n return;\n }\n return new Promise((resolve) => {\n const key = catalogueKey(scope);\n try {\n const tx = db.transaction(\"catalogues\", \"readonly\");\n tx.oncomplete = () => db.close();\n tx.onabort = tx.onerror = () => {\n db.close();\n resolve(undefined);\n };\n const request = tx.objectStore(\"catalogues\").get(key);\n request.onsuccess = () => {\n const value = request.result as RecordValue | undefined;\n const now = Date.now();\n if (\n !value ||\n !Number.isFinite(value.savedAt) ||\n now < value.savedAt ||\n now - value.savedAt >= maxAge ||\n value.menu?.branchId !== scope.branchId ||\n value.scope?.store !== store ||\n catalogueKey(value.scope) !== key ||\n !Array.isArray(value.coverage?.menuIds) ||\n value.coverage.menuIds.length !== 1 ||\n value.coverage.menuIds[0] !== scope.menuId ||\n !value.etag\n ) {\n if (value) {\n mutate((table) => table.delete(key));\n }\n resolve(undefined);\n return;\n }\n mutate((table) => {\n const latest = table.get(key);\n latest.onsuccess = () => {\n if (latest.result) {\n try {\n table.put({ ...latest.result, usedAt: now });\n } catch {\n // A quota/security failure only disables this cache write.\n }\n }\n };\n });\n resolve(value);\n };\n } catch {\n db.close();\n resolve(undefined);\n }\n });\n },\n save(value: SavedCatalogue) {\n if (value.scope.store !== store) {\n return;\n }\n mutate((table) => {\n try {\n const bytes = new TextEncoder().encode(JSON.stringify(value)).length;\n if (bytes > maxBytes) {\n return;\n }\n const key = catalogueKey(value.scope);\n const request = table.getAll();\n request.onsuccess = () => {\n const now = Date.now();\n const entries = (request.result as RecordValue[])\n .filter((entry) => entry.key !== key)\n .sort((a, b) => a.usedAt - b.usedAt);\n let total = entries.reduce(\n (sum, entry) => sum + entry.bytes,\n bytes,\n );\n for (const entry of entries) {\n if (now - entry.savedAt >= maxAge || total > maxBytes) {\n table.delete(entry.key);\n total -= entry.bytes;\n }\n }\n try {\n table.put({ ...value, key, bytes, usedAt: now });\n } catch {\n // Quota failures can throw synchronously as well as abort a transaction.\n }\n };\n } catch {\n // Serialization/storage failures are a cache miss, never a form error.\n }\n });\n },\n };\n}\n\n/** Digest excludes transport versions: publication follows shopper-visible content. */\nexport async function catalogueDigest(menu: Menu): Promise<string> {\n const canonical = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map(canonical);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, canonical(entry)]),\n );\n }\n return value;\n };\n const { version: _version, ...content } = menu;\n const bytes = new TextEncoder().encode(JSON.stringify(canonical(content)));\n const hash = await crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(hash), (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n}\n/** A saved source menu that stays separate from the complete branch catalogue. */\nexport function createSavedCatalogue(\n client: import(\"../client\").Zappie,\n scope: CatalogueScope,\n) {\n const storage = createCatalogueStorage(scope.store);\n const key = catalogueKey(scope);\n // Digests run after the saved copy has rendered, never in front of it.\n let lastDigest: Promise<string> | undefined;\n return {\n async restore() {\n const saved = await storage.read(scope);\n if (saved) {\n lastDigest = catalogueDigest(saved.menu);\n client._internal.cache.set(key, saved, saved.etag);\n }\n return saved;\n },\n /** Save in the background and return whether the content changed. */\n async publish(value: SavedCatalogue) {\n const previous = lastDigest;\n const next = catalogueDigest(value.menu);\n lastDigest = next;\n const digest = await next;\n const changed = digest !== (await previous);\n const saved = { ...value, etag: digest };\n if (changed) {\n client._internal.cache.set(key, saved, digest);\n }\n storage.save(saved);\n return changed;\n },\n };\n}\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/persist/catalogue.ts"],
4
+ "sourcesContent": ["import type { CategoryPage, Menu } from \"../models\";\n\n/**\n * The store, branch, order context and source menu that identify a saved catalogue.\n */\nexport type CatalogueScope = {\n store: string;\n branchId: string;\n orderContext: \"delivery\" | \"pickup\" | \"dineIn\";\n menuId: string;\n};\n/** The saved coverage. A complete source menu still covers only part of the branch. */\nexport type SavedCatalogue = {\n scope: CatalogueScope;\n menu: Menu;\n coverage: { menuIds: string[]; complete: boolean };\n pages: { categoryId: string; cursor?: string; page: CategoryPage }[];\n etag: string;\n savedAt: number;\n /**\n * The host's catalogue revision when saved. An unchanged revision means the\n * saved copy is current and needs no background refresh.\n */\n revision?: string;\n};\ntype RecordValue = SavedCatalogue & {\n key: string;\n bytes: number;\n usedAt: number;\n};\n/**\n * Default saved-catalogue lifetime in milliseconds: 24 hours.\n */\nexport const CATALOGUE_MAX_AGE_MS = 24 * 60 * 60 * 1000;\n/**\n * Default per-store catalogue storage budget in serialized bytes: 16 MiB.\n */\nexport const CATALOGUE_MAX_BYTES = 16 * 1024 * 1024;\n/**\n * Build a versioned JSON storage key from the store, branch, order context and menu ID.\n */\nexport function catalogueKey(scope: CatalogueScope) {\n return JSON.stringify([\n \"catalogue:v1\",\n scope.store,\n scope.branchId,\n scope.orderContext,\n scope.menuId,\n ]);\n}\n/** Opt-in browser persistence. Storage failures never escape into shopper UI. */\nexport function createCatalogueStorage(\n store: string,\n options: { maxAgeMs?: number; maxBytes?: number } = {},\n) {\n const maxAge = options.maxAgeMs ?? CATALOGUE_MAX_AGE_MS;\n const maxBytes = options.maxBytes ?? CATALOGUE_MAX_BYTES;\n function open(): Promise<IDBDatabase | undefined> {\n return new Promise((resolve) => {\n let settled = false;\n const timer = setTimeout(() => finish(), 1000);\n function finish(db?: IDBDatabase) {\n if (settled) {\n db?.close();\n return;\n }\n settled = true;\n clearTimeout(timer);\n resolve(db);\n }\n try {\n const request = indexedDB.open(`zappie:catalogue:v1:${store}`, 1);\n request.onupgradeneeded = () => {\n request.result.createObjectStore(\"catalogues\", { keyPath: \"key\" });\n };\n request.onerror = () => finish();\n request.onblocked = () => finish();\n request.onsuccess = () => finish(request.result);\n } catch {\n finish();\n }\n });\n }\n function idle(work: () => void) {\n if (typeof requestIdleCallback === \"function\") {\n requestIdleCallback(work, { timeout: 2000 });\n } else {\n setTimeout(work, 0);\n }\n }\n function mutate(work: (table: IDBObjectStore) => void) {\n idle(() => {\n void open().then((db) => {\n if (!db) {\n return;\n }\n try {\n const tx = db.transaction(\"catalogues\", \"readwrite\");\n tx.oncomplete = tx.onabort = tx.onerror = () => db.close();\n work(tx.objectStore(\"catalogues\"));\n } catch {\n db.close();\n }\n });\n });\n }\n return {\n async read(scope: CatalogueScope): Promise<SavedCatalogue | undefined> {\n if (scope.store !== store) {\n return;\n }\n const db = await open();\n if (!db) {\n return;\n }\n return new Promise((resolve) => {\n const key = catalogueKey(scope);\n try {\n const tx = db.transaction(\"catalogues\", \"readonly\");\n tx.oncomplete = () => db.close();\n tx.onabort = tx.onerror = () => {\n db.close();\n resolve(undefined);\n };\n const request = tx.objectStore(\"catalogues\").get(key);\n request.onsuccess = () => {\n const value = request.result as RecordValue | undefined;\n const now = Date.now();\n if (\n !value ||\n !Number.isFinite(value.savedAt) ||\n now < value.savedAt ||\n now - value.savedAt >= maxAge ||\n value.menu?.branchId !== scope.branchId ||\n value.scope?.store !== store ||\n catalogueKey(value.scope) !== key ||\n !Array.isArray(value.coverage?.menuIds) ||\n value.coverage.menuIds.length !== 1 ||\n value.coverage.menuIds[0] !== scope.menuId ||\n !value.etag\n ) {\n if (value) {\n mutate((table) => table.delete(key));\n }\n resolve(undefined);\n return;\n }\n mutate((table) => {\n const latest = table.get(key);\n latest.onsuccess = () => {\n if (latest.result) {\n try {\n table.put({ ...latest.result, usedAt: now });\n } catch {\n // A quota/security failure only disables this cache write.\n }\n }\n };\n });\n resolve(value);\n };\n } catch {\n db.close();\n resolve(undefined);\n }\n });\n },\n save(value: SavedCatalogue) {\n if (value.scope.store !== store) {\n return;\n }\n mutate((table) => {\n try {\n const bytes = new TextEncoder().encode(JSON.stringify(value)).length;\n if (bytes > maxBytes) {\n return;\n }\n const key = catalogueKey(value.scope);\n const request = table.getAll();\n request.onsuccess = () => {\n const now = Date.now();\n const entries = (request.result as RecordValue[])\n .filter((entry) => entry.key !== key)\n .sort((a, b) => a.usedAt - b.usedAt);\n let total = entries.reduce(\n (sum, entry) => sum + entry.bytes,\n bytes,\n );\n for (const entry of entries) {\n if (now - entry.savedAt >= maxAge || total > maxBytes) {\n table.delete(entry.key);\n total -= entry.bytes;\n }\n }\n try {\n table.put({ ...value, key, bytes, usedAt: now });\n } catch {\n // Quota failures can throw synchronously as well as abort a transaction.\n }\n };\n } catch {\n // Serialization/storage failures are a cache miss, never a form error.\n }\n });\n },\n };\n}\n\n/** Digest excludes transport versions: publication follows shopper-visible content. */\nexport async function catalogueDigest(menu: Menu): Promise<string> {\n const canonical = (value: unknown): unknown => {\n if (Array.isArray(value)) {\n return value.map(canonical);\n }\n if (value && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value)\n .sort(([a], [b]) => a.localeCompare(b))\n .map(([key, entry]) => [key, canonical(entry)]),\n );\n }\n return value;\n };\n const { version: _version, ...content } = menu;\n const bytes = new TextEncoder().encode(JSON.stringify(canonical(content)));\n const hash = await crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(hash), (byte) =>\n byte.toString(16).padStart(2, \"0\"),\n ).join(\"\");\n}\n/** A saved source menu that stays separate from the complete branch catalogue. */\nexport function createSavedCatalogue(\n client: import(\"../client\").Zappie,\n scope: CatalogueScope,\n) {\n const storage = createCatalogueStorage(scope.store);\n const key = catalogueKey(scope);\n // Digests run after the saved copy has rendered, never in front of it.\n let lastDigest: Promise<string> | undefined;\n return {\n async restore() {\n const saved = await storage.read(scope);\n if (saved) {\n lastDigest = catalogueDigest(saved.menu);\n client._internal.cache.set(key, saved, saved.etag);\n }\n return saved;\n },\n /** Save in the background and return whether the content changed. */\n async publish(value: SavedCatalogue) {\n const previous = lastDigest;\n const next = catalogueDigest(value.menu);\n lastDigest = next;\n const digest = await next;\n const changed = digest !== (await previous);\n const saved = { ...value, etag: digest };\n if (changed) {\n client._internal.cache.set(key, saved, digest);\n }\n storage.save(saved);\n return changed;\n },\n };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,97 @@
1
+ // src/places/client.ts
2
+ import { createPlacesRequest } from "./request.js";
3
+ import { API_VERSION, RestTransport, validateConfig } from "./sdk.js";
4
+ import { createAddressSearch } from "./search.js";
5
+ var DEFAULT_CUSTOMER_BASE = "/_zappie/api";
6
+ function createPlaces(options) {
7
+ validateConfig({ store: "places", key: options.key });
8
+ const base = new RestTransport({
9
+ ...options.baseUrl ? { baseUrl: options.baseUrl } : {},
10
+ ...options.fetch ? { fetch: options.fetch } : {}
11
+ }).baseUrl;
12
+ const customerBase = (options.customerBase ?? DEFAULT_CUSTOMER_BASE).replace(
13
+ /\/+$/,
14
+ ""
15
+ );
16
+ const request = createPlacesRequest(
17
+ base,
18
+ options.key,
19
+ options.version ?? API_VERSION,
20
+ options.fetch ?? globalThis.fetch
21
+ );
22
+ const readPlace = (id, read) => {
23
+ const params = new URLSearchParams();
24
+ if (read.branchId !== void 0) {
25
+ params.set("branch_id", read.branchId);
26
+ }
27
+ if (read.sessionToken !== void 0) {
28
+ params.set("session", read.sessionToken);
29
+ }
30
+ const suffix = params.size > 0 ? `?${params}` : "";
31
+ return request(`/places/${encodeURIComponent(id)}${suffix}`, {
32
+ method: "GET",
33
+ ...read.signal ? { signal: read.signal } : {}
34
+ });
35
+ };
36
+ const client = {
37
+ async autocomplete(query, sessionToken, read = {}) {
38
+ if (!query.trim()) {
39
+ return [];
40
+ }
41
+ const params = new URLSearchParams({
42
+ q: query.trim(),
43
+ session: sessionToken
44
+ });
45
+ const result = await request(
46
+ `/places/autocomplete?${params}`,
47
+ { method: "GET", ...read.signal ? { signal: read.signal } : {} }
48
+ );
49
+ return result.suggestions;
50
+ },
51
+ place(id, read) {
52
+ return readPlace(id, read);
53
+ },
54
+ reverse(lat, lng, read = {}) {
55
+ const params = new URLSearchParams({
56
+ lat: String(lat),
57
+ lng: String(lng)
58
+ });
59
+ return request(`/places/reverse?${params}`, {
60
+ method: "GET",
61
+ ...read.signal ? { signal: read.signal } : {}
62
+ });
63
+ },
64
+ staticMapUrl(lat, lng, branchId) {
65
+ const params = new URLSearchParams({
66
+ lat: String(lat),
67
+ lng: String(lng)
68
+ });
69
+ if (branchId !== void 0) {
70
+ params.set("branch_id", branchId);
71
+ }
72
+ return `${customerBase}/places/static-map?${params}`;
73
+ },
74
+ zoneCheck(body, read = {}) {
75
+ return request("/delivery/zones/check", {
76
+ method: "POST",
77
+ headers: { "Content-Type": "application/json" },
78
+ body: JSON.stringify(body),
79
+ ...read.signal ? { signal: read.signal } : {}
80
+ });
81
+ },
82
+ createAddressSearch(searchOptions = {}) {
83
+ return createAddressSearch(
84
+ {
85
+ autocomplete: client.autocomplete,
86
+ place: readPlace
87
+ },
88
+ searchOptions
89
+ );
90
+ }
91
+ };
92
+ return client;
93
+ }
94
+ export {
95
+ createPlaces
96
+ };
97
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/places/client.ts"],
4
+ "sourcesContent": ["import { createPlacesRequest } from \"./request\";\nimport { API_VERSION, RestTransport, validateConfig } from \"./sdk\";\nimport { createAddressSearch } from \"./search\";\nimport type {\n AddressSearchOptions,\n Place,\n PlaceOptions,\n PlacesClientOptions,\n PlaceSuggestion,\n SignalOptions,\n ZoneCheck,\n ZoneCheckRequest,\n} from \"./types\";\n\nconst DEFAULT_CUSTOMER_BASE = \"/_zappie/api\";\n\n/**\n * Create a client for address autocomplete, place lookup and delivery-zone checks.\n * Also provides reverse lookup, static-map URLs and debounced address search controllers.\n *\n * @param options - Your publishable key and optional transport settings.\n * @returns A places client. Creating it validates the key format without fetching data.\n */\nexport function createPlaces(options: PlacesClientOptions) {\n validateConfig({ store: \"places\", key: options.key });\n const base = new RestTransport({\n ...(options.baseUrl ? { baseUrl: options.baseUrl } : {}),\n ...(options.fetch ? { fetch: options.fetch } : {}),\n }).baseUrl;\n const customerBase = (options.customerBase ?? DEFAULT_CUSTOMER_BASE).replace(\n /\\/+$/,\n \"\",\n );\n const request = createPlacesRequest(\n base,\n options.key,\n options.version ?? API_VERSION,\n options.fetch ?? globalThis.fetch,\n );\n const readPlace = (\n id: string,\n read: SignalOptions & { branchId?: string; sessionToken?: string },\n ) => {\n const params = new URLSearchParams();\n if (read.branchId !== undefined) {\n params.set(\"branch_id\", read.branchId);\n }\n if (read.sessionToken !== undefined) {\n params.set(\"session\", read.sessionToken);\n }\n const suffix = params.size > 0 ? `?${params}` : \"\";\n return request<Place>(`/places/${encodeURIComponent(id)}${suffix}`, {\n method: \"GET\",\n ...(read.signal ? { signal: read.signal } : {}),\n });\n };\n const client = {\n async autocomplete(\n query: string,\n sessionToken: string,\n read: SignalOptions = {},\n ): Promise<PlaceSuggestion[]> {\n if (!query.trim()) {\n return [];\n }\n const params = new URLSearchParams({\n q: query.trim(),\n session: sessionToken,\n });\n const result = await request<{ suggestions: PlaceSuggestion[] }>(\n `/places/autocomplete?${params}`,\n { method: \"GET\", ...(read.signal ? { signal: read.signal } : {}) },\n );\n return result.suggestions;\n },\n place(id: string, read: PlaceOptions): Promise<Place> {\n return readPlace(id, read);\n },\n reverse(lat: number, lng: number, read: SignalOptions = {}) {\n const params = new URLSearchParams({\n lat: String(lat),\n lng: String(lng),\n });\n return request<Place>(`/places/reverse?${params}`, {\n method: \"GET\",\n ...(read.signal ? { signal: read.signal } : {}),\n });\n },\n staticMapUrl(lat: number, lng: number, branchId?: string) {\n const params = new URLSearchParams({\n lat: String(lat),\n lng: String(lng),\n });\n if (branchId !== undefined) {\n params.set(\"branch_id\", branchId);\n }\n return `${customerBase}/places/static-map?${params}`;\n },\n zoneCheck(body: ZoneCheckRequest, read: SignalOptions = {}) {\n return request<ZoneCheck>(\"/delivery/zones/check\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n ...(read.signal ? { signal: read.signal } : {}),\n });\n },\n createAddressSearch(searchOptions: AddressSearchOptions = {}) {\n return createAddressSearch(\n {\n autocomplete: client.autocomplete,\n place: readPlace,\n },\n searchOptions,\n );\n },\n };\n return client;\n}\n\n/**\n * The place lookup, address search and delivery-zone operations returned by createPlaces.\n */\nexport type PlacesClient = ReturnType<typeof createPlaces>;\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,20 @@
1
+ // src/places/error.ts
2
+ import { stableErrorCode } from "../internal/customer-http.js";
3
+ import { ZappieError } from "./sdk.js";
4
+ var PlacesError = class extends ZappieError {
5
+ constructor(status, apiCode, message, param, issues) {
6
+ super(stableErrorCode(status), message, {
7
+ status,
8
+ retryable: status === 429 || status >= 500,
9
+ ...param !== void 0 ? { param } : {}
10
+ });
11
+ this.apiCode = apiCode;
12
+ if (issues !== void 0) {
13
+ this.issues = issues;
14
+ }
15
+ }
16
+ };
17
+ export {
18
+ PlacesError
19
+ };
20
+ //# sourceMappingURL=error.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/places/error.ts"],
4
+ "sourcesContent": ["import { stableErrorCode } from \"../internal/customer-http\";\nimport { ZappieError } from \"./sdk\";\n\n/**\n * A places API failure with its HTTP status, API code and optional validation issues.\n * Statuses 429 and 5xx are marked retryable.\n */\nexport class PlacesError 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 retryable: 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,cAAN,cAA0B,YAAY;AAAA,EAG3C,YACE,QACS,SACT,SACA,OACA,QACA;AACA,UAAM,gBAAgB,MAAM,GAAG,SAAS;AAAA,MACtC;AAAA,MACA,WAAW,WAAW,OAAO,UAAU;AAAA,MACvC,GAAI,UAAU,SAAY,EAAE,MAAM,IAAI,CAAC;AAAA,IACzC,CAAC;AATQ;AAUT,QAAI,WAAW,QAAW;AACxB,WAAK,SAAS;AAAA,IAChB;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -1 +1,8 @@
1
- import {ZappieError,RestTransport,API_VERSION}from'@zappie/sdk';import {validateConfig}from'@zappie/sdk/internal';function P(n){return n===400||n===422?"invalid_request":n===401?"unauthorized":n===404?"not_found":n===429?"rate_limited":"server_error"}async function b(n,a){let s=await n.json().catch(()=>({})),o=s&&typeof s=="object"?s:{},e="error"in o&&o.error&&typeof o.error=="object"?o.error:{};return {apiCode:"code"in e&&typeof e.code=="string"?e.code:"server_error",message:"message"in e&&typeof e.message=="string"?e.message:a,..."param"in e&&typeof e.param=="string"?{param:e.param}:{},..."issues"in e?{issues:e.issues}:{}}}function E(n,a){return a?.throwIfAborted(),new Promise((s,o)=>{let i=setTimeout(()=>{a?.removeEventListener("abort",r),s();},n),r=()=>{clearTimeout(i),a?.removeEventListener("abort",r),o(a?.reason??new DOMException("Aborted","AbortError"));};a?.addEventListener("abort",r,{once:true});})}async function y(n,a,s,o){for(let e=0;e<2;e++)try{return await n(a,{...s,credentials:"same-origin",headers:{Accept:"application/json",...s.headers}})}catch(i){if(s.signal?.aborted)throw s.signal.reason??i;if(e===1)throw new ZappieError("network_error",o,{cause:i,retryable:true});await E(400,s.signal??void 0);}throw new ZappieError("network_error",o,{retryable:true})}var u=class extends ZappieError{constructor(s,o,e,i,r){super(P(s),e,{status:s,retryable:s===429||s>=500,...i!==void 0?{param:i}:{}});this.apiCode=o;r!==void 0&&(this.issues=r);}};function v(n,a,s,o){return async(e,i={})=>{let r=await y(o,n+e,{...i,redirect:"manual",headers:{Authorization:`Bearer ${a}`,"Zappie-Version":s,...i.headers}},"Could not reach the places service");if(!r.ok){let t=await b(r,`The places service answered ${r.status}`);throw new u(r.status,t.apiCode,t.message,t.param,t.issues)}return await r.json()}}var g=()=>new DOMException("Superseded","AbortError");function A(n,a={}){let s=a.debounceMs??250,o=crypto.randomUUID(),e,i,r,t=0,c=()=>{t++,i!==void 0&&(clearTimeout(i),i=void 0),e?.abort(g()),e=void 0,r?.(g()),r=void 0;};return {suggest(l){c();let p=t;return l.trim()?new Promise((d,f)=>{r=f,i=setTimeout(async()=>{i=void 0,e=new AbortController;try{let m=await n.autocomplete(l.trim(),o,{signal:e.signal});p===t&&d(m);}catch(m){p===t&&f(m);}finally{p===t&&(r=void 0,e=void 0);}},s);}):Promise.resolve([])},async select(l){c();let p=t;e=new AbortController;try{let d=await n.place(l,{...a.branchId!==void 0?{branchId:a.branchId}:{},sessionToken:o,signal:e.signal});if(p!==t)throw g();return o=crypto.randomUUID(),d}finally{p===t&&(e=void 0);}},dispose:c}}var R="/_zappie/api";function k(n){validateConfig({store:"places",key:n.key});let a=new RestTransport({...n.baseUrl?{baseUrl:n.baseUrl}:{},...n.fetch?{fetch:n.fetch}:{}}).baseUrl,s=(n.customerBase??R).replace(/\/+$/,""),o=v(a,n.key,n.version??API_VERSION,n.fetch??globalThis.fetch),e=(r,t)=>{let c=new URLSearchParams;t.branchId!==void 0&&c.set("branch_id",t.branchId),t.sessionToken!==void 0&&c.set("session",t.sessionToken);let l=c.size>0?`?${c}`:"";return o(`/places/${encodeURIComponent(r)}${l}`,{method:"GET",...t.signal?{signal:t.signal}:{}})},i={async autocomplete(r,t,c={}){if(!r.trim())return [];let l=new URLSearchParams({q:r.trim(),session:t});return (await o(`/places/autocomplete?${l}`,{method:"GET",...c.signal?{signal:c.signal}:{}})).suggestions},place(r,t){return e(r,t)},reverse(r,t,c={}){let l=new URLSearchParams({lat:String(r),lng:String(t)});return o(`/places/reverse?${l}`,{method:"GET",...c.signal?{signal:c.signal}:{}})},staticMapUrl(r,t,c){let l=new URLSearchParams({lat:String(r),lng:String(t)});return c!==void 0&&l.set("branch_id",c),`${s}/places/static-map?${l}`},zoneCheck(r,t={}){return o("/delivery/zones/check",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r),...t.signal?{signal:t.signal}:{}})},createAddressSearch(r={}){return A({autocomplete:i.autocomplete,place:e},r)}};return i}export{u as PlacesError,k as createPlaces};//# sourceMappingURL=index.js.map
1
+ // src/places/index.ts
2
+ import { createPlaces } from "./client.js";
3
+ import { PlacesError } from "./error.js";
4
+ export {
5
+ PlacesError,
6
+ createPlaces
7
+ };
8
+ //# sourceMappingURL=index.js.map
@@ -1 +1,7 @@
1
- {"version":3,"sources":["../../src/internal/customer-http.ts","../../src/places/error.ts","../../src/places/request.ts","../../src/places/search.ts","../../src/places/client.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","PlacesError","apiCode","param","issues","createPlacesRequest","base","key","version","path","createAddressSearch","client","options","debounceMs","token","controller","rejectPending","revision","cancel","query","current","failure","placeId","DEFAULT_CUSTOMER_BASE","createPlaces","validateConfig","RestTransport","customerBase","request","API_VERSION","readPlace","id","read","params","suffix","sessionToken","lat","lng","branchId","searchOptions"],"mappings":"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","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 places API failure with its HTTP status, API code and optional validation issues.\n * Statuses 429 and 5xx are marked retryable.\n */\nexport class PlacesError 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 retryable: status === 429 || status >= 500,\n ...(param !== undefined ? { param } : {}),\n });\n if (issues !== undefined) {\n this.issues = issues;\n }\n }\n}\n","import { apiError, requestWithRetry } from \"../internal/customer-http\";\nimport { PlacesError } from \"./error\";\n\nexport type PlacesRequest = <T>(path: string, init?: RequestInit) => Promise<T>;\n\nexport function createPlacesRequest(\n base: string,\n key: string,\n version: string,\n fetcher: typeof fetch,\n): PlacesRequest {\n return async <T>(path: string, init: RequestInit = {}): Promise<T> => {\n const response = await requestWithRetry(\n fetcher,\n base + path,\n {\n ...init,\n // Workers reject redirect: \"error\"; !response.ok below refuses a redirect.\n redirect: \"manual\",\n headers: {\n Authorization: `Bearer ${key}`,\n \"Zappie-Version\": version,\n ...init.headers,\n },\n },\n \"Could not reach the places service\",\n );\n if (!response.ok) {\n const value = await apiError(\n response,\n `The places service answered ${response.status}`,\n );\n throw new PlacesError(\n response.status,\n value.apiCode,\n value.message,\n value.param,\n value.issues,\n );\n }\n return (await response.json()) as T;\n };\n}\n","import type { AddressSearchOptions, Place, PlaceSuggestion } from \"./types\";\n\ntype SearchClient = {\n autocomplete(\n query: string,\n token: string,\n options: { signal?: AbortSignal },\n ): Promise<PlaceSuggestion[]>;\n place(\n id: string,\n options: {\n branchId?: string;\n sessionToken?: string;\n signal?: AbortSignal;\n },\n ): Promise<Place>;\n};\n\nconst aborted = () => new DOMException(\"Superseded\", \"AbortError\");\n\nexport function createAddressSearch(\n client: SearchClient,\n options: AddressSearchOptions = {},\n) {\n const debounceMs = options.debounceMs ?? 250;\n let token = crypto.randomUUID();\n let controller: AbortController | undefined;\n let timer: ReturnType<typeof setTimeout> | undefined;\n let rejectPending: ((reason: unknown) => void) | undefined;\n let revision = 0;\n const cancel = () => {\n revision++;\n if (timer !== undefined) {\n clearTimeout(timer);\n timer = undefined;\n }\n controller?.abort(aborted());\n controller = undefined;\n rejectPending?.(aborted());\n rejectPending = undefined;\n };\n return {\n suggest(query: string): Promise<PlaceSuggestion[]> {\n cancel();\n const current = revision;\n if (!query.trim()) {\n return Promise.resolve([]);\n }\n return new Promise((resolve, reject) => {\n rejectPending = reject;\n timer = setTimeout(async () => {\n timer = undefined;\n controller = new AbortController();\n try {\n const value = await client.autocomplete(query.trim(), token, {\n signal: controller.signal,\n });\n if (current === revision) {\n resolve(value);\n }\n } catch (failure) {\n if (current === revision) {\n reject(failure);\n }\n } finally {\n if (current === revision) {\n rejectPending = undefined;\n controller = undefined;\n }\n }\n }, debounceMs);\n });\n },\n async select(placeId: string): Promise<Place> {\n cancel();\n const current = revision;\n controller = new AbortController();\n try {\n const value = await client.place(placeId, {\n ...(options.branchId !== undefined\n ? { branchId: options.branchId }\n : {}),\n sessionToken: token,\n signal: controller.signal,\n });\n if (current !== revision) {\n throw aborted();\n }\n token = crypto.randomUUID();\n return value;\n } finally {\n if (current === revision) {\n controller = undefined;\n }\n }\n },\n dispose: cancel,\n };\n}\n","import { createPlacesRequest } from \"./request\";\nimport { API_VERSION, RestTransport, validateConfig } from \"./sdk\";\nimport { createAddressSearch } from \"./search\";\nimport type {\n AddressSearchOptions,\n Place,\n PlaceOptions,\n PlacesClientOptions,\n PlaceSuggestion,\n SignalOptions,\n ZoneCheck,\n ZoneCheckRequest,\n} from \"./types\";\n\nconst DEFAULT_CUSTOMER_BASE = \"/_zappie/api\";\n\n/**\n * Create a client for address autocomplete, place lookup and delivery-zone checks.\n * Also provides reverse lookup, static-map URLs and debounced address search controllers.\n *\n * @param options - Your publishable key and optional transport settings.\n * @returns A places client. Creating it validates the key format without fetching data.\n */\nexport function createPlaces(options: PlacesClientOptions) {\n validateConfig({ store: \"places\", key: options.key });\n const base = new RestTransport({\n ...(options.baseUrl ? { baseUrl: options.baseUrl } : {}),\n ...(options.fetch ? { fetch: options.fetch } : {}),\n }).baseUrl;\n const customerBase = (options.customerBase ?? DEFAULT_CUSTOMER_BASE).replace(\n /\\/+$/,\n \"\",\n );\n const request = createPlacesRequest(\n base,\n options.key,\n options.version ?? API_VERSION,\n options.fetch ?? globalThis.fetch,\n );\n const readPlace = (\n id: string,\n read: SignalOptions & { branchId?: string; sessionToken?: string },\n ) => {\n const params = new URLSearchParams();\n if (read.branchId !== undefined) {\n params.set(\"branch_id\", read.branchId);\n }\n if (read.sessionToken !== undefined) {\n params.set(\"session\", read.sessionToken);\n }\n const suffix = params.size > 0 ? `?${params}` : \"\";\n return request<Place>(`/places/${encodeURIComponent(id)}${suffix}`, {\n method: \"GET\",\n ...(read.signal ? { signal: read.signal } : {}),\n });\n };\n const client = {\n async autocomplete(\n query: string,\n sessionToken: string,\n read: SignalOptions = {},\n ): Promise<PlaceSuggestion[]> {\n if (!query.trim()) {\n return [];\n }\n const params = new URLSearchParams({\n q: query.trim(),\n session: sessionToken,\n });\n const result = await request<{ suggestions: PlaceSuggestion[] }>(\n `/places/autocomplete?${params}`,\n { method: \"GET\", ...(read.signal ? { signal: read.signal } : {}) },\n );\n return result.suggestions;\n },\n place(id: string, read: PlaceOptions): Promise<Place> {\n return readPlace(id, read);\n },\n reverse(lat: number, lng: number, read: SignalOptions = {}) {\n const params = new URLSearchParams({\n lat: String(lat),\n lng: String(lng),\n });\n return request<Place>(`/places/reverse?${params}`, {\n method: \"GET\",\n ...(read.signal ? { signal: read.signal } : {}),\n });\n },\n staticMapUrl(lat: number, lng: number, branchId?: string) {\n const params = new URLSearchParams({\n lat: String(lat),\n lng: String(lng),\n });\n if (branchId !== undefined) {\n params.set(\"branch_id\", branchId);\n }\n return `${customerBase}/places/static-map?${params}`;\n },\n zoneCheck(body: ZoneCheckRequest, read: SignalOptions = {}) {\n return request<ZoneCheck>(\"/delivery/zones/check\", {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify(body),\n ...(read.signal ? { signal: read.signal } : {}),\n });\n },\n createAddressSearch(searchOptions: AddressSearchOptions = {}) {\n return createAddressSearch(\n {\n autocomplete: client.autocomplete,\n place: readPlace,\n },\n searchOptions,\n );\n },\n };\n return client;\n}\n\n/**\n * The place lookup, address search and delivery-zone operations returned by createPlaces.\n */\nexport type PlacesClient = ReturnType<typeof createPlaces>;\n"]}
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/places/index.ts"],
4
+ "sourcesContent": ["export { createPlaces } from \"./client\";\nexport type { PlacesClient } from \"./client\";\nexport { PlacesError } from \"./error\";\nexport type * from \"./types\";\n"],
5
+ "mappings": ";AAAA,SAAS,oBAAoB;AAE7B,SAAS,mBAAmB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,40 @@
1
+ // src/places/request.ts
2
+ import { apiError, requestWithRetry } from "../internal/customer-http.js";
3
+ import { PlacesError } from "./error.js";
4
+ function createPlacesRequest(base, key, version, fetcher) {
5
+ return async (path, init = {}) => {
6
+ const response = await requestWithRetry(
7
+ fetcher,
8
+ base + path,
9
+ {
10
+ ...init,
11
+ // Workers reject redirect: "error"; !response.ok below refuses a redirect.
12
+ redirect: "manual",
13
+ headers: {
14
+ Authorization: `Bearer ${key}`,
15
+ "Zappie-Version": version,
16
+ ...init.headers
17
+ }
18
+ },
19
+ "Could not reach the places service"
20
+ );
21
+ if (!response.ok) {
22
+ const value = await apiError(
23
+ response,
24
+ `The places service answered ${response.status}`
25
+ );
26
+ throw new PlacesError(
27
+ response.status,
28
+ value.apiCode,
29
+ value.message,
30
+ value.param,
31
+ value.issues
32
+ );
33
+ }
34
+ return await response.json();
35
+ };
36
+ }
37
+ export {
38
+ createPlacesRequest
39
+ };
40
+ //# sourceMappingURL=request.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/places/request.ts"],
4
+ "sourcesContent": ["import { apiError, requestWithRetry } from \"../internal/customer-http\";\nimport { PlacesError } from \"./error\";\n\nexport type PlacesRequest = <T>(path: string, init?: RequestInit) => Promise<T>;\n\nexport function createPlacesRequest(\n base: string,\n key: string,\n version: string,\n fetcher: typeof fetch,\n): PlacesRequest {\n return async <T>(path: string, init: RequestInit = {}): Promise<T> => {\n const response = await requestWithRetry(\n fetcher,\n base + path,\n {\n ...init,\n // Workers reject redirect: \"error\"; !response.ok below refuses a redirect.\n redirect: \"manual\",\n headers: {\n Authorization: `Bearer ${key}`,\n \"Zappie-Version\": version,\n ...init.headers,\n },\n },\n \"Could not reach the places service\",\n );\n if (!response.ok) {\n const value = await apiError(\n response,\n `The places service answered ${response.status}`,\n );\n throw new PlacesError(\n response.status,\n value.apiCode,\n value.message,\n value.param,\n value.issues,\n );\n }\n return (await response.json()) as T;\n };\n}\n"],
5
+ "mappings": ";AAAA,SAAS,UAAU,wBAAwB;AAC3C,SAAS,mBAAmB;AAIrB,SAAS,oBACd,MACA,KACA,SACA,SACe;AACf,SAAO,OAAU,MAAc,OAAoB,CAAC,MAAkB;AACpE,UAAM,WAAW,MAAM;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,MACP;AAAA,QACE,GAAG;AAAA;AAAA,QAEH,UAAU;AAAA,QACV,SAAS;AAAA,UACP,eAAe,UAAU,GAAG;AAAA,UAC5B,kBAAkB;AAAA,UAClB,GAAG,KAAK;AAAA,QACV;AAAA,MACF;AAAA,MACA;AAAA,IACF;AACA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM;AAAA,QAClB;AAAA,QACA,+BAA+B,SAAS,MAAM;AAAA,MAChD;AACA,YAAM,IAAI;AAAA,QACR,SAAS;AAAA,QACT,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAC9B;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,10 @@
1
+ // src/places/sdk.ts
2
+ import { API_VERSION, RestTransport, ZappieError } from "@zappie/sdk";
3
+ import { validateConfig } from "@zappie/sdk/internal";
4
+ export {
5
+ API_VERSION,
6
+ RestTransport,
7
+ ZappieError,
8
+ validateConfig
9
+ };
10
+ //# sourceMappingURL=sdk.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/places/sdk.ts"],
4
+ "sourcesContent": ["// Isolated places errors import the installed core so their identity is shared.\n// eslint-disable-next-line no-restricted-imports\nexport { API_VERSION, RestTransport, ZappieError } from \"@zappie/sdk\";\n// eslint-disable-next-line no-restricted-imports\nexport { validateConfig } from \"@zappie/sdk/internal\";\n"],
5
+ "mappings": ";AAEA,SAAS,aAAa,eAAe,mBAAmB;AAExD,SAAS,sBAAsB;",
6
+ "names": []
7
+ }