@zappie/verify 0.1.2 → 0.1.5
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 +20 -0
- package/dist/chunk-JYFSFOIS.js +2795 -0
- package/dist/chunk-JYFSFOIS.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +306 -2371
- package/dist/index.js.map +1 -1
- package/dist/quote-body-NAFPZOGR.js +24 -0
- package/dist/quote-body-NAFPZOGR.js.map +1 -0
- package/dist/{quote-client-6XJJHITL.js → quote-client-3NC5KSBE.js} +78 -5
- package/dist/quote-client-3NC5KSBE.js.map +1 -0
- package/dist/{selected-menu-3GCAICBQ.js → selected-menu-5AIX7JHU.js} +2 -2
- package/dist/selected-menu-5AIX7JHU.js.map +1 -0
- package/dist/{store-KIO5RCZO.js → store-AOU2FRUX.js} +20 -9
- package/dist/store-AOU2FRUX.js.map +1 -0
- package/package.json +2 -2
- package/schema/verify-report.v1.json +7 -3
- package/dist/chunk-WUWUDCYO.js +0 -485
- package/dist/chunk-WUWUDCYO.js.map +0 -1
- package/dist/quote-client-6XJJHITL.js.map +0 -1
- package/dist/selected-menu-3GCAICBQ.js.map +0 -1
- package/dist/store-KIO5RCZO.js.map +0 -1
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// ../sdk/src/transport/quote-body.ts
|
|
2
|
+
function quoteBody(body) {
|
|
3
|
+
const f = body.fulfilment;
|
|
4
|
+
if (!f) {
|
|
5
|
+
return body;
|
|
6
|
+
}
|
|
7
|
+
const { table: _table, address, ...fulfilment } = f;
|
|
8
|
+
if (!address) {
|
|
9
|
+
return { ...body, fulfilment };
|
|
10
|
+
}
|
|
11
|
+
const { line2: _line2, instructions, ...rest } = address;
|
|
12
|
+
return {
|
|
13
|
+
...body,
|
|
14
|
+
fulfilment: {
|
|
15
|
+
...fulfilment,
|
|
16
|
+
...fulfilment.instructions === void 0 && instructions !== void 0 ? { instructions } : {},
|
|
17
|
+
address: rest
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
quoteBody
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=quote-body-NAFPZOGR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/transport/quote-body.ts"],"sourcesContent":["import type { QuoteRequest } from \"../cart/types\";\n\n// Keep legacy fields in saved carts and host requests. REST accepts only these address fields.\nexport function quoteBody(body: QuoteRequest): QuoteRequest {\n const f = body.fulfilment;\n if (!f) {\n return body;\n }\n const { table: _table, address, ...fulfilment } = f;\n if (!address) {\n return { ...body, fulfilment };\n }\n const { line2: _line2, instructions, ...rest } = address;\n return {\n ...body,\n fulfilment: {\n ...fulfilment,\n ...(fulfilment.instructions === undefined && instructions !== undefined\n ? { instructions }\n : {}),\n address: rest,\n },\n };\n}\n"],"mappings":";AAGO,SAAS,UAAU,MAAkC;AAC1D,QAAM,IAAI,KAAK;AACf,MAAI,CAAC,GAAG;AACN,WAAO;AAAA,EACT;AACA,QAAM,EAAE,OAAO,QAAQ,SAAS,GAAG,WAAW,IAAI;AAClD,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,GAAG,MAAM,WAAW;AAAA,EAC/B;AACA,QAAM,EAAE,OAAO,QAAQ,cAAc,GAAG,KAAK,IAAI;AACjD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,YAAY;AAAA,MACV,GAAG;AAAA,MACH,GAAI,WAAW,iBAAiB,UAAa,iBAAiB,SAC1D,EAAE,aAAa,IACf,CAAC;AAAA,MACL,SAAS;AAAA,IACX;AAAA,EACF;AACF;","names":[]}
|
|
@@ -4,8 +4,10 @@ import {
|
|
|
4
4
|
money,
|
|
5
5
|
payloadKey,
|
|
6
6
|
record,
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
requestWithRetry,
|
|
8
|
+
sumMoney,
|
|
9
|
+
wireError
|
|
10
|
+
} from "./chunk-JYFSFOIS.js";
|
|
9
11
|
|
|
10
12
|
// ../sdk/src/cart/quote-response.ts
|
|
11
13
|
function fail() {
|
|
@@ -30,6 +32,7 @@ function fix(value) {
|
|
|
30
32
|
case "accept_price":
|
|
31
33
|
case "remove_promo":
|
|
32
34
|
case "change_address":
|
|
35
|
+
case "choose_region":
|
|
33
36
|
return { action: v.action };
|
|
34
37
|
case "choose_option":
|
|
35
38
|
case "choose_other_option":
|
|
@@ -107,12 +110,29 @@ function mapQuote(value, branchId) {
|
|
|
107
110
|
return fail();
|
|
108
111
|
}
|
|
109
112
|
const deliveryCharges = charges.filter((c) => c.code === "delivery");
|
|
113
|
+
const integer = (value2) => {
|
|
114
|
+
if (!Number.isSafeInteger(value2) || Number(value2) < 0) {
|
|
115
|
+
return fail();
|
|
116
|
+
}
|
|
117
|
+
return value2;
|
|
118
|
+
};
|
|
119
|
+
const fulfilment = v.fulfilment === void 0 ? void 0 : record(v.fulfilment);
|
|
120
|
+
if (v.menu_version_stale !== void 0 && typeof v.menu_version_stale !== "boolean") {
|
|
121
|
+
return fail();
|
|
122
|
+
}
|
|
110
123
|
const lines = list(v.lines).map((raw) => {
|
|
111
124
|
const l = record(raw);
|
|
112
125
|
if ((l.unit_price == null || l.line_total == null) && v.lines_unpriced !== true) {
|
|
113
126
|
return fail();
|
|
114
127
|
}
|
|
115
128
|
return {
|
|
129
|
+
...l.item_id !== void 0 ? { itemId: text(l.item_id) } : {},
|
|
130
|
+
...l.name !== void 0 ? { name: text(l.name) } : {},
|
|
131
|
+
...l.quantity !== void 0 ? { quantity: integer(l.quantity) } : {},
|
|
132
|
+
...l.status !== void 0 ? { status: text(l.status) } : {},
|
|
133
|
+
...l.options_total !== void 0 ? {
|
|
134
|
+
optionsTotal: l.options_total === null ? null : amount(l.options_total)
|
|
135
|
+
} : {},
|
|
116
136
|
lineId: text(l.line_id),
|
|
117
137
|
unitPrice: l.unit_price == null ? null : amount(l.unit_price),
|
|
118
138
|
total: l.line_total == null ? null : amount(l.line_total)
|
|
@@ -125,6 +145,15 @@ function mapQuote(value, branchId) {
|
|
|
125
145
|
return fail();
|
|
126
146
|
}
|
|
127
147
|
return {
|
|
148
|
+
...v.menu_version_stale !== void 0 ? { menuVersionStale: v.menu_version_stale } : {},
|
|
149
|
+
...fulfilment ? {
|
|
150
|
+
fulfilment: {
|
|
151
|
+
type: text(fulfilment.type),
|
|
152
|
+
scheduledFor: fulfilment.scheduled_for === null ? null : text(fulfilment.scheduled_for),
|
|
153
|
+
...fulfilment.eta_minutes !== void 0 ? { etaMinutes: list(fulfilment.eta_minutes).map(integer) } : {},
|
|
154
|
+
...fulfilment.delivery_region_id !== void 0 ? { deliveryRegionId: text(fulfilment.delivery_region_id) } : {}
|
|
155
|
+
}
|
|
156
|
+
} : {},
|
|
128
157
|
lines,
|
|
129
158
|
...v.lines_unpriced === true ? { linesUnpriced: true } : {},
|
|
130
159
|
subtotal,
|
|
@@ -179,7 +208,51 @@ function mapQuote(value, branchId) {
|
|
|
179
208
|
}
|
|
180
209
|
|
|
181
210
|
// ../sdk/src/cart/quote-client.ts
|
|
182
|
-
function
|
|
211
|
+
function customerQuoteBody(body) {
|
|
212
|
+
const value = body.fulfilment;
|
|
213
|
+
if (!value) {
|
|
214
|
+
return body;
|
|
215
|
+
}
|
|
216
|
+
const { table: _table, address, ...fulfilment } = value;
|
|
217
|
+
if (!address) {
|
|
218
|
+
return { ...body, fulfilment };
|
|
219
|
+
}
|
|
220
|
+
const { line2: _line2, instructions, ...rest } = address;
|
|
221
|
+
return {
|
|
222
|
+
...body,
|
|
223
|
+
fulfilment: {
|
|
224
|
+
...fulfilment,
|
|
225
|
+
...fulfilment.instructions === void 0 && instructions !== void 0 ? { instructions } : {},
|
|
226
|
+
address: rest
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function createQuoteClient(transport, context, options = {}) {
|
|
231
|
+
const customerBase = options.customerBase?.replace(/\/+$/, "");
|
|
232
|
+
const signedQuote = async (body, signal, idempotencyKey) => {
|
|
233
|
+
const response = await requestWithRetry(
|
|
234
|
+
options.fetch ?? globalThis.fetch,
|
|
235
|
+
`${customerBase}/quote`,
|
|
236
|
+
{
|
|
237
|
+
method: "POST",
|
|
238
|
+
headers: {
|
|
239
|
+
"Content-Type": "application/json",
|
|
240
|
+
"Idempotency-Key": idempotencyKey
|
|
241
|
+
},
|
|
242
|
+
body: JSON.stringify(customerQuoteBody(body)),
|
|
243
|
+
signal
|
|
244
|
+
},
|
|
245
|
+
"Could not reach the storefront quote service"
|
|
246
|
+
);
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
throw wireError(
|
|
249
|
+
await response.json().catch(() => ({})),
|
|
250
|
+
response.status,
|
|
251
|
+
response.headers.get("Zappie-Request-Id") ?? void 0
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
return await response.json();
|
|
255
|
+
};
|
|
183
256
|
let controller;
|
|
184
257
|
let sequence = 0;
|
|
185
258
|
let cached;
|
|
@@ -207,7 +280,7 @@ function createQuoteClient(transport, context) {
|
|
|
207
280
|
const promise = (async () => {
|
|
208
281
|
const idempotencyKey = await payloadKey(key);
|
|
209
282
|
signal.throwIfAborted();
|
|
210
|
-
const raw = await transport.quote(
|
|
283
|
+
const raw = customerBase ? await signedQuote(body, signal, idempotencyKey) : await transport.quote(
|
|
211
284
|
{ ...context(), signal, idempotencyKey },
|
|
212
285
|
body
|
|
213
286
|
);
|
|
@@ -250,4 +323,4 @@ function createQuoteClient(transport, context) {
|
|
|
250
323
|
export {
|
|
251
324
|
createQuoteClient
|
|
252
325
|
};
|
|
253
|
-
//# sourceMappingURL=quote-client-
|
|
326
|
+
//# sourceMappingURL=quote-client-3NC5KSBE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/cart/quote-response.ts","../../sdk/src/cart/quote-client.ts"],"sourcesContent":["// Quote responses load lazily with the quote client, outside the synchronous core.\nimport { ZappieError } from \"../errors\";\nimport { sumMoney } from \"../internal/money-math\";\nimport { money } from \"../money\";\nimport { mapMoney, record } from \"../transport/mappers\";\nimport type { CartFix, CartFulfilment, CartIssue, Quote } from \"./types\";\nfunction fail(): never {\n throw new ZappieError(\"server_error\", \"Invalid quote response\");\n}\nfunction text(value: unknown): string {\n if (typeof value !== \"string\") {\n return fail();\n }\n return value;\n}\nfunction list(value: unknown): unknown[] {\n if (!Array.isArray(value)) {\n return fail();\n }\n return value;\n}\n/** A fix newer than this SDK is dropped (undefined); a malformed known fix still fails. */\nfunction fix(value: unknown): CartFix | undefined {\n const v = record(value);\n switch (v.action) {\n case \"remove_line\":\n case \"accept_price\":\n case \"remove_promo\":\n case \"change_address\":\n case \"choose_region\":\n return { action: v.action };\n case \"choose_option\":\n case \"choose_other_option\":\n return { action: v.action, groupId: text(v.group_id) };\n case \"set_quantity\": {\n if (\n !Number.isInteger(v.quantity) ||\n Number(v.quantity) < 1 ||\n Number(v.quantity) > 99\n ) {\n return fail();\n }\n return { action: v.action, quantity: v.quantity as number };\n }\n case \"schedule\":\n return {\n action: v.action,\n ...(v.next_open_at ? { nextOpenAt: text(v.next_open_at) } : {}),\n ...(v.slots ? { slots: list(v.slots).map(text) } : {}),\n };\n case \"switch_fulfilment\": {\n const types = list(v.types)\n .map(text)\n .filter((t) => [\"pickup\", \"delivery\", \"dine_in\"].includes(t));\n return types.length\n ? { action: v.action, types: types as CartFulfilment[\"type\"][] }\n : undefined;\n }\n default:\n return undefined;\n }\n}\nconst codes = [\n \"item_unavailable\",\n \"item_not_found\",\n \"option_unavailable\",\n \"option_required\",\n \"option_limit\",\n \"quantity_limit\",\n \"price_changed\",\n \"branch_closed\",\n \"fulfilment_unavailable\",\n \"outside_delivery_zone\",\n \"delivery_region_required\",\n \"schedule_invalid\",\n \"promo_invalid\",\n \"promo_min_spend\",\n \"min_order\",\n \"menu_version_stale\",\n];\nexport function mapQuote(value: unknown, branchId: string): Quote {\n const v = record(value);\n if (\n v.branch_id !== branchId ||\n !Number.isFinite(Date.parse(text(v.expires_at)))\n ) {\n return fail();\n }\n const subtotal = mapMoney(v.subtotal);\n const checkout = record(v.checkout);\n if (\n typeof v.can_checkout !== \"boolean\" ||\n typeof checkout.ready !== \"boolean\" ||\n (checkout.reason !== undefined &&\n checkout.reason !== \"issues\" &&\n checkout.reason !== \"customer_required\")\n ) {\n return fail();\n }\n const amount = (raw: unknown) => {\n const result = mapMoney(raw);\n if (result.currency !== subtotal.currency) {\n return fail();\n }\n return result;\n };\n const charge = (raw: unknown) => {\n const c = record(raw);\n return {\n code: text(c.code),\n label: text(c.label),\n amount: amount(c.amount),\n };\n };\n const charges = list(v.charges).map(charge);\n const discounts = list(v.discounts).map(charge);\n const total = amount(v.total);\n if (\n sumMoney(\n [...charges, ...discounts].map((c) => c.amount),\n subtotal,\n ).amountMinor !== total.amountMinor\n ) {\n return fail();\n }\n const deliveryCharges = charges.filter((c) => c.code === \"delivery\");\n const integer = (value: unknown) => {\n if (!Number.isSafeInteger(value) || Number(value) < 0) {\n return fail();\n }\n return value as number;\n };\n const fulfilment =\n v.fulfilment === undefined ? undefined : record(v.fulfilment);\n if (\n v.menu_version_stale !== undefined &&\n typeof v.menu_version_stale !== \"boolean\"\n ) {\n return fail();\n }\n const lines = list(v.lines).map((raw) => {\n const l = record(raw);\n if (\n (l.unit_price == null || l.line_total == null) &&\n v.lines_unpriced !== true\n ) {\n return fail();\n }\n return {\n ...(l.item_id !== undefined ? { itemId: text(l.item_id) } : {}),\n ...(l.name !== undefined ? { name: text(l.name) } : {}),\n ...(l.quantity !== undefined ? { quantity: integer(l.quantity) } : {}),\n ...(l.status !== undefined ? { status: text(l.status) } : {}),\n ...(l.options_total !== undefined\n ? {\n optionsTotal:\n l.options_total === null ? null : amount(l.options_total),\n }\n : {}),\n lineId: text(l.line_id),\n unitPrice: l.unit_price == null ? null : amount(l.unit_price),\n total: l.line_total == null ? null : amount(l.line_total),\n };\n });\n if (\n v.lines_unpriced !== true &&\n sumMoney(\n lines.map((line) => line.total!),\n money(0, subtotal.currency),\n ).amountMinor !== subtotal.amountMinor\n ) {\n return fail();\n }\n return {\n ...(v.menu_version_stale !== undefined\n ? { menuVersionStale: v.menu_version_stale as boolean }\n : {}),\n ...(fulfilment\n ? {\n fulfilment: {\n type: text(fulfilment.type),\n scheduledFor:\n fulfilment.scheduled_for === null\n ? null\n : text(fulfilment.scheduled_for),\n ...(fulfilment.eta_minutes !== undefined\n ? { etaMinutes: list(fulfilment.eta_minutes).map(integer) }\n : {}),\n ...(fulfilment.delivery_region_id !== undefined\n ? { deliveryRegionId: text(fulfilment.delivery_region_id) }\n : {}),\n },\n }\n : {}),\n lines,\n ...(v.lines_unpriced === true ? { linesUnpriced: true } : {}),\n subtotal,\n total,\n fees: charges.filter((c) => c.code !== \"delivery\"),\n discounts,\n ...(deliveryCharges.length\n ? {\n delivery: sumMoney(\n deliveryCharges.map((c) => c.amount),\n money(0, subtotal.currency),\n ),\n }\n : {}),\n menuVersion: text(v.menu_version),\n expiresAt: text(v.expires_at),\n issues: list(v.issues).flatMap((raw): CartIssue[] => {\n const i = record(raw);\n const code = text(i.code);\n const severity = text(i.severity);\n const known =\n codes.includes(code) &&\n [\"blocking\", \"warning\", \"info\"].includes(severity);\n const fixes = list(i.fixes)\n .map(fix)\n .filter((f): f is CartFix => f !== undefined);\n const lineId = i.line_id ? text(i.line_id) : undefined;\n if (!known && (severity === \"warning\" || severity === \"info\")) {\n console.warn(\n `Zappie quote issue \"${code}\" is newer than this SDK and was skipped`,\n );\n return [];\n }\n // A blocking (or unknown-severity) issue newer than the SDK keeps checkout blocked.\n return [\n {\n code: known ? (code as CartIssue[\"code\"]) : \"item_unavailable\",\n severity: known ? (severity as CartIssue[\"severity\"]) : \"blocking\",\n message: text(i.message),\n source: \"quote\",\n ...(lineId ? { lineId } : {}),\n ...(i.group_id ? { groupId: text(i.group_id) } : {}),\n ...(i.data || !known\n ? {\n data: {\n ...(i.data ? record(i.data) : {}),\n ...(known ? {} : { code }),\n },\n }\n : {}),\n fixes:\n !known && !fixes.length && lineId\n ? [{ action: \"remove_line\" }]\n : fixes,\n },\n ];\n }),\n canCheckout: v.can_checkout,\n checkout: {\n ready: checkout.ready,\n ...(checkout.reason !== undefined ? { reason: checkout.reason } : {}),\n },\n };\n}\n","import { wireError, ZappieError } from \"../errors\";\nimport { requestWithRetry } from \"../internal/customer-http\";\nimport { payloadKey } from \"../internal/digest\";\nimport type { RequestCtx, Transport } from \"../transport/types\";\nimport { mapQuote } from \"./quote-response\";\nimport type { Quote, QuoteRequest, WireQuote } from \"./types\";\ntype QuoteClientOptions = {\n customerBase?: string | undefined;\n fetch?: typeof fetch | undefined;\n};\nfunction customerQuoteBody(body: QuoteRequest): QuoteRequest {\n const value = body.fulfilment;\n if (!value) {\n return body;\n }\n const { table: _table, address, ...fulfilment } = value;\n if (!address) {\n return { ...body, fulfilment };\n }\n const { line2: _line2, instructions, ...rest } = address;\n return {\n ...body,\n fulfilment: {\n ...fulfilment,\n ...(fulfilment.instructions === undefined && instructions !== undefined\n ? { instructions }\n : {}),\n address: rest,\n },\n };\n}\nexport function createQuoteClient(\n transport: Transport,\n context: () => RequestCtx,\n options: QuoteClientOptions = {},\n) {\n const customerBase = options.customerBase?.replace(/\\/+$/, \"\");\n const signedQuote = async (\n body: QuoteRequest,\n signal: AbortSignal,\n idempotencyKey: string,\n ): Promise<WireQuote> => {\n const response = await requestWithRetry(\n options.fetch ?? globalThis.fetch,\n `${customerBase}/quote`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n \"Idempotency-Key\": idempotencyKey,\n },\n body: JSON.stringify(customerQuoteBody(body)),\n signal,\n },\n \"Could not reach the storefront quote service\",\n );\n if (!response.ok) {\n throw wireError(\n await response.json().catch(() => ({})),\n response.status,\n response.headers.get(\"Zappie-Request-Id\") ?? undefined,\n );\n }\n return (await response.json()) as WireQuote;\n };\n let controller: AbortController | undefined;\n let sequence = 0;\n let cached: { key: string; quote: Quote } | undefined;\n let flight: { key: string; promise: Promise<Quote> } | undefined;\n const cancel = () => {\n sequence++;\n controller?.abort();\n flight = undefined;\n };\n return {\n cancel,\n async get(\n body: QuoteRequest,\n force: boolean,\n apply: (quote: Quote) => void,\n ): Promise<Quote> {\n const key = JSON.stringify(body);\n if (\n !force &&\n cached?.key === key &&\n Date.parse(cached.quote.expiresAt) > Date.now()\n ) {\n apply(cached.quote);\n return cached.quote;\n }\n if (!force && flight?.key === key) {\n return flight.promise;\n }\n cancel();\n const seq = sequence;\n controller = new AbortController();\n const signal = controller.signal;\n const promise = (async () => {\n const idempotencyKey = await payloadKey(key);\n signal.throwIfAborted();\n const raw = customerBase\n ? await signedQuote(body, signal, idempotencyKey)\n : await transport.quote(\n { ...context(), signal, idempotencyKey },\n body,\n );\n signal.throwIfAborted();\n const quote = mapQuote(raw, body.branch_id);\n const ids = new Set(quote.lines.map((line) => line.lineId));\n if (\n ids.size !== quote.lines.length ||\n quote.lines.length !== body.lines.length ||\n body.lines.some((line) => !ids.has(line.line_id))\n ) {\n throw new ZappieError(\n \"server_error\",\n \"Quote line identities do not match the cart\",\n );\n }\n if (seq === sequence) {\n cached = { key, quote };\n apply(quote);\n }\n return quote;\n })();\n flight = { key, promise };\n try {\n return await promise;\n } finally {\n if (seq === sequence) {\n flight = undefined;\n }\n }\n },\n accept(issue: CartIssueForAcceptance) {\n if (cached) {\n cached.quote = {\n ...cached.quote,\n issues: cached.quote.issues.filter(\n (i) => !(i.code === issue.code && i.lineId === issue.lineId),\n ),\n };\n }\n },\n };\n}\ntype CartIssueForAcceptance = { code: string; lineId?: string };\n\nexport type QuoteClient = ReturnType<typeof createQuoteClient>;\n"],"mappings":"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","names":["value"]}
|
|
@@ -8,7 +8,7 @@ async function selectedMenu(ctx, request, json, mapMenu, invalid) {
|
|
|
8
8
|
};
|
|
9
9
|
const query = new URLSearchParams({
|
|
10
10
|
branch: ctx.branchId,
|
|
11
|
-
|
|
11
|
+
fulfilment: ctx.orderContext === "dineIn" ? "dine_in" : ctx.orderContext
|
|
12
12
|
});
|
|
13
13
|
const response = await request(
|
|
14
14
|
`/menus/${encodeURIComponent(ctx.menuId)}?${query}`
|
|
@@ -76,4 +76,4 @@ export {
|
|
|
76
76
|
selectedMenu,
|
|
77
77
|
selectedMenuKey
|
|
78
78
|
};
|
|
79
|
-
//# sourceMappingURL=selected-menu-
|
|
79
|
+
//# sourceMappingURL=selected-menu-5AIX7JHU.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/transport/selected-menu.ts"],"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.menuIds) ||\n coverage.menuIds.length !== 1 ||\n coverage.menuIds[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"],"mappings":";AA+BA,eAAsB,aACpB,KACA,SACA,MACA,SACA,SAC+B;AAG/B,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,OAAO,QAAQ,KAAK,IAAI,QAAQ;AACtC,MACE,IAAI,eACJ,SAAS,aAAa,QACtB,CAAC,MAAM,QAAQ,SAAS,OAAO,KAC/B,SAAS,QAAQ,WAAW,KAC5B,SAAS,QAAQ,CAAC,MAAM,IAAI,UAC5B,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;","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// ../sdk/src/transport/store.ts
|
|
2
|
-
function mapStore(value, record, text, list, hours, mapMoney, money, opt, isString, isBoolean) {
|
|
2
|
+
function mapStore(value, record, text, list, hours, mapMoney, money, opt, isString, isBoolean, mapSeo) {
|
|
3
3
|
const coordinates = (input) => {
|
|
4
4
|
const coordinates2 = record(input ?? {});
|
|
5
5
|
return typeof coordinates2.lat === "number" && typeof coordinates2.lng === "number" ? { lat: coordinates2.lat, lng: coordinates2.lng } : void 0;
|
|
@@ -9,8 +9,8 @@ function mapStore(value, record, text, list, hours, mapMoney, money, opt, isStri
|
|
|
9
9
|
return {
|
|
10
10
|
pickup: value2.pickup === true,
|
|
11
11
|
delivery: value2.delivery === true,
|
|
12
|
-
dineIn:
|
|
13
|
-
scheduling:
|
|
12
|
+
dineIn: value2.dine_in === true,
|
|
13
|
+
scheduling: value2.scheduled === true
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
const source = record(value);
|
|
@@ -23,14 +23,26 @@ function mapStore(value, record, text, list, hours, mapMoney, money, opt, isStri
|
|
|
23
23
|
...opt("placeId", pickup.place_id, isString),
|
|
24
24
|
...pickupCoordinates ? { coordinates: pickupCoordinates } : {}
|
|
25
25
|
};
|
|
26
|
-
const address = typeof branch.address === "string" ? branch.address : branch.address ?
|
|
26
|
+
const address = typeof branch.address === "string" ? branch.address : branch.address ? text(record(branch.address).line1).trim() : void 0;
|
|
27
27
|
const addressFields = branch.address && typeof branch.address === "object" ? record(branch.address) : {};
|
|
28
28
|
const branchCoordinates = coordinates(addressFields);
|
|
29
29
|
return {
|
|
30
|
+
...branch.currency !== void 0 ? { currency: money(0, text(branch.currency)).currency } : {},
|
|
31
|
+
...opt("country", addressFields.country, isString),
|
|
32
|
+
...branch.delivery_regions !== void 0 ? {
|
|
33
|
+
deliveryRegions: list(branch.delivery_regions).map((raw2) => {
|
|
34
|
+
const region = record(raw2);
|
|
35
|
+
return {
|
|
36
|
+
id: text(region.id),
|
|
37
|
+
name: text(region.name),
|
|
38
|
+
fee: mapMoney(region.fee)
|
|
39
|
+
};
|
|
40
|
+
})
|
|
41
|
+
} : {},
|
|
30
42
|
id: text(branch.id),
|
|
31
43
|
slug: text(branch.slug ?? branch.id),
|
|
32
44
|
name: text(branch.name),
|
|
33
|
-
openingTimes: hours(branch.
|
|
45
|
+
openingTimes: hours(branch.hours),
|
|
34
46
|
isOpen: branch.is_open === true,
|
|
35
47
|
fulfilment: fulfilment(branch.fulfilment),
|
|
36
48
|
...address !== void 0 ? { address } : {},
|
|
@@ -94,9 +106,9 @@ function mapStore(value, record, text, list, hours, mapMoney, money, opt, isStri
|
|
|
94
106
|
aggregate[key] ||= branch.fulfilment[key];
|
|
95
107
|
}
|
|
96
108
|
}
|
|
97
|
-
const accent = brand.accent ?? (brand.colors ? record(brand.colors).accent : void 0);
|
|
98
109
|
const templateSettings = record(source.template_settings ?? {});
|
|
99
110
|
return {
|
|
111
|
+
...source.seo != null ? { seo: mapSeo(source.seo) } : {},
|
|
100
112
|
id: text(source.id),
|
|
101
113
|
slug: text(source.slug),
|
|
102
114
|
name: text(source.name),
|
|
@@ -106,8 +118,7 @@ function mapStore(value, record, text, list, hours, mapMoney, money, opt, isStri
|
|
|
106
118
|
...source.template_settings !== void 0 ? { templateSettings } : {},
|
|
107
119
|
brand: {
|
|
108
120
|
...opt("logoUrl", brand.logo_url, isString),
|
|
109
|
-
...opt("coverImageUrl", brand.cover_image_url, isString)
|
|
110
|
-
...isString(accent) ? { accent } : {}
|
|
121
|
+
...opt("coverImageUrl", brand.cover_image_url, isString)
|
|
111
122
|
},
|
|
112
123
|
fulfilment: source.fulfilment ? fulfilment(source.fulfilment) : aggregate,
|
|
113
124
|
paymentMethods,
|
|
@@ -117,4 +128,4 @@ function mapStore(value, record, text, list, hours, mapMoney, money, opt, isStri
|
|
|
117
128
|
export {
|
|
118
129
|
mapStore
|
|
119
130
|
};
|
|
120
|
-
//# sourceMappingURL=store-
|
|
131
|
+
//# sourceMappingURL=store-AOU2FRUX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../sdk/src/transport/store.ts"],"sourcesContent":["import type { Branch, Fulfilment, OpeningTime, Store } from \"../models\";\nimport type { Currency, Money } from \"../money\";\n\ntype Guard<T> = (value: unknown) => value is T;\ntype Optional = <K extends string, T>(\n key: K,\n value: unknown,\n is: Guard<T>,\n) => { [P in K]?: T };\n\n/** Core parsing helpers are passed in, in this order, so this lazy entry has no runtime import. */\nexport function mapStore(\n value: unknown,\n record: (value: unknown) => Record<string, unknown>,\n text: (value: unknown) => string,\n list: (value: unknown) => unknown[],\n hours: (value: unknown) => OpeningTime[],\n mapMoney: (value: unknown) => Money,\n money: (amountMinor: number, currency: Currency) => Money,\n opt: Optional,\n isString: Guard<string>,\n isBoolean: Guard<boolean>,\n mapSeo: (value: unknown) => NonNullable<Store[\"seo\"]>,\n): Store {\n const coordinates = (input: unknown) => {\n const coordinates = record(input ?? {});\n return typeof coordinates.lat === \"number\" &&\n typeof coordinates.lng === \"number\"\n ? { lat: coordinates.lat, lng: coordinates.lng }\n : undefined;\n };\n const fulfilment = (input: unknown): Fulfilment => {\n const value = record(input);\n return {\n pickup: value.pickup === true,\n delivery: value.delivery === true,\n dineIn: value.dine_in === true,\n scheduling: value.scheduled === true,\n };\n };\n const source = record(value);\n const brand = record(source.brand ?? {});\n const branches: Branch[] = list(source.branches).map((raw) => {\n const branch = record(raw);\n const pickup = record(branch.pickup_address ?? {});\n const pickupCoordinates = coordinates(pickup.coordinates);\n const pickupAddress = {\n ...opt(\"placeId\", pickup.place_id, isString),\n ...(pickupCoordinates ? { coordinates: pickupCoordinates } : {}),\n };\n const address =\n typeof branch.address === \"string\"\n ? branch.address\n : branch.address\n ? text(record(branch.address).line1).trim()\n : undefined;\n const addressFields =\n branch.address && typeof branch.address === \"object\"\n ? record(branch.address)\n : {};\n const branchCoordinates = coordinates(addressFields);\n return {\n ...(branch.currency !== undefined\n ? { currency: money(0, text(branch.currency) as Currency).currency }\n : {}),\n ...opt(\"country\", addressFields.country, isString),\n ...(branch.delivery_regions !== undefined\n ? {\n deliveryRegions: list(branch.delivery_regions).map((raw) => {\n const region = record(raw);\n return {\n id: text(region.id),\n name: text(region.name),\n fee: mapMoney(region.fee),\n };\n }),\n }\n : {}),\n id: text(branch.id),\n slug: text(branch.slug ?? branch.id),\n name: text(branch.name),\n openingTimes: hours(branch.hours),\n isOpen: branch.is_open === true,\n fulfilment: fulfilment(branch.fulfilment),\n ...(address !== undefined ? { address } : {}),\n ...(isString(branch.phone) ? { phone: branch.phone.trim() } : {}),\n ...opt(\"timezone\", branch.timezone, isString),\n ...(branchCoordinates ? { coordinates: branchCoordinates } : {}),\n ...opt(\"closedUntil\", branch.closed_until, isString),\n ...opt(\"nextChangeAt\", branch.next_change_at, isString),\n ...opt(\"isDefault\", branch.is_default, isBoolean),\n ...(Object.keys(pickupAddress).length > 0 ? { pickupAddress } : {}),\n ...(branch.social_links !== undefined\n ? {\n socialLinks: list(branch.social_links).flatMap((rawLink) => {\n const link = record(rawLink);\n // Templates render these as links; only http(s) URLs are kept.\n try {\n const url = new URL(text(link.url));\n return isString(link.type) &&\n (url.protocol === \"https:\" || url.protocol === \"http:\")\n ? [{ type: link.type, url: url.href }]\n : [];\n } catch {\n return [];\n }\n }),\n }\n : {}),\n ...(branch.minimum_order\n ? { minimumOrder: mapMoney(branch.minimum_order) }\n : {}),\n ...(branch.special_hours\n ? {\n specialHours: list(branch.special_hours).map((rawHours) => {\n const special = record(rawHours);\n return {\n date: text(special.date),\n closed: special.closed === true,\n ...opt(\"opens\", special.open, isString),\n ...opt(\"closes\", special.close, isString),\n };\n }),\n }\n : {}),\n };\n });\n const allowed = [\n \"card\",\n \"bank_transfer\",\n \"wallet\",\n \"zap\",\n \"apple_pay\",\n \"google_pay\",\n ];\n const paymentMethods = list(source.payment_methods)\n .map(text)\n .filter((method) => {\n if (allowed.includes(method)) {\n return true;\n }\n console.warn(\n `Zappie payment method \"${method}\" is newer than this SDK and was skipped`,\n );\n return false;\n });\n const aggregate = {\n pickup: false,\n delivery: false,\n dineIn: false,\n scheduling: false,\n };\n for (const branch of branches) {\n for (const key of Object.keys(aggregate) as (keyof Fulfilment)[]) {\n aggregate[key] ||= branch.fulfilment[key];\n }\n }\n const templateSettings = record(source.template_settings ?? {}) as Record<\n string,\n string | number | boolean\n >;\n return {\n ...(source.seo != null ? { seo: mapSeo(source.seo) } : {}),\n id: text(source.id),\n slug: text(source.slug),\n name: text(source.name),\n currency: money(0, text(source.currency) as Currency).currency,\n timezone: text(source.timezone),\n ...opt(\"description\", source.description, isString),\n ...(source.template_settings !== undefined ? { templateSettings } : {}),\n brand: {\n ...opt(\"logoUrl\", brand.logo_url, isString),\n ...opt(\"coverImageUrl\", brand.cover_image_url, isString),\n },\n fulfilment: source.fulfilment ? fulfilment(source.fulfilment) : aggregate,\n paymentMethods: paymentMethods as Store[\"paymentMethods\"],\n branches,\n };\n}\n"],"mappings":"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","names":["coordinates","value","raw"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zappie/verify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Deterministic verification for Zappie storefronts.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@axe-core/playwright": "4.13.0",
|
|
28
|
-
"@zappie/sdk": "^0.1.
|
|
28
|
+
"@zappie/sdk": "^0.1.6"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"ajv": "^8.18.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"$id": "https://zappie.ai/
|
|
3
|
+
"$id": "https://registry.zappie.ai/v1/schema/verify-report.json",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"additionalProperties": false,
|
|
6
6
|
"required": [
|
|
@@ -17,7 +17,9 @@
|
|
|
17
17
|
"metrics"
|
|
18
18
|
],
|
|
19
19
|
"properties": {
|
|
20
|
-
"schema": {
|
|
20
|
+
"schema": {
|
|
21
|
+
"const": "https://registry.zappie.ai/v1/schema/verify-report.json"
|
|
22
|
+
},
|
|
21
23
|
"id": { "type": "string", "pattern": "^ver_" },
|
|
22
24
|
"suite": { "enum": ["standard", "extended"] },
|
|
23
25
|
"target": {
|
|
@@ -63,7 +65,9 @@
|
|
|
63
65
|
"properties": {
|
|
64
66
|
"menuJsKbGz": { "type": "number" },
|
|
65
67
|
"lcpMs": { "type": "number" },
|
|
66
|
-
"cls": { "type": "number" }
|
|
68
|
+
"cls": { "type": "number" },
|
|
69
|
+
"productCardTappableMs": { "type": "number" },
|
|
70
|
+
"productCardOpenMs": { "type": "number" }
|
|
67
71
|
}
|
|
68
72
|
},
|
|
69
73
|
"signature": { "type": "string" }
|