@zappie/sdk 0.1.6 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/README.md +21 -1
- package/dist/cart/branch.d.ts +2 -2
- package/dist/cart/item.d.ts +3 -3
- package/dist/cart/quote.d.ts +3 -3
- package/dist/{client-Bm2cCYea.d.ts → client-iVMHfAFn.d.ts} +2 -2
- package/dist/debug.d.ts +3 -3
- package/dist/debug.js +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +1 -1
- package/dist/integrations/index.d.ts +9 -6
- package/dist/integrations/index.js +1 -0
- package/dist/integrations/index.js.map +2 -2
- package/dist/internal.d.ts +3 -3
- package/dist/{models-Rg5kQUkv.d.ts → models-D__QbqEd.d.ts} +14 -1
- package/dist/persist/catalogue.d.ts +3 -3
- package/dist/react/index.d.ts +3 -3
- package/dist/server/index.d.ts +7 -4
- package/dist/server/storefront-url/build-v1.js +8 -17
- package/dist/server/storefront-url/build-v1.js.map +2 -2
- package/dist/server/storefront-url/build-v2.js +13 -41
- package/dist/server/storefront-url/build-v2.js.map +2 -2
- package/dist/server/storefront-url/canonical.js +36 -0
- package/dist/server/storefront-url/canonical.js.map +7 -0
- package/dist/server/storefront-url/contract.js +2 -2
- package/dist/server/storefront-url/contract.js.map +2 -2
- package/dist/server/storefront-url/params.js +35 -18
- package/dist/server/storefront-url/params.js.map +2 -2
- package/dist/server/storefront-url/parse-v1.js +15 -12
- package/dist/server/storefront-url/parse-v1.js.map +2 -2
- package/dist/server/storefront-url/parse-v2.js +17 -79
- package/dist/server/storefront-url/parse-v2.js.map +2 -2
- package/dist/server/storefront-url/public-id.js +8 -0
- package/dist/server/storefront-url/public-id.js.map +7 -0
- package/dist/server/storefront-url/redirect.js +20 -6
- package/dist/server/storefront-url/redirect.js.map +2 -2
- package/dist/server/storefront-url/sign-in.js +2 -1
- package/dist/server/storefront-url/sign-in.js.map +2 -2
- package/dist/server/storefront-url/types.js +1 -0
- package/dist/server/storefront-url/types.js.map +2 -2
- package/dist/server/storefront-url/url.js +34 -23
- package/dist/server/storefront-url/url.js.map +2 -2
- package/dist/testing/index.d.ts +3 -3
- package/dist/transport/category-page.d.ts +2 -2
- package/dist/transport/category-page.js +6 -2
- package/dist/transport/category-page.js.map +2 -2
- package/dist/transport/presentation.d.ts +7 -0
- package/dist/transport/presentation.js +68 -0
- package/dist/transport/presentation.js.map +7 -0
- package/dist/transport/rest.js +15 -3
- package/dist/transport/rest.js.map +2 -2
- package/dist/transport/search.d.ts +3 -3
- package/dist/transport/search.js +6 -1
- package/dist/transport/search.js.map +2 -2
- package/dist/transport/selected-menu.d.ts +3 -3
- package/dist/transport/selected-menu.js +7 -2
- package/dist/transport/selected-menu.js.map +2 -2
- package/dist/transport/store.d.ts +1 -2
- package/dist/transport/store.js.map +1 -1
- package/dist/{types-CuDvfW9g.d.ts → types-B-iTMrVV.d.ts} +1 -1
- package/dist/url/index.d.ts +4 -1
- package/package.json +1 -1
|
@@ -20,41 +20,52 @@ var inputUrl = (input) => {
|
|
|
20
20
|
const value = typeof input === "string" ? input : input.url;
|
|
21
21
|
return new URL(value, FALLBACK_ORIGIN);
|
|
22
22
|
};
|
|
23
|
+
var isAttributionKey = (key) => /^utm_|^(ref|\w*c..?id|.?braid|li_fat_id)$/.test(key);
|
|
23
24
|
var queryRecord = (params, contract) => {
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
25
|
+
const allowed = contract === "v2" ? STOREFRONT_QUERY_PARAMETERS : STOREFRONT_V1_QUERY_PARAMETERS;
|
|
26
|
+
return Object.fromEntries(
|
|
27
|
+
[...params].filter(
|
|
28
|
+
([key]) => allowed.includes(key) || isAttributionKey(key)
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
};
|
|
32
|
+
var STATE_FIELDS = {
|
|
33
|
+
menu_id: "menuId",
|
|
34
|
+
category_id: "categoryId",
|
|
35
|
+
menu_layout: "menuLayout",
|
|
36
|
+
modal_id: "modalId",
|
|
37
|
+
auth_modal_id: "authModalId",
|
|
38
|
+
payment_id: "paymentId",
|
|
39
|
+
lightbox: "lightbox",
|
|
40
|
+
catalogue_search: "catalogueSearch",
|
|
41
|
+
catalogue_categories: "catalogueCategories"
|
|
32
42
|
};
|
|
33
43
|
var pageState = (url, contract = "v2") => {
|
|
34
44
|
const query = queryRecord(url.searchParams, contract);
|
|
45
|
+
const state = { query };
|
|
46
|
+
for (const [key, field] of Object.entries(STATE_FIELDS)) {
|
|
47
|
+
const value = url.searchParams.get(key);
|
|
48
|
+
if (value !== null) {
|
|
49
|
+
state[field] = value;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
35
52
|
const pickup = url.searchParams.get("pickup");
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
...url.searchParams.has("auth_modal_id") ? { authModalId: url.searchParams.get("auth_modal_id") ?? "" } : {},
|
|
44
|
-
...url.searchParams.has("payment_id") ? { paymentId: url.searchParams.get("payment_id") ?? "" } : {},
|
|
45
|
-
...url.searchParams.has("lightbox") ? { lightbox: url.searchParams.get("lightbox") ?? "" } : {},
|
|
46
|
-
...url.searchParams.has("catalogue_search") ? { catalogueSearch: url.searchParams.get("catalogue_search") ?? "" } : {},
|
|
47
|
-
...url.searchParams.has("catalogue_categories") ? {
|
|
48
|
-
catalogueCategories: url.searchParams.get("catalogue_categories") ?? ""
|
|
49
|
-
} : {}
|
|
50
|
-
};
|
|
53
|
+
if (pickup === "true" || pickup === "false") {
|
|
54
|
+
state.mode = pickup === "true" ? "pickup" : "delivery";
|
|
55
|
+
}
|
|
56
|
+
if (state.categoryId === void 0 && contract === "v2" && url.hash.startsWith("#c-")) {
|
|
57
|
+
state.categoryId = decode(url.hash.slice(3));
|
|
58
|
+
}
|
|
59
|
+
return state;
|
|
51
60
|
};
|
|
52
61
|
export {
|
|
53
62
|
FALLBACK_ORIGIN,
|
|
54
63
|
ITEM_MODAL_PREFIX,
|
|
64
|
+
STATE_FIELDS,
|
|
55
65
|
decode,
|
|
56
66
|
encode,
|
|
57
67
|
inputUrl,
|
|
68
|
+
isAttributionKey,
|
|
58
69
|
pageState,
|
|
59
70
|
queryRecord
|
|
60
71
|
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/server/storefront-url/url.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n STOREFRONT_QUERY_PARAMETERS,\n STOREFRONT_V1_QUERY_PARAMETERS,\n type StorefrontPageState,\n type StorefrontUrlInput,\n} from \"./types\";\n\nexport const FALLBACK_ORIGIN = \"https://storefront.invalid\";\nexport const ITEM_MODAL_PREFIX = \"product_\";\n\nexport const decode = (value: string) => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nexport const encode = (value: string) => encodeURIComponent(value);\n\nexport const inputUrl = (input: StorefrontUrlInput) => {\n if (input instanceof URL) {\n return new URL(input.toString());\n }\n const value = typeof input === \"string\" ? input : input.url;\n return new URL(value, FALLBACK_ORIGIN);\n};\n\nexport const queryRecord = (params: URLSearchParams, contract: \"v1\" | \"v2\") => {\n const
|
|
5
|
-
"mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEA,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAE1B,IAAM,SAAS,CAAC,UAAkB;AACvC,MAAI;AACF,WAAO,mBAAmB,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,SAAS,CAAC,UAAkB,mBAAmB,KAAK;AAE1D,IAAM,WAAW,CAAC,UAA8B;AACrD,MAAI,iBAAiB,KAAK;AACxB,WAAO,IAAI,IAAI,MAAM,SAAS,CAAC;AAAA,EACjC;AACA,QAAM,QAAQ,OAAO,UAAU,WAAW,QAAQ,MAAM;AACxD,SAAO,IAAI,IAAI,OAAO,eAAe;AACvC;AAEO,IAAM,
|
|
4
|
+
"sourcesContent": ["import {\n STOREFRONT_QUERY_PARAMETERS,\n STOREFRONT_V1_QUERY_PARAMETERS,\n type StorefrontPageState,\n type StorefrontUrlInput,\n} from \"./types\";\n\nexport const FALLBACK_ORIGIN = \"https://storefront.invalid\";\nexport const ITEM_MODAL_PREFIX = \"product_\";\n\nexport const decode = (value: string) => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n};\n\nexport const encode = (value: string) => encodeURIComponent(value);\n\nexport const inputUrl = (input: StorefrontUrlInput) => {\n if (input instanceof URL) {\n return new URL(input.toString());\n }\n const value = typeof input === \"string\" ? input : input.url;\n return new URL(value, FALLBACK_ORIGIN);\n};\n\nexport const isAttributionKey = (key: string) =>\n /^utm_|^(ref|\\w*c..?id|.?braid|li_fat_id)$/.test(key);\n\nexport const queryRecord = (params: URLSearchParams, contract: \"v1\" | \"v2\") => {\n const allowed: readonly string[] =\n contract === \"v2\"\n ? STOREFRONT_QUERY_PARAMETERS\n : STOREFRONT_V1_QUERY_PARAMETERS;\n return Object.fromEntries(\n [...params].filter(\n ([key]) => allowed.includes(key) || isAttributionKey(key),\n ),\n );\n};\n\nexport const STATE_FIELDS = {\n menu_id: \"menuId\",\n category_id: \"categoryId\",\n menu_layout: \"menuLayout\",\n modal_id: \"modalId\",\n auth_modal_id: \"authModalId\",\n payment_id: \"paymentId\",\n lightbox: \"lightbox\",\n catalogue_search: \"catalogueSearch\",\n catalogue_categories: \"catalogueCategories\",\n} as const;\n\nexport const pageState = (\n url: URL,\n contract: \"v1\" | \"v2\" = \"v2\",\n): StorefrontPageState => {\n const query = queryRecord(url.searchParams, contract);\n const state: StorefrontPageState = { query };\n for (const [key, field] of Object.entries(STATE_FIELDS)) {\n const value = url.searchParams.get(key);\n if (value !== null) {\n state[field] = value;\n }\n }\n const pickup = url.searchParams.get(\"pickup\");\n if (pickup === \"true\" || pickup === \"false\") {\n state.mode = pickup === \"true\" ? \"pickup\" : \"delivery\";\n }\n if (\n state.categoryId === undefined &&\n contract === \"v2\" &&\n url.hash.startsWith(\"#c-\")\n ) {\n state.categoryId = decode(url.hash.slice(3));\n }\n return state;\n};\n"],
|
|
5
|
+
"mappings": ";AAAA;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AAEA,IAAM,kBAAkB;AACxB,IAAM,oBAAoB;AAE1B,IAAM,SAAS,CAAC,UAAkB;AACvC,MAAI;AACF,WAAO,mBAAmB,KAAK;AAAA,EACjC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,IAAM,SAAS,CAAC,UAAkB,mBAAmB,KAAK;AAE1D,IAAM,WAAW,CAAC,UAA8B;AACrD,MAAI,iBAAiB,KAAK;AACxB,WAAO,IAAI,IAAI,MAAM,SAAS,CAAC;AAAA,EACjC;AACA,QAAM,QAAQ,OAAO,UAAU,WAAW,QAAQ,MAAM;AACxD,SAAO,IAAI,IAAI,OAAO,eAAe;AACvC;AAEO,IAAM,mBAAmB,CAAC,QAC/B,4CAA4C,KAAK,GAAG;AAE/C,IAAM,cAAc,CAAC,QAAyB,aAA0B;AAC7E,QAAM,UACJ,aAAa,OACT,8BACA;AACN,SAAO,OAAO;AAAA,IACZ,CAAC,GAAG,MAAM,EAAE;AAAA,MACV,CAAC,CAAC,GAAG,MAAM,QAAQ,SAAS,GAAG,KAAK,iBAAiB,GAAG;AAAA,IAC1D;AAAA,EACF;AACF;AAEO,IAAM,eAAe;AAAA,EAC1B,SAAS;AAAA,EACT,aAAa;AAAA,EACb,aAAa;AAAA,EACb,UAAU;AAAA,EACV,eAAe;AAAA,EACf,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,sBAAsB;AACxB;AAEO,IAAM,YAAY,CACvB,KACA,WAAwB,SACA;AACxB,QAAM,QAAQ,YAAY,IAAI,cAAc,QAAQ;AACpD,QAAM,QAA6B,EAAE,MAAM;AAC3C,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACvD,UAAM,QAAQ,IAAI,aAAa,IAAI,GAAG;AACtC,QAAI,UAAU,MAAM;AAClB,YAAM,KAAK,IAAI;AAAA,IACjB;AAAA,EACF;AACA,QAAM,SAAS,IAAI,aAAa,IAAI,QAAQ;AAC5C,MAAI,WAAW,UAAU,WAAW,SAAS;AAC3C,UAAM,OAAO,WAAW,SAAS,WAAW;AAAA,EAC9C;AACA,MACE,MAAM,eAAe,UACrB,aAAa,QACb,IAAI,KAAK,WAAW,KAAK,GACzB;AACA,UAAM,aAAa,OAAO,IAAI,KAAK,MAAM,CAAC,CAAC;AAAA,EAC7C;AACA,SAAO;AACT;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/dist/testing/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { T as Transport, e as ZappieErrorCode, S as StorageLike, c as StoreResource, M as MenuResource, d as ZappieEvents, C as Cache } from '../client-
|
|
2
|
-
import { S as Store, a as Menu, F as Formatters } from '../models-
|
|
1
|
+
import { T as Transport, e as ZappieErrorCode, S as StorageLike, c as StoreResource, M as MenuResource, d as ZappieEvents, C as Cache } from '../client-iVMHfAFn.js';
|
|
2
|
+
import { S as Store, a as Menu, F as Formatters } from '../models-D__QbqEd.js';
|
|
3
3
|
export { VERSION } from '../index.js';
|
|
4
|
-
import { d as CartModule, b as CartLineInput } from '../types-
|
|
4
|
+
import { d as CartModule, b as CartLineInput } from '../types-B-iTMrVV.js';
|
|
5
5
|
|
|
6
6
|
/** Store and branch menus supplied to the deterministic mock transport. */
|
|
7
7
|
type MockFixtures = {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as Menu, C as CategoryPage } from '../models-
|
|
1
|
+
import { a as Menu, C as CategoryPage } from '../models-D__QbqEd.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Validates and maps one category page. Only progressive catalogues read
|
|
@@ -12,6 +12,6 @@ declare function categoryPage(raw: Record<string, unknown>, ctx: {
|
|
|
12
12
|
menuId: string;
|
|
13
13
|
categoryId: string;
|
|
14
14
|
cursor?: string;
|
|
15
|
-
}, mapMenu: (value: unknown, branchId: string) => Menu, invalid: () => Error): CategoryPage
|
|
15
|
+
}, mapMenu: (value: unknown, branchId: string) => Menu, invalid: () => Error): Promise<CategoryPage>;
|
|
16
16
|
|
|
17
17
|
export { categoryPage };
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// src/transport/category-page.ts
|
|
2
|
-
function categoryPage(raw, ctx, mapMenu, invalid) {
|
|
3
|
-
const menu =
|
|
2
|
+
async function categoryPage(raw, ctx, mapMenu, invalid) {
|
|
3
|
+
const menu = (await import("./presentation.js")).presentMenu(
|
|
4
|
+
mapMenu(raw, ctx.branchId),
|
|
5
|
+
raw,
|
|
6
|
+
invalid
|
|
7
|
+
);
|
|
4
8
|
if (raw.next_cursor != null && (typeof raw.next_cursor !== "string" || !raw.next_cursor || raw.next_cursor === ctx.cursor) || menu.categories.some((c) => c.id !== ctx.categoryId) || Object.keys(menu.items).some(
|
|
5
9
|
(id) => !menu.categories.some((c) => c.itemIds.includes(id))
|
|
6
10
|
) || !menu.menus?.some(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transport/category-page.ts"],
|
|
4
|
-
"sourcesContent": ["import type { CategoryPage, Menu } from \"../models\";\n\n/**\n * Validates and maps one category page. Only progressive catalogues read\n * pages, so this loads on the first `menu.page()` call and stays out of the\n * core bundle, like the quote client (PRD 03 \u00A74). The mapper and error come\n * in as arguments: importing them would split the core's shared code into a\n * separate chunk, which costs the core more than this module saves.\n */\nexport function categoryPage(\n raw: Record<string, unknown>,\n ctx: {\n branchId: string;\n menuId: string;\n categoryId: string;\n cursor?: string;\n },\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): CategoryPage {\n const menu = mapMenu(raw, ctx.branchId);\n if (\n (raw.next_cursor != null &&\n (typeof raw.next_cursor !== \"string\" ||\n !raw.next_cursor ||\n raw.next_cursor === ctx.cursor)) ||\n menu.categories.some((c) => c.id !== ctx.categoryId) ||\n Object.keys(menu.items).some(\n (id) => !menu.categories.some((c) => c.itemIds.includes(id)),\n ) ||\n !menu.menus?.some(\n (m) => m.id === ctx.menuId && m.categoryIds.includes(ctx.categoryId),\n )\n ) {\n throw invalid();\n }\n return {\n menu: { ...menu, completeness: \"partial\" },\n menuId: ctx.menuId,\n categoryId: ctx.categoryId,\n ...(typeof raw.next_cursor === \"string\" && raw.next_cursor\n ? { nextCursor: raw.next_cursor }\n : {}),\n };\n}\n"],
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["import type { CategoryPage, Menu } from \"../models\";\n\n/**\n * Validates and maps one category page. Only progressive catalogues read\n * pages, so this loads on the first `menu.page()` call and stays out of the\n * core bundle, like the quote client (PRD 03 \u00A74). The mapper and error come\n * in as arguments: importing them would split the core's shared code into a\n * separate chunk, which costs the core more than this module saves.\n */\nexport async function categoryPage(\n raw: Record<string, unknown>,\n ctx: {\n branchId: string;\n menuId: string;\n categoryId: string;\n cursor?: string;\n },\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): Promise<CategoryPage> {\n const menu = (await import(\"./presentation\")).presentMenu(\n mapMenu(raw, ctx.branchId),\n raw,\n invalid,\n );\n if (\n (raw.next_cursor != null &&\n (typeof raw.next_cursor !== \"string\" ||\n !raw.next_cursor ||\n raw.next_cursor === ctx.cursor)) ||\n menu.categories.some((c) => c.id !== ctx.categoryId) ||\n Object.keys(menu.items).some(\n (id) => !menu.categories.some((c) => c.itemIds.includes(id)),\n ) ||\n !menu.menus?.some(\n (m) => m.id === ctx.menuId && m.categoryIds.includes(ctx.categoryId),\n )\n ) {\n throw invalid();\n }\n return {\n menu: { ...menu, completeness: \"partial\" },\n menuId: ctx.menuId,\n categoryId: ctx.categoryId,\n ...(typeof raw.next_cursor === \"string\" && raw.next_cursor\n ? { nextCursor: raw.next_cursor }\n : {}),\n };\n}\n"],
|
|
5
|
+
"mappings": ";AASA,eAAsB,aACpB,KACA,KAMA,SACA,SACuB;AACvB,QAAM,QAAQ,MAAM,OAAO,mBAAgB,GAAG;AAAA,IAC5C,QAAQ,KAAK,IAAI,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,MACG,IAAI,eAAe,SACjB,OAAO,IAAI,gBAAgB,YAC1B,CAAC,IAAI,eACL,IAAI,gBAAgB,IAAI,WAC5B,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,IAAI,UAAU,KACnD,OAAO,KAAK,KAAK,KAAK,EAAE;AAAA,IACtB,CAAC,OAAO,CAAC,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,QAAQ,SAAS,EAAE,CAAC;AAAA,EAC7D,KACA,CAAC,KAAK,OAAO;AAAA,IACX,CAAC,MAAM,EAAE,OAAO,IAAI,UAAU,EAAE,YAAY,SAAS,IAAI,UAAU;AAAA,EACrE,GACA;AACA,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AAAA,IACL,MAAM,EAAE,GAAG,MAAM,cAAc,UAAU;AAAA,IACzC,QAAQ,IAAI;AAAA,IACZ,YAAY,IAAI;AAAA,IAChB,GAAI,OAAO,IAAI,gBAAgB,YAAY,IAAI,cAC3C,EAAE,YAAY,IAAI,YAAY,IAC9B,CAAC;AAAA,EACP;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { a as Menu, S as Store } from '../models-D__QbqEd.js';
|
|
2
|
+
|
|
3
|
+
type Invalid = () => Error;
|
|
4
|
+
declare function presentStore(store: Store, value: unknown, invalid: Invalid): Store;
|
|
5
|
+
declare function presentMenu(menu: Menu, value: unknown, invalid: Invalid): Menu;
|
|
6
|
+
|
|
7
|
+
export { presentMenu, presentStore };
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/transport/presentation.ts
|
|
2
|
+
var object = (value, invalid) => {
|
|
3
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
4
|
+
throw invalid();
|
|
5
|
+
}
|
|
6
|
+
return value;
|
|
7
|
+
};
|
|
8
|
+
var array = (value, invalid) => {
|
|
9
|
+
if (!Array.isArray(value)) {
|
|
10
|
+
throw invalid();
|
|
11
|
+
}
|
|
12
|
+
return value;
|
|
13
|
+
};
|
|
14
|
+
var string = (value, invalid) => {
|
|
15
|
+
if (typeof value !== "string") {
|
|
16
|
+
throw invalid();
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
};
|
|
20
|
+
function presentStore(store, value, invalid) {
|
|
21
|
+
const source = value;
|
|
22
|
+
source.branches.forEach((raw, index) => {
|
|
23
|
+
const branch = store.branches[index];
|
|
24
|
+
if (raw.order_ahead_days !== void 0) {
|
|
25
|
+
if (!Number.isSafeInteger(raw.order_ahead_days) || Number(raw.order_ahead_days) < 0) {
|
|
26
|
+
throw invalid();
|
|
27
|
+
}
|
|
28
|
+
branch.orderAheadDays = raw.order_ahead_days;
|
|
29
|
+
}
|
|
30
|
+
if (raw.promos !== void 0) {
|
|
31
|
+
branch.promos = array(raw.promos, invalid).map((value2) => {
|
|
32
|
+
const promo = object(value2, invalid);
|
|
33
|
+
return {
|
|
34
|
+
id: string(promo.id, invalid),
|
|
35
|
+
name: string(promo.name, invalid),
|
|
36
|
+
description: string(promo.description, invalid)
|
|
37
|
+
};
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
return store;
|
|
42
|
+
}
|
|
43
|
+
function presentMenu(menu, value, invalid) {
|
|
44
|
+
value.menus.forEach((raw, index) => {
|
|
45
|
+
const section = menu.menus[index];
|
|
46
|
+
if (raw.layout !== void 0) {
|
|
47
|
+
if (!["LIST", "GRID", "CARD"].includes(raw.layout)) {
|
|
48
|
+
throw invalid();
|
|
49
|
+
}
|
|
50
|
+
section.layout = raw.layout;
|
|
51
|
+
}
|
|
52
|
+
if (raw.is_active !== void 0) {
|
|
53
|
+
if (typeof raw.is_active !== "boolean") {
|
|
54
|
+
throw invalid();
|
|
55
|
+
}
|
|
56
|
+
section.isActive = raw.is_active;
|
|
57
|
+
}
|
|
58
|
+
if (raw.info_banner_html !== void 0) {
|
|
59
|
+
section.infoBannerHtml = string(raw.info_banner_html, invalid);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
return menu;
|
|
63
|
+
}
|
|
64
|
+
export {
|
|
65
|
+
presentMenu,
|
|
66
|
+
presentStore
|
|
67
|
+
};
|
|
68
|
+
//# sourceMappingURL=presentation.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/transport/presentation.ts"],
|
|
4
|
+
"sourcesContent": ["import type { Menu, Store } from \"../models\";\n\ntype Invalid = () => Error;\ntype Wire = Record<string, unknown>;\n\nconst object = (value: unknown, invalid: Invalid) => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw invalid();\n }\n return value as Wire;\n};\nconst array = (value: unknown, invalid: Invalid) => {\n if (!Array.isArray(value)) {\n throw invalid();\n }\n return value;\n};\nconst string = (value: unknown, invalid: Invalid) => {\n if (typeof value !== \"string\") {\n throw invalid();\n }\n return value;\n};\n\nexport function presentStore(store: Store, value: unknown, invalid: Invalid) {\n const source = value as Wire;\n (source.branches as Wire[]).forEach((raw, index) => {\n const branch = store.branches[index]!;\n if (raw.order_ahead_days !== undefined) {\n if (\n !Number.isSafeInteger(raw.order_ahead_days) ||\n Number(raw.order_ahead_days) < 0\n ) {\n throw invalid();\n }\n branch.orderAheadDays = raw.order_ahead_days as number;\n }\n if (raw.promos !== undefined) {\n branch.promos = array(raw.promos, invalid).map((value) => {\n const promo = object(value, invalid);\n return {\n id: string(promo.id, invalid),\n name: string(promo.name, invalid),\n description: string(promo.description, invalid),\n };\n });\n }\n });\n return store;\n}\n\nexport function presentMenu(menu: Menu, value: unknown, invalid: Invalid) {\n ((value as Wire).menus as Wire[]).forEach((raw, index) => {\n const section = menu.menus![index]!;\n if (raw.layout !== undefined) {\n if (![\"LIST\", \"GRID\", \"CARD\"].includes(raw.layout as string)) {\n throw invalid();\n }\n section.layout = raw.layout as NonNullable<typeof section.layout>;\n }\n if (raw.is_active !== undefined) {\n if (typeof raw.is_active !== \"boolean\") {\n throw invalid();\n }\n section.isActive = raw.is_active;\n }\n if (raw.info_banner_html !== undefined) {\n section.infoBannerHtml = string(raw.info_banner_html, invalid);\n }\n });\n return menu;\n}\n"],
|
|
5
|
+
"mappings": ";AAKA,IAAM,SAAS,CAAC,OAAgB,YAAqB;AACnD,MAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AACT;AACA,IAAM,QAAQ,CAAC,OAAgB,YAAqB;AAClD,MAAI,CAAC,MAAM,QAAQ,KAAK,GAAG;AACzB,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AACT;AACA,IAAM,SAAS,CAAC,OAAgB,YAAqB;AACnD,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AACT;AAEO,SAAS,aAAa,OAAc,OAAgB,SAAkB;AAC3E,QAAM,SAAS;AACf,EAAC,OAAO,SAAoB,QAAQ,CAAC,KAAK,UAAU;AAClD,UAAM,SAAS,MAAM,SAAS,KAAK;AACnC,QAAI,IAAI,qBAAqB,QAAW;AACtC,UACE,CAAC,OAAO,cAAc,IAAI,gBAAgB,KAC1C,OAAO,IAAI,gBAAgB,IAAI,GAC/B;AACA,cAAM,QAAQ;AAAA,MAChB;AACA,aAAO,iBAAiB,IAAI;AAAA,IAC9B;AACA,QAAI,IAAI,WAAW,QAAW;AAC5B,aAAO,SAAS,MAAM,IAAI,QAAQ,OAAO,EAAE,IAAI,CAACA,WAAU;AACxD,cAAM,QAAQ,OAAOA,QAAO,OAAO;AACnC,eAAO;AAAA,UACL,IAAI,OAAO,MAAM,IAAI,OAAO;AAAA,UAC5B,MAAM,OAAO,MAAM,MAAM,OAAO;AAAA,UAChC,aAAa,OAAO,MAAM,aAAa,OAAO;AAAA,QAChD;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEO,SAAS,YAAY,MAAY,OAAgB,SAAkB;AACxE,EAAE,MAAe,MAAiB,QAAQ,CAAC,KAAK,UAAU;AACxD,UAAM,UAAU,KAAK,MAAO,KAAK;AACjC,QAAI,IAAI,WAAW,QAAW;AAC5B,UAAI,CAAC,CAAC,QAAQ,QAAQ,MAAM,EAAE,SAAS,IAAI,MAAgB,GAAG;AAC5D,cAAM,QAAQ;AAAA,MAChB;AACA,cAAQ,SAAS,IAAI;AAAA,IACvB;AACA,QAAI,IAAI,cAAc,QAAW;AAC/B,UAAI,OAAO,IAAI,cAAc,WAAW;AACtC,cAAM,QAAQ;AAAA,MAChB;AACA,cAAQ,WAAW,IAAI;AAAA,IACzB;AACA,QAAI,IAAI,qBAAqB,QAAW;AACtC,cAAQ,iBAAiB,OAAO,IAAI,kBAAkB,OAAO;AAAA,IAC/D;AAAA,EACF,CAAC;AACD,SAAO;AACT;",
|
|
6
|
+
"names": ["value"]
|
|
7
|
+
}
|
package/dist/transport/rest.js
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from "./mappers.js";
|
|
19
19
|
var MAX_RETRY_WAIT_MS = 5e3;
|
|
20
20
|
var wireFulfilment = (value) => value === "dineIn" ? "dine_in" : value;
|
|
21
|
+
var presentationError = () => new ZappieError("server_error", "Invalid storefront presentation");
|
|
21
22
|
var RestTransport = class {
|
|
22
23
|
constructor(opts = {}) {
|
|
23
24
|
const url = new URL(opts.baseUrl ?? "https://api.zappie.ai/storefront/v1");
|
|
@@ -124,11 +125,16 @@ var RestTransport = class {
|
|
|
124
125
|
{ cause }
|
|
125
126
|
);
|
|
126
127
|
});
|
|
128
|
+
const presentation = import("./presentation.js");
|
|
127
129
|
const response = this.request("/store", ctx).then(
|
|
128
130
|
(value) => this.json(value)
|
|
129
131
|
);
|
|
130
|
-
const [{ mapStore }, raw] = await Promise.all([
|
|
131
|
-
|
|
132
|
+
const [{ mapStore }, { presentStore }, raw] = await Promise.all([
|
|
133
|
+
mapper,
|
|
134
|
+
presentation,
|
|
135
|
+
response
|
|
136
|
+
]);
|
|
137
|
+
const store = mapStore(
|
|
132
138
|
raw,
|
|
133
139
|
record,
|
|
134
140
|
text,
|
|
@@ -141,8 +147,10 @@ var RestTransport = class {
|
|
|
141
147
|
isBoolean,
|
|
142
148
|
mapSeo
|
|
143
149
|
);
|
|
150
|
+
return presentStore(store, raw, presentationError);
|
|
144
151
|
}
|
|
145
152
|
async getMenu(ctx) {
|
|
153
|
+
const presentation = import("./presentation.js");
|
|
146
154
|
let cursor;
|
|
147
155
|
const seen = /* @__PURE__ */ new Set();
|
|
148
156
|
let output;
|
|
@@ -172,7 +180,11 @@ var RestTransport = class {
|
|
|
172
180
|
};
|
|
173
181
|
}
|
|
174
182
|
const raw = record(await this.json(response));
|
|
175
|
-
const page =
|
|
183
|
+
const page = (await presentation).presentMenu(
|
|
184
|
+
mapMenu(raw, ctx.branchId),
|
|
185
|
+
raw,
|
|
186
|
+
presentationError
|
|
187
|
+
);
|
|
176
188
|
if (ctx.metadataOnly) {
|
|
177
189
|
if (Object.keys(page.items).length || raw.next_cursor) {
|
|
178
190
|
throw new ZappieError("server_error", "Invalid metadata response");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transport/rest.ts"],
|
|
4
|
-
"sourcesContent": ["import type { QuoteRequest, WireQuote } from \"../cart/types\";\nimport type { MenuFulfilment } from \"../client\";\nimport { ZappieError, wireError } from \"../errors\";\nimport { delay, throwIfAborted } from \"../internal/abort\";\nimport { payloadKey } from \"../internal/digest\";\nimport { money } from \"../money\";\nimport {\n hours,\n isBoolean,\n isString,\n list,\n mapItem,\n mapMenu,\n mapMoney,\n mapSeo,\n opt,\n record,\n text,\n} from \"./mappers\";\nimport type { SelectedMenuRequest } from \"./selected-menu\";\nimport type {\n MenuResponse,\n MenuVersion,\n RequestCtx,\n SearchRequest,\n Transport,\n} from \"./types\";\n/** The longest Retry-After the SDK waits out before surfacing the error instead. */\nconst MAX_RETRY_WAIT_MS = 5_000;\nconst wireFulfilment = (value: MenuFulfilment) =>\n value === \"dineIn\" ? \"dine_in\" : value;\n/** REST connection options. A custom fetch can provide tracing or mock responses. */\nexport type RestTransportOptions = { baseUrl?: string; fetch?: typeof fetch };\n/** REST read adapter for the versioned storefront API. */\nexport class RestTransport implements Transport {\n readonly baseUrl: string;\n private fetcher: typeof fetch;\n constructor(opts: RestTransportOptions = {}) {\n const url = new URL(opts.baseUrl ?? \"https://api.zappie.ai/storefront/v1\");\n if (\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.protocol !== \"https:\" &&\n !(\n url.protocol === \"http:\" &&\n [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname)\n ))\n ) {\n throw new ZappieError(\n \"invalid_request\",\n \"REST baseUrl requires HTTPS, or HTTP on localhost\",\n );\n }\n this.baseUrl = url.href.replace(/\\/$/, \"\");\n // Called as this.fetcher(), a stored global fetch would run with the\n // transport as `this`, which Workers refuses (\"Illegal invocation\").\n this.fetcher =\n opts.fetch ?? ((input, init) => globalThis.fetch(input, init));\n }\n private async request(\n path: string,\n ctx: RequestCtx,\n etag?: string,\n body?: QuoteRequest,\n ): Promise<Response> {\n if (typeof window !== \"undefined\" && ctx.key.startsWith(\"sk_\")) {\n throw new ZappieError(\n \"invalid_request\",\n \"Secret keys cannot be sent from a browser\",\n );\n }\n for (let attempt = 0; ; attempt++) {\n throwIfAborted(ctx.signal);\n let response: Response;\n try {\n response = await this.fetcher(this.baseUrl + path, {\n method: body ? \"POST\" : \"GET\",\n ...(body ? { body: JSON.stringify(body) } : {}),\n // Workers reject redirect: \"error\"; a redirect is still refused below\n // as a non-OK response (a 3xx, or opaqueredirect in browsers).\n redirect: \"manual\",\n headers: {\n ...(body ? { \"Content-Type\": \"application/json\" } : {}),\n ...(ctx.idempotencyKey\n ? { \"Idempotency-Key\": ctx.idempotencyKey }\n : {}),\n Authorization: `Bearer ${ctx.key}`,\n \"Zappie-Version\": ctx.version,\n ...(etag ? { \"If-None-Match\": etag } : {}),\n },\n ...(ctx.signal ? { signal: ctx.signal } : {}),\n });\n } catch (error) {\n throwIfAborted(ctx.signal);\n if (attempt >= 2) {\n throw new ZappieError(\n \"network_error\",\n \"Could not reach the storefront service\",\n { cause: error },\n );\n }\n await delay(100 * 2 ** attempt + Math.random() * 100, ctx.signal);\n continue;\n }\n if (response.ok || response.status === 304) {\n return response;\n }\n const retry = response.headers.get(\"Retry-After\");\n const seconds = retry !== null ? Number(retry) : NaN;\n const wait =\n retry !== null\n ? Number.isFinite(seconds)\n ? Math.max(0, seconds * 1000)\n : Math.max(0, Date.parse(retry) - Date.now())\n : NaN;\n // A longer wait than this is the caller's decision, not a silently stalled read.\n const tooLong = Number.isFinite(wait) && wait > MAX_RETRY_WAIT_MS;\n if (\n attempt < 2 &&\n !tooLong &&\n (response.status === 429 || response.status >= 500)\n ) {\n await response.body?.cancel();\n await delay(\n Number.isFinite(wait)\n ? wait\n : 100 * 2 ** attempt + Math.random() * 100,\n ctx.signal,\n );\n continue;\n }\n const errorBody = await response.json().catch(() => ({}));\n throw wireError(\n errorBody,\n response.status,\n response.headers.get(\"Zappie-Request-Id\") ?? undefined,\n );\n }\n }\n private async json(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch (cause) {\n if (cause instanceof Error && cause.name === \"AbortError\") {\n throw cause;\n }\n throw new ZappieError(\n \"server_error\",\n \"The storefront service returned invalid JSON\",\n { status: response.status, cause },\n );\n }\n }\n async quote(ctx: RequestCtx, body: QuoteRequest): Promise<WireQuote> {\n body = (await import(\"./quote-body\")).quoteBody(body);\n const request = {\n ...ctx,\n idempotencyKey:\n ctx.idempotencyKey ?? (await payloadKey(JSON.stringify(body))),\n };\n const raw = await this.json(\n await this.request(\"/quote\", request, undefined, body),\n );\n // The cart's quote client validates and maps the response.\n return raw as WireQuote;\n }\n async getStore(ctx: RequestCtx) {\n const mapper = import(\"./store\").catch((cause) => {\n throw new ZappieError(\n \"server_error\",\n \"Could not load the storefront store mapper\",\n { cause },\n );\n });\n const response = this.request(\"/store\", ctx).then((value) =>\n this.json(value),\n );\n const [{ mapStore }, raw] = await Promise.all([mapper, response]);\n return mapStore(\n raw,\n record,\n text,\n list,\n hours,\n mapMoney,\n money,\n opt,\n isString,\n isBoolean,\n mapSeo,\n );\n }\n async getMenu(\n ctx: RequestCtx & {\n branchId: string;\n ifNoneMatch?: string;\n metadataOnly?: boolean;\n fulfilment?: MenuFulfilment;\n },\n ): Promise<MenuResponse> {\n let cursor: string | undefined;\n const seen = new Set<string>();\n let output: ReturnType<typeof mapMenu> | undefined;\n let etag: string | undefined;\n do {\n const query = new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.fulfilment\n ? { fulfilment: wireFulfilment(ctx.fulfilment) }\n : {}),\n ...(ctx.metadataOnly ? { metadata_only: \"true\" } : {}),\n ...(cursor ? { cursor } : {}),\n });\n const response = await this.request(\n `/menus?${query}`,\n ctx,\n cursor ? undefined : ctx.ifNoneMatch,\n );\n if (response.status === 304) {\n if (cursor) {\n throw new ZappieError(\n \"server_error\",\n \"Unexpected 304 on a continuation page\",\n );\n }\n return {\n notModified: true,\n ...(response.headers.get(\"ETag\")\n ? { etag: response.headers.get(\"ETag\")! }\n : {}),\n };\n }\n const raw = record(await this.json(response));\n const page = mapMenu(raw, ctx.branchId);\n if (ctx.metadataOnly) {\n if (Object.keys(page.items).length || raw.next_cursor) {\n throw new ZappieError(\"server_error\", \"Invalid metadata response\");\n }\n return { menu: { ...page, completeness: \"partial\" } };\n }\n if (!output) {\n output = page;\n etag = response.headers.get(\"ETag\") ?? undefined;\n } else {\n if (page.version !== output.version) {\n throw new ZappieError(\n \"server_error\",\n \"Menu changed while fetching pages; retry the read\",\n );\n }\n Object.assign(output.items, page.items);\n for (const category of page.categories) {\n const existing = output.categories.find((c) => c.id === category.id);\n if (existing) {\n existing.itemIds = [\n ...new Set([...existing.itemIds, ...category.itemIds]),\n ];\n } else {\n output.categories.push(category);\n }\n }\n for (const section of page.menus ?? []) {\n const existing = output.menus?.find((m) => m.id === section.id);\n if (existing) {\n existing.categoryIds = [\n ...new Set([...existing.categoryIds, ...section.categoryIds]),\n ];\n } else {\n output.menus?.push(section);\n }\n }\n }\n cursor =\n typeof raw.next_cursor === \"string\" && raw.next_cursor\n ? raw.next_cursor\n : undefined;\n if (cursor) {\n if (seen.has(cursor)) {\n throw new ZappieError(\n \"server_error\",\n \"Repeated menu pagination cursor\",\n );\n }\n seen.add(cursor);\n }\n } while (cursor);\n if (output.menus && output.menus.length > 1) {\n output.id = `branch:${ctx.branchId}`;\n output.name = \"Catalogue\";\n delete output.schedule;\n }\n for (const category of output.categories) {\n for (const id of category.itemIds) {\n if (!Object.prototype.hasOwnProperty.call(output.items, id)) {\n throw new ZappieError(\n \"server_error\",\n \"Category refers to a missing item\",\n );\n }\n }\n }\n if (Object.keys(output.items).length > 2000) {\n console.warn(\"Zappie menu contains more than 2,000 items\");\n }\n return { menu: output, ...(etag ? { etag } : {}) };\n }\n async getSelectedMenu(ctx: SelectedMenuRequest) {\n return (await import(\"./selected-menu\")).selectedMenu(\n ctx,\n (path) => this.request(path, ctx, ctx.ifNoneMatch),\n (response) => this.json(response),\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid selected menu\"),\n );\n }\n async search(ctx: SearchRequest) {\n return (await import(\"./search\")).searchPage(\n ctx,\n async (path) => this.json(await this.request(path, ctx)),\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid search page\"),\n );\n }\n async getCategoryPage(\n ctx: RequestCtx & {\n branchId: string;\n menuId: string;\n categoryId: string;\n cursor?: string;\n },\n ) {\n const query = new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.cursor ? { cursor: ctx.cursor } : {}),\n });\n const raw = await this.json(\n await this.request(\n `/menus/${encodeURIComponent(ctx.menuId)}/categories/${encodeURIComponent(ctx.categoryId)}/items?${query}`,\n ctx,\n ),\n );\n // Loaded on first use: only progressive catalogues read pages.\n return (await import(\"./category-page\")).categoryPage(\n record(raw),\n ctx,\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid category page\"),\n );\n }\n async getMenuVersion(\n ctx: RequestCtx & { branchId: string; fulfilment?: MenuFulfilment },\n ): Promise<MenuVersion> {\n const value = record(\n await this.json(\n await this.request(\n `/menus/version?${new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.fulfilment\n ? { fulfilment: wireFulfilment(ctx.fulfilment) }\n : {}),\n })}`,\n ctx,\n ),\n ),\n );\n if (\n typeof value.menu_version !== \"string\" ||\n typeof value.availability_hash !== \"string\"\n ) {\n throw new ZappieError(\"server_error\", \"Invalid menu version response\");\n }\n return {\n version: value.menu_version,\n availabilityHash: value.availability_hash,\n };\n }\n async getItem(ctx: RequestCtx & { branchId: string; itemId: string }) {\n const item = mapItem(\n await this.json(\n await this.request(\n `/items/${encodeURIComponent(ctx.itemId)}?${new URLSearchParams({ branch: ctx.branchId })}`,\n ctx,\n ),\n ),\n );\n if (item.id !== ctx.itemId) {\n throw new ZappieError(\n \"server_error\",\n \"Item response identity does not match the request\",\n );\n }\n return item;\n }\n}\n"],
|
|
5
|
-
"mappings": ";AAEA,SAAS,aAAa,iBAAiB;AACvC,SAAS,OAAO,sBAAsB;AACtC,SAAS,kBAAkB;AAC3B,SAAS,aAAa;AACtB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAUP,IAAM,oBAAoB;AAC1B,IAAM,iBAAiB,CAAC,UACtB,UAAU,WAAW,YAAY;
|
|
4
|
+
"sourcesContent": ["import type { QuoteRequest, WireQuote } from \"../cart/types\";\nimport type { MenuFulfilment } from \"../client\";\nimport { ZappieError, wireError } from \"../errors\";\nimport { delay, throwIfAborted } from \"../internal/abort\";\nimport { payloadKey } from \"../internal/digest\";\nimport { money } from \"../money\";\nimport {\n hours,\n isBoolean,\n isString,\n list,\n mapItem,\n mapMenu,\n mapMoney,\n mapSeo,\n opt,\n record,\n text,\n} from \"./mappers\";\nimport type { SelectedMenuRequest } from \"./selected-menu\";\nimport type {\n MenuResponse,\n MenuVersion,\n RequestCtx,\n SearchRequest,\n Transport,\n} from \"./types\";\n/** The longest Retry-After the SDK waits out before surfacing the error instead. */\nconst MAX_RETRY_WAIT_MS = 5_000;\nconst wireFulfilment = (value: MenuFulfilment) =>\n value === \"dineIn\" ? \"dine_in\" : value;\nconst presentationError = () =>\n new ZappieError(\"server_error\", \"Invalid storefront presentation\");\n/** REST connection options. A custom fetch can provide tracing or mock responses. */\nexport type RestTransportOptions = { baseUrl?: string; fetch?: typeof fetch };\n/** REST read adapter for the versioned storefront API. */\nexport class RestTransport implements Transport {\n readonly baseUrl: string;\n private fetcher: typeof fetch;\n constructor(opts: RestTransportOptions = {}) {\n const url = new URL(opts.baseUrl ?? \"https://api.zappie.ai/storefront/v1\");\n if (\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.protocol !== \"https:\" &&\n !(\n url.protocol === \"http:\" &&\n [\"localhost\", \"127.0.0.1\", \"[::1]\"].includes(url.hostname)\n ))\n ) {\n throw new ZappieError(\n \"invalid_request\",\n \"REST baseUrl requires HTTPS, or HTTP on localhost\",\n );\n }\n this.baseUrl = url.href.replace(/\\/$/, \"\");\n // Called as this.fetcher(), a stored global fetch would run with the\n // transport as `this`, which Workers refuses (\"Illegal invocation\").\n this.fetcher =\n opts.fetch ?? ((input, init) => globalThis.fetch(input, init));\n }\n private async request(\n path: string,\n ctx: RequestCtx,\n etag?: string,\n body?: QuoteRequest,\n ): Promise<Response> {\n if (typeof window !== \"undefined\" && ctx.key.startsWith(\"sk_\")) {\n throw new ZappieError(\n \"invalid_request\",\n \"Secret keys cannot be sent from a browser\",\n );\n }\n for (let attempt = 0; ; attempt++) {\n throwIfAborted(ctx.signal);\n let response: Response;\n try {\n response = await this.fetcher(this.baseUrl + path, {\n method: body ? \"POST\" : \"GET\",\n ...(body ? { body: JSON.stringify(body) } : {}),\n // Workers reject redirect: \"error\"; a redirect is still refused below\n // as a non-OK response (a 3xx, or opaqueredirect in browsers).\n redirect: \"manual\",\n headers: {\n ...(body ? { \"Content-Type\": \"application/json\" } : {}),\n ...(ctx.idempotencyKey\n ? { \"Idempotency-Key\": ctx.idempotencyKey }\n : {}),\n Authorization: `Bearer ${ctx.key}`,\n \"Zappie-Version\": ctx.version,\n ...(etag ? { \"If-None-Match\": etag } : {}),\n },\n ...(ctx.signal ? { signal: ctx.signal } : {}),\n });\n } catch (error) {\n throwIfAborted(ctx.signal);\n if (attempt >= 2) {\n throw new ZappieError(\n \"network_error\",\n \"Could not reach the storefront service\",\n { cause: error },\n );\n }\n await delay(100 * 2 ** attempt + Math.random() * 100, ctx.signal);\n continue;\n }\n if (response.ok || response.status === 304) {\n return response;\n }\n const retry = response.headers.get(\"Retry-After\");\n const seconds = retry !== null ? Number(retry) : NaN;\n const wait =\n retry !== null\n ? Number.isFinite(seconds)\n ? Math.max(0, seconds * 1000)\n : Math.max(0, Date.parse(retry) - Date.now())\n : NaN;\n // A longer wait than this is the caller's decision, not a silently stalled read.\n const tooLong = Number.isFinite(wait) && wait > MAX_RETRY_WAIT_MS;\n if (\n attempt < 2 &&\n !tooLong &&\n (response.status === 429 || response.status >= 500)\n ) {\n await response.body?.cancel();\n await delay(\n Number.isFinite(wait)\n ? wait\n : 100 * 2 ** attempt + Math.random() * 100,\n ctx.signal,\n );\n continue;\n }\n const errorBody = await response.json().catch(() => ({}));\n throw wireError(\n errorBody,\n response.status,\n response.headers.get(\"Zappie-Request-Id\") ?? undefined,\n );\n }\n }\n private async json(response: Response): Promise<unknown> {\n try {\n return await response.json();\n } catch (cause) {\n if (cause instanceof Error && cause.name === \"AbortError\") {\n throw cause;\n }\n throw new ZappieError(\n \"server_error\",\n \"The storefront service returned invalid JSON\",\n { status: response.status, cause },\n );\n }\n }\n async quote(ctx: RequestCtx, body: QuoteRequest): Promise<WireQuote> {\n body = (await import(\"./quote-body\")).quoteBody(body);\n const request = {\n ...ctx,\n idempotencyKey:\n ctx.idempotencyKey ?? (await payloadKey(JSON.stringify(body))),\n };\n const raw = await this.json(\n await this.request(\"/quote\", request, undefined, body),\n );\n // The cart's quote client validates and maps the response.\n return raw as WireQuote;\n }\n async getStore(ctx: RequestCtx) {\n const mapper = import(\"./store\").catch((cause) => {\n throw new ZappieError(\n \"server_error\",\n \"Could not load the storefront store mapper\",\n { cause },\n );\n });\n const presentation = import(\"./presentation\");\n const response = this.request(\"/store\", ctx).then((value) =>\n this.json(value),\n );\n const [{ mapStore }, { presentStore }, raw] = await Promise.all([\n mapper,\n presentation,\n response,\n ]);\n const store = mapStore(\n raw,\n record,\n text,\n list,\n hours,\n mapMoney,\n money,\n opt,\n isString,\n isBoolean,\n mapSeo,\n );\n return presentStore(store, raw, presentationError);\n }\n async getMenu(\n ctx: RequestCtx & {\n branchId: string;\n ifNoneMatch?: string;\n metadataOnly?: boolean;\n fulfilment?: MenuFulfilment;\n },\n ): Promise<MenuResponse> {\n const presentation = import(\"./presentation\");\n let cursor: string | undefined;\n const seen = new Set<string>();\n let output: ReturnType<typeof mapMenu> | undefined;\n let etag: string | undefined;\n do {\n const query = new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.fulfilment\n ? { fulfilment: wireFulfilment(ctx.fulfilment) }\n : {}),\n ...(ctx.metadataOnly ? { metadata_only: \"true\" } : {}),\n ...(cursor ? { cursor } : {}),\n });\n const response = await this.request(\n `/menus?${query}`,\n ctx,\n cursor ? undefined : ctx.ifNoneMatch,\n );\n if (response.status === 304) {\n if (cursor) {\n throw new ZappieError(\n \"server_error\",\n \"Unexpected 304 on a continuation page\",\n );\n }\n return {\n notModified: true,\n ...(response.headers.get(\"ETag\")\n ? { etag: response.headers.get(\"ETag\")! }\n : {}),\n };\n }\n const raw = record(await this.json(response));\n const page = (await presentation).presentMenu(\n mapMenu(raw, ctx.branchId),\n raw,\n presentationError,\n );\n if (ctx.metadataOnly) {\n if (Object.keys(page.items).length || raw.next_cursor) {\n throw new ZappieError(\"server_error\", \"Invalid metadata response\");\n }\n return { menu: { ...page, completeness: \"partial\" } };\n }\n if (!output) {\n output = page;\n etag = response.headers.get(\"ETag\") ?? undefined;\n } else {\n if (page.version !== output.version) {\n throw new ZappieError(\n \"server_error\",\n \"Menu changed while fetching pages; retry the read\",\n );\n }\n Object.assign(output.items, page.items);\n for (const category of page.categories) {\n const existing = output.categories.find((c) => c.id === category.id);\n if (existing) {\n existing.itemIds = [\n ...new Set([...existing.itemIds, ...category.itemIds]),\n ];\n } else {\n output.categories.push(category);\n }\n }\n for (const section of page.menus ?? []) {\n const existing = output.menus?.find((m) => m.id === section.id);\n if (existing) {\n existing.categoryIds = [\n ...new Set([...existing.categoryIds, ...section.categoryIds]),\n ];\n } else {\n output.menus?.push(section);\n }\n }\n }\n cursor =\n typeof raw.next_cursor === \"string\" && raw.next_cursor\n ? raw.next_cursor\n : undefined;\n if (cursor) {\n if (seen.has(cursor)) {\n throw new ZappieError(\n \"server_error\",\n \"Repeated menu pagination cursor\",\n );\n }\n seen.add(cursor);\n }\n } while (cursor);\n if (output.menus && output.menus.length > 1) {\n output.id = `branch:${ctx.branchId}`;\n output.name = \"Catalogue\";\n delete output.schedule;\n }\n for (const category of output.categories) {\n for (const id of category.itemIds) {\n if (!Object.prototype.hasOwnProperty.call(output.items, id)) {\n throw new ZappieError(\n \"server_error\",\n \"Category refers to a missing item\",\n );\n }\n }\n }\n if (Object.keys(output.items).length > 2000) {\n console.warn(\"Zappie menu contains more than 2,000 items\");\n }\n return { menu: output, ...(etag ? { etag } : {}) };\n }\n async getSelectedMenu(ctx: SelectedMenuRequest) {\n return (await import(\"./selected-menu\")).selectedMenu(\n ctx,\n (path) => this.request(path, ctx, ctx.ifNoneMatch),\n (response) => this.json(response),\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid selected menu\"),\n );\n }\n async search(ctx: SearchRequest) {\n return (await import(\"./search\")).searchPage(\n ctx,\n async (path) => this.json(await this.request(path, ctx)),\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid search page\"),\n );\n }\n async getCategoryPage(\n ctx: RequestCtx & {\n branchId: string;\n menuId: string;\n categoryId: string;\n cursor?: string;\n },\n ) {\n const query = new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.cursor ? { cursor: ctx.cursor } : {}),\n });\n const raw = await this.json(\n await this.request(\n `/menus/${encodeURIComponent(ctx.menuId)}/categories/${encodeURIComponent(ctx.categoryId)}/items?${query}`,\n ctx,\n ),\n );\n // Loaded on first use: only progressive catalogues read pages.\n return (await import(\"./category-page\")).categoryPage(\n record(raw),\n ctx,\n mapMenu,\n () => new ZappieError(\"server_error\", \"Invalid category page\"),\n );\n }\n async getMenuVersion(\n ctx: RequestCtx & { branchId: string; fulfilment?: MenuFulfilment },\n ): Promise<MenuVersion> {\n const value = record(\n await this.json(\n await this.request(\n `/menus/version?${new URLSearchParams({\n branch: ctx.branchId,\n ...(ctx.fulfilment\n ? { fulfilment: wireFulfilment(ctx.fulfilment) }\n : {}),\n })}`,\n ctx,\n ),\n ),\n );\n if (\n typeof value.menu_version !== \"string\" ||\n typeof value.availability_hash !== \"string\"\n ) {\n throw new ZappieError(\"server_error\", \"Invalid menu version response\");\n }\n return {\n version: value.menu_version,\n availabilityHash: value.availability_hash,\n };\n }\n async getItem(ctx: RequestCtx & { branchId: string; itemId: string }) {\n const item = mapItem(\n await this.json(\n await this.request(\n `/items/${encodeURIComponent(ctx.itemId)}?${new URLSearchParams({ branch: ctx.branchId })}`,\n ctx,\n ),\n ),\n );\n if (item.id !== ctx.itemId) {\n throw new ZappieError(\n \"server_error\",\n \"Item response identity does not match the request\",\n );\n }\n return item;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as Menu } from '../models-
|
|
2
|
-
import { j as SearchRequest, k as SearchPage } from '../client-
|
|
3
|
-
import '../types-
|
|
1
|
+
import { a as Menu } from '../models-D__QbqEd.js';
|
|
2
|
+
import { j as SearchRequest, k as SearchPage } from '../client-iVMHfAFn.js';
|
|
3
|
+
import '../types-B-iTMrVV.js';
|
|
4
4
|
|
|
5
5
|
/** Loaded only when search is used; request authentication/retries stay in REST. */
|
|
6
6
|
declare function searchPage(ctx: SearchRequest, read: (path: string) => Promise<unknown>, mapMenu: (value: unknown, branchId: string) => Menu, invalid: () => Error): Promise<SearchPage>;
|
package/dist/transport/search.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/transport/search.ts
|
|
2
2
|
async function searchPage(ctx, read, mapMenu, invalid) {
|
|
3
|
+
const presentation = import("./presentation.js");
|
|
3
4
|
ctx.signal?.throwIfAborted();
|
|
4
5
|
const query = new URLSearchParams({
|
|
5
6
|
branch: ctx.branchId,
|
|
@@ -13,7 +14,11 @@ async function searchPage(ctx, read, mapMenu, invalid) {
|
|
|
13
14
|
throw invalid();
|
|
14
15
|
}
|
|
15
16
|
const cursor = raw.next_cursor;
|
|
16
|
-
const menu =
|
|
17
|
+
const menu = (await presentation).presentMenu(
|
|
18
|
+
mapMenu(raw, ctx.branchId),
|
|
19
|
+
raw,
|
|
20
|
+
invalid
|
|
21
|
+
);
|
|
17
22
|
if (Object.keys(menu.items).length > 25 || cursor != null && (typeof cursor !== "string" || !cursor || cursor === ctx.cursor) || Object.keys(menu.items).some(
|
|
18
23
|
(id) => !menu.categories.some((category) => category.itemIds.includes(id))
|
|
19
24
|
) || menu.categories.some(
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transport/search.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Menu } from \"../models\";\nimport type { SearchPage, SearchRequest } from \"./types\";\n\n/** Loaded only when search is used; request authentication/retries stay in REST. */\nexport async function searchPage(\n ctx: SearchRequest,\n read: (path: string) => Promise<unknown>,\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): Promise<SearchPage> {\n ctx.signal?.throwIfAborted();\n const query = new URLSearchParams({\n branch: ctx.branchId,\n query: ctx.query.trim(),\n limit: \"25\",\n ...(ctx.cursor ? { cursor: ctx.cursor } : {}),\n });\n const raw = await read(`/items/search?${query}`);\n ctx.signal?.throwIfAborted();\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw invalid();\n }\n const cursor = (raw as Record<string, unknown>).next_cursor;\n const menu = mapMenu(raw, ctx.branchId);\n if (\n Object.keys(menu.items).length > 25 ||\n (cursor != null &&\n (typeof cursor !== \"string\" || !cursor || cursor === ctx.cursor)) ||\n Object.keys(menu.items).some(\n (id) =>\n !menu.categories.some((category) => category.itemIds.includes(id)),\n ) ||\n menu.categories.some(\n (category) =>\n !menu.menus?.some((source) => source.categoryIds.includes(category.id)),\n )\n ) {\n throw invalid();\n }\n return {\n menu: { ...menu, completeness: \"partial\" },\n ...(typeof cursor === \"string\" ? { nextCursor: cursor } : {}),\n };\n}\n"],
|
|
5
|
-
"mappings": ";AAIA,eAAsB,WACpB,KACA,MACA,SACA,SACqB;AACrB,MAAI,QAAQ,eAAe;AAC3B,QAAM,QAAQ,IAAI,gBAAgB;AAAA,IAChC,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI,MAAM,KAAK;AAAA,IACtB,OAAO;AAAA,IACP,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;AAAA,EAC7C,CAAC;AACD,QAAM,MAAM,MAAM,KAAK,iBAAiB,KAAK,EAAE;AAC/C,MAAI,QAAQ,eAAe;AAC3B,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,QAAQ;AAAA,EAChB;AACA,QAAM,SAAU,IAAgC;AAChD,QAAM,
|
|
4
|
+
"sourcesContent": ["import type { Menu } from \"../models\";\nimport type { SearchPage, SearchRequest } from \"./types\";\n\n/** Loaded only when search is used; request authentication/retries stay in REST. */\nexport async function searchPage(\n ctx: SearchRequest,\n read: (path: string) => Promise<unknown>,\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): Promise<SearchPage> {\n const presentation = import(\"./presentation\");\n ctx.signal?.throwIfAborted();\n const query = new URLSearchParams({\n branch: ctx.branchId,\n query: ctx.query.trim(),\n limit: \"25\",\n ...(ctx.cursor ? { cursor: ctx.cursor } : {}),\n });\n const raw = await read(`/items/search?${query}`);\n ctx.signal?.throwIfAborted();\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n throw invalid();\n }\n const cursor = (raw as Record<string, unknown>).next_cursor;\n const menu = (await presentation).presentMenu(\n mapMenu(raw, ctx.branchId),\n raw,\n invalid,\n );\n if (\n Object.keys(menu.items).length > 25 ||\n (cursor != null &&\n (typeof cursor !== \"string\" || !cursor || cursor === ctx.cursor)) ||\n Object.keys(menu.items).some(\n (id) =>\n !menu.categories.some((category) => category.itemIds.includes(id)),\n ) ||\n menu.categories.some(\n (category) =>\n !menu.menus?.some((source) => source.categoryIds.includes(category.id)),\n )\n ) {\n throw invalid();\n }\n return {\n menu: { ...menu, completeness: \"partial\" },\n ...(typeof cursor === \"string\" ? { nextCursor: cursor } : {}),\n };\n}\n"],
|
|
5
|
+
"mappings": ";AAIA,eAAsB,WACpB,KACA,MACA,SACA,SACqB;AACrB,QAAM,eAAe,OAAO,mBAAgB;AAC5C,MAAI,QAAQ,eAAe;AAC3B,QAAM,QAAQ,IAAI,gBAAgB;AAAA,IAChC,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI,MAAM,KAAK;AAAA,IACtB,OAAO;AAAA,IACP,GAAI,IAAI,SAAS,EAAE,QAAQ,IAAI,OAAO,IAAI,CAAC;AAAA,EAC7C,CAAC;AACD,QAAM,MAAM,MAAM,KAAK,iBAAiB,KAAK,EAAE;AAC/C,MAAI,QAAQ,eAAe;AAC3B,MAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GAAG;AACzD,UAAM,QAAQ;AAAA,EAChB;AACA,QAAM,SAAU,IAAgC;AAChD,QAAM,QAAQ,MAAM,cAAc;AAAA,IAChC,QAAQ,KAAK,IAAI,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,MACE,OAAO,KAAK,KAAK,KAAK,EAAE,SAAS,MAChC,UAAU,SACR,OAAO,WAAW,YAAY,CAAC,UAAU,WAAW,IAAI,WAC3D,OAAO,KAAK,KAAK,KAAK,EAAE;AAAA,IACtB,CAAC,OACC,CAAC,KAAK,WAAW,KAAK,CAAC,aAAa,SAAS,QAAQ,SAAS,EAAE,CAAC;AAAA,EACrE,KACA,KAAK,WAAW;AAAA,IACd,CAAC,aACC,CAAC,KAAK,OAAO,KAAK,CAAC,WAAW,OAAO,YAAY,SAAS,SAAS,EAAE,CAAC;AAAA,EAC1E,GACA;AACA,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AAAA,IACL,MAAM,EAAE,GAAG,MAAM,cAAc,UAAU;AAAA,IACzC,GAAI,OAAO,WAAW,WAAW,EAAE,YAAY,OAAO,IAAI,CAAC;AAAA,EAC7D;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { z as SelectedMenu, h as SelectedMenuRequest, i as SelectedMenuResponse, B as SelectedMenuTransport, D as createSelectedMenuReader, F as selectedMenu, G as selectedMenuKey } from '../client-
|
|
2
|
-
import '../models-
|
|
3
|
-
import '../types-
|
|
1
|
+
export { z as SelectedMenu, h as SelectedMenuRequest, i as SelectedMenuResponse, B as SelectedMenuTransport, D as createSelectedMenuReader, F as selectedMenu, G as selectedMenuKey } from '../client-iVMHfAFn.js';
|
|
2
|
+
import '../models-D__QbqEd.js';
|
|
3
|
+
import '../types-B-iTMrVV.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// src/transport/selected-menu.ts
|
|
2
2
|
async function selectedMenu(ctx, request, json, mapMenu, invalid) {
|
|
3
|
+
const presentation = import("./presentation.js");
|
|
3
4
|
const record = (value) => {
|
|
4
5
|
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
5
6
|
throw invalid();
|
|
@@ -22,8 +23,12 @@ async function selectedMenu(ctx, request, json, mapMenu, invalid) {
|
|
|
22
23
|
}
|
|
23
24
|
const raw = record(await json(response));
|
|
24
25
|
const coverage = record(raw.coverage);
|
|
25
|
-
const menu =
|
|
26
|
-
|
|
26
|
+
const menu = (await presentation).presentMenu(
|
|
27
|
+
mapMenu(raw, ctx.branchId),
|
|
28
|
+
raw,
|
|
29
|
+
invalid
|
|
30
|
+
);
|
|
31
|
+
if (raw.next_cursor || coverage.complete !== true || !Array.isArray(coverage.menu_ids) || coverage.menu_ids.length !== 1 || coverage.menu_ids[0] !== ctx.menuId || menu.menus?.length !== 1 || menu.menus[0]?.id !== ctx.menuId) {
|
|
27
32
|
throw invalid();
|
|
28
33
|
}
|
|
29
34
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/transport/selected-menu.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Zappie } from \"../client\";\nimport type { Menu } from \"../models\";\nimport type { CatalogueScope } from \"../persist/catalogue\";\nimport type { RequestCtx } from \"./types\";\n\n/** Complete for the named source, never complete for the branch. */\nexport type SelectedMenu = {\n menu: Menu & { completeness: \"partial\" };\n coverage: { menuIds: [string]; complete: true };\n};\n/**\n * A source menu with its ETag, or an unchanged response carrying the matching ETag.\n */\nexport type SelectedMenuResponse =\n (SelectedMenu & { etag: string }) | { notModified: true; etag: string };\n/**\n * A branch-scoped source-menu request with order context and an optional conditional ETag.\n */\nexport type SelectedMenuRequest = RequestCtx & {\n branchId: string;\n menuId: string;\n orderContext: CatalogueScope[\"orderContext\"];\n ifNoneMatch?: string;\n};\n/**\n * A transport that reads one complete source menu without claiming branch-wide coverage.\n */\nexport type SelectedMenuTransport = {\n getSelectedMenu(request: SelectedMenuRequest): Promise<SelectedMenuResponse>;\n};\n/** Dependencies are passed by REST to avoid splitting core shared chunks. */\nexport async function selectedMenu(\n ctx: SelectedMenuRequest,\n request: (path: string) => Promise<Response>,\n json: (response: Response) => Promise<unknown>,\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): Promise<SelectedMenuResponse> {\n // Checked here rather than passed in: every argument REST passes costs the\n // core bytes, and the core has none to spare.\n const record = (value: unknown) => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw invalid();\n }\n return value as Record<string, unknown>;\n };\n const query = new URLSearchParams({\n branch: ctx.branchId,\n fulfilment: ctx.orderContext === \"dineIn\" ? \"dine_in\" : ctx.orderContext,\n });\n const response = await request(\n `/menus/${encodeURIComponent(ctx.menuId)}?${query}`,\n );\n const etag = response.headers.get(\"ETag\");\n if (!etag) {\n throw invalid();\n }\n if (response.status === 304) {\n return { notModified: true, etag };\n }\n const raw = record(await json(response));\n const coverage = record(raw.coverage);\n const menu = mapMenu(raw, ctx.branchId);\n if (\n raw.next_cursor ||\n coverage.complete !== true ||\n !Array.isArray(coverage.
|
|
5
|
-
"mappings": ";AA+BA,eAAsB,aACpB,KACA,SACA,MACA,SACA,SAC+B;
|
|
4
|
+
"sourcesContent": ["import type { Zappie } from \"../client\";\nimport type { Menu } from \"../models\";\nimport type { CatalogueScope } from \"../persist/catalogue\";\nimport type { RequestCtx } from \"./types\";\n\n/** Complete for the named source, never complete for the branch. */\nexport type SelectedMenu = {\n menu: Menu & { completeness: \"partial\" };\n coverage: { menuIds: [string]; complete: true };\n};\n/**\n * A source menu with its ETag, or an unchanged response carrying the matching ETag.\n */\nexport type SelectedMenuResponse =\n (SelectedMenu & { etag: string }) | { notModified: true; etag: string };\n/**\n * A branch-scoped source-menu request with order context and an optional conditional ETag.\n */\nexport type SelectedMenuRequest = RequestCtx & {\n branchId: string;\n menuId: string;\n orderContext: CatalogueScope[\"orderContext\"];\n ifNoneMatch?: string;\n};\n/**\n * A transport that reads one complete source menu without claiming branch-wide coverage.\n */\nexport type SelectedMenuTransport = {\n getSelectedMenu(request: SelectedMenuRequest): Promise<SelectedMenuResponse>;\n};\n/** Dependencies are passed by REST to avoid splitting core shared chunks. */\nexport async function selectedMenu(\n ctx: SelectedMenuRequest,\n request: (path: string) => Promise<Response>,\n json: (response: Response) => Promise<unknown>,\n mapMenu: (value: unknown, branchId: string) => Menu,\n invalid: () => Error,\n): Promise<SelectedMenuResponse> {\n const presentation = import(\"./presentation\");\n // Checked here rather than passed in: every argument REST passes costs the\n // core bytes, and the core has none to spare.\n const record = (value: unknown) => {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw invalid();\n }\n return value as Record<string, unknown>;\n };\n const query = new URLSearchParams({\n branch: ctx.branchId,\n fulfilment: ctx.orderContext === \"dineIn\" ? \"dine_in\" : ctx.orderContext,\n });\n const response = await request(\n `/menus/${encodeURIComponent(ctx.menuId)}?${query}`,\n );\n const etag = response.headers.get(\"ETag\");\n if (!etag) {\n throw invalid();\n }\n if (response.status === 304) {\n return { notModified: true, etag };\n }\n const raw = record(await json(response));\n const coverage = record(raw.coverage);\n const menu = (await presentation).presentMenu(\n mapMenu(raw, ctx.branchId),\n raw,\n invalid,\n );\n if (\n raw.next_cursor ||\n coverage.complete !== true ||\n !Array.isArray(coverage.menu_ids) ||\n coverage.menu_ids.length !== 1 ||\n coverage.menu_ids[0] !== ctx.menuId ||\n menu.menus?.length !== 1 ||\n menu.menus[0]?.id !== ctx.menuId\n ) {\n throw invalid();\n }\n return {\n menu: { ...menu, completeness: \"partial\" },\n coverage: { menuIds: [ctx.menuId], complete: true },\n etag,\n };\n}\n/**\n * Build a versioned cache key for a source menu within a store, branch and order context.\n */\nexport function selectedMenuKey(scope: CatalogueScope) {\n return JSON.stringify([\n \"selected-menu:v1\",\n scope.store,\n scope.branchId,\n scope.orderContext,\n scope.menuId,\n ]);\n}\n/** Dedicated lazy resource: deliberately does not call menu.hydrate(). */\nexport function createSelectedMenuReader(client: Zappie) {\n const transport = client._internal.transport;\n return {\n async read(\n scope: CatalogueScope,\n options: { signal?: AbortSignal; ifNoneMatch?: string } = {},\n ) {\n if (!transport.getSelectedMenu) {\n throw new Error(\"Transport does not support selected menus\");\n }\n const response = await transport.getSelectedMenu({\n key: client.config.key,\n version: client.config.version,\n branchId: scope.branchId,\n menuId: scope.menuId,\n orderContext: scope.orderContext,\n ...options,\n });\n options.signal?.throwIfAborted();\n if (!(\"notModified\" in response)) {\n if (\n response.menu.branchId !== scope.branchId ||\n response.coverage.menuIds.length !== 1 ||\n response.coverage.menuIds[0] !== scope.menuId\n ) {\n throw new Error(\"Selected menu belongs to another scope\");\n }\n const key = selectedMenuKey(scope);\n const previous =\n client._internal.cache.snapshot<SelectedMenuResponse>(key).value;\n if (JSON.stringify(previous) !== JSON.stringify(response)) {\n client._internal.cache.set(key, response, response.etag);\n }\n }\n return response;\n },\n };\n}\n"],
|
|
5
|
+
"mappings": ";AA+BA,eAAsB,aACpB,KACA,SACA,MACA,SACA,SAC+B;AAC/B,QAAM,eAAe,OAAO,mBAAgB;AAG5C,QAAM,SAAS,CAAC,UAAmB;AACjC,QAAI,CAAC,SAAS,OAAO,UAAU,YAAY,MAAM,QAAQ,KAAK,GAAG;AAC/D,YAAM,QAAQ;AAAA,IAChB;AACA,WAAO;AAAA,EACT;AACA,QAAM,QAAQ,IAAI,gBAAgB;AAAA,IAChC,QAAQ,IAAI;AAAA,IACZ,YAAY,IAAI,iBAAiB,WAAW,YAAY,IAAI;AAAA,EAC9D,CAAC;AACD,QAAM,WAAW,MAAM;AAAA,IACrB,UAAU,mBAAmB,IAAI,MAAM,CAAC,IAAI,KAAK;AAAA,EACnD;AACA,QAAM,OAAO,SAAS,QAAQ,IAAI,MAAM;AACxC,MAAI,CAAC,MAAM;AACT,UAAM,QAAQ;AAAA,EAChB;AACA,MAAI,SAAS,WAAW,KAAK;AAC3B,WAAO,EAAE,aAAa,MAAM,KAAK;AAAA,EACnC;AACA,QAAM,MAAM,OAAO,MAAM,KAAK,QAAQ,CAAC;AACvC,QAAM,WAAW,OAAO,IAAI,QAAQ;AACpC,QAAM,QAAQ,MAAM,cAAc;AAAA,IAChC,QAAQ,KAAK,IAAI,QAAQ;AAAA,IACzB;AAAA,IACA;AAAA,EACF;AACA,MACE,IAAI,eACJ,SAAS,aAAa,QACtB,CAAC,MAAM,QAAQ,SAAS,QAAQ,KAChC,SAAS,SAAS,WAAW,KAC7B,SAAS,SAAS,CAAC,MAAM,IAAI,UAC7B,KAAK,OAAO,WAAW,KACvB,KAAK,MAAM,CAAC,GAAG,OAAO,IAAI,QAC1B;AACA,UAAM,QAAQ;AAAA,EAChB;AACA,SAAO;AAAA,IACL,MAAM,EAAE,GAAG,MAAM,cAAc,UAAU;AAAA,IACzC,UAAU,EAAE,SAAS,CAAC,IAAI,MAAM,GAAG,UAAU,KAAK;AAAA,IAClD;AAAA,EACF;AACF;AAIO,SAAS,gBAAgB,OAAuB;AACrD,SAAO,KAAK,UAAU;AAAA,IACpB;AAAA,IACA,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,IACN,MAAM;AAAA,EACR,CAAC;AACH;AAEO,SAAS,yBAAyB,QAAgB;AACvD,QAAM,YAAY,OAAO,UAAU;AACnC,SAAO;AAAA,IACL,MAAM,KACJ,OACA,UAA0D,CAAC,GAC3D;AACA,UAAI,CAAC,UAAU,iBAAiB;AAC9B,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,YAAM,WAAW,MAAM,UAAU,gBAAgB;AAAA,QAC/C,KAAK,OAAO,OAAO;AAAA,QACnB,SAAS,OAAO,OAAO;AAAA,QACvB,UAAU,MAAM;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,cAAc,MAAM;AAAA,QACpB,GAAG;AAAA,MACL,CAAC;AACD,cAAQ,QAAQ,eAAe;AAC/B,UAAI,EAAE,iBAAiB,WAAW;AAChC,YACE,SAAS,KAAK,aAAa,MAAM,YACjC,SAAS,SAAS,QAAQ,WAAW,KACrC,SAAS,SAAS,QAAQ,CAAC,MAAM,MAAM,QACvC;AACA,gBAAM,IAAI,MAAM,wCAAwC;AAAA,QAC1D;AACA,cAAM,MAAM,gBAAgB,KAAK;AACjC,cAAM,WACJ,OAAO,UAAU,MAAM,SAA+B,GAAG,EAAE;AAC7D,YAAI,KAAK,UAAU,QAAQ,MAAM,KAAK,UAAU,QAAQ,GAAG;AACzD,iBAAO,UAAU,MAAM,IAAI,KAAK,UAAU,SAAS,IAAI;AAAA,QACzD;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { i as OpeningTime, M as Money, d as Currency, S as Store } from '../models-
|
|
1
|
+
import { i as OpeningTime, M as Money, d as Currency, S as Store } from '../models-D__QbqEd.js';
|
|
2
2
|
|
|
3
3
|
type Guard<T> = (value: unknown) => value is T;
|
|
4
4
|
type Optional = <K extends string, T>(key: K, value: unknown, is: Guard<T>) => {
|
|
5
5
|
[P in K]?: T;
|
|
6
6
|
};
|
|
7
|
-
/** Core parsing helpers are passed in, in this order, so this lazy entry has no runtime import. */
|
|
8
7
|
declare function mapStore(value: unknown, record: (value: unknown) => Record<string, unknown>, text: (value: unknown) => string, list: (value: unknown) => unknown[], hours: (value: unknown) => OpeningTime[], mapMoney: (value: unknown) => Money, money: (amountMinor: number, currency: Currency) => Money, opt: Optional, isString: Guard<string>, isBoolean: Guard<boolean>, mapSeo: (value: unknown) => NonNullable<Store["seo"]>): Store;
|
|
9
8
|
|
|
10
9
|
export { mapStore };
|