@zappie/sdk 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/README.md +55 -313
- package/dist/cart/errors.js +13 -0
- package/dist/cart/errors.js.map +7 -0
- package/dist/cart/index.js +768 -0
- package/dist/cart/index.js.map +7 -0
- package/dist/cart/item.js +12 -1
- package/dist/cart/item.js.map +7 -1
- package/dist/cart/preview.js +32 -0
- package/dist/cart/preview.js.map +7 -0
- package/dist/cart/price.js +25 -0
- package/dist/cart/price.js.map +7 -0
- package/dist/cart/quote-client.js +76 -0
- package/dist/cart/quote-client.js.map +7 -0
- package/dist/cart/quote-response.js +178 -0
- package/dist/cart/quote-response.js.map +7 -0
- package/dist/cart/reconcile.js +108 -0
- package/dist/cart/reconcile.js.map +7 -0
- package/dist/cart/source-menu.js +21 -0
- package/dist/cart/source-menu.js.map +7 -0
- package/dist/cart/storage.js +174 -0
- package/dist/cart/storage.js.map +7 -0
- package/dist/cart/types.js +1 -0
- package/dist/cart/types.js.map +7 -0
- package/dist/cart/validate.js +265 -0
- package/dist/cart/validate.js.map +7 -0
- package/dist/cart/wire.js +42 -0
- package/dist/cart/wire.js.map +7 -0
- package/dist/cart/working-set.js +80 -0
- package/dist/cart/working-set.js.map +7 -0
- package/dist/checkout/client.js +102 -0
- package/dist/checkout/client.js.map +7 -0
- package/dist/checkout/error.js +21 -0
- package/dist/checkout/error.js.map +7 -0
- package/dist/checkout/index.js +13 -1
- package/dist/checkout/index.js.map +7 -1
- package/dist/checkout/readiness.js +36 -0
- package/dist/checkout/readiness.js.map +7 -0
- package/dist/checkout/sdk.js +9 -0
- package/dist/checkout/sdk.js.map +7 -0
- package/dist/checkout/session.js +58 -0
- package/dist/checkout/session.js.map +7 -0
- package/dist/checkout/types.js +1 -0
- package/dist/checkout/types.js.map +7 -0
- package/dist/client.js +253 -0
- package/dist/client.js.map +7 -0
- package/dist/config/index.js +13 -1
- package/dist/config/index.js.map +7 -0
- package/dist/config.js +28 -0
- package/dist/config.js.map +7 -0
- package/dist/customer/client.js +149 -0
- package/dist/customer/client.js.map +7 -0
- package/dist/customer/error.js +20 -0
- package/dist/customer/error.js.map +7 -0
- package/dist/customer/index.js +8 -3
- package/dist/customer/index.js.map +7 -1
- package/dist/customer/navigation.js +45 -0
- package/dist/customer/navigation.js.map +7 -0
- package/dist/customer/react.js +67 -2
- package/dist/customer/react.js.map +7 -1
- package/dist/customer/request.js +37 -0
- package/dist/customer/request.js.map +7 -0
- package/dist/customer/sdk.js +6 -0
- package/dist/customer/sdk.js.map +7 -0
- package/dist/customer/types.js +1 -0
- package/dist/customer/types.js.map +7 -0
- package/dist/customer/watch-order.js +80 -0
- package/dist/customer/watch-order.js.map +7 -0
- package/dist/debug.js +78 -1
- package/dist/debug.js.map +7 -1
- package/dist/errors.js +69 -0
- package/dist/errors.js.map +7 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +29 -1
- package/dist/index.js.map +7 -1
- package/dist/internal/abort.js +29 -0
- package/dist/internal/abort.js.map +7 -0
- package/dist/internal/cache.js +142 -0
- package/dist/internal/cache.js.map +7 -0
- package/dist/internal/customer-http.js +74 -0
- package/dist/internal/customer-http.js.map +7 -0
- package/dist/internal/digest.js +15 -0
- package/dist/internal/digest.js.map +7 -0
- package/dist/internal/emitter.js +27 -0
- package/dist/internal/emitter.js.map +7 -0
- package/dist/internal/money-math.js +30 -0
- package/dist/internal/money-math.js.map +7 -0
- package/dist/internal.js +9 -1
- package/dist/internal.js.map +7 -1
- package/dist/models.js +1 -0
- package/dist/models.js.map +7 -0
- package/dist/money.js +58 -0
- package/dist/money.js.map +7 -0
- package/dist/persist/catalogue.js +206 -2
- package/dist/persist/catalogue.js.map +7 -1
- package/dist/places/client.js +97 -0
- package/dist/places/client.js.map +7 -0
- package/dist/places/error.js +20 -0
- package/dist/places/error.js.map +7 -0
- package/dist/places/index.js +8 -1
- package/dist/places/index.js.map +7 -1
- package/dist/places/request.js +40 -0
- package/dist/places/request.js.map +7 -0
- package/dist/places/sdk.js +10 -0
- package/dist/places/sdk.js.map +7 -0
- package/dist/places/search.js +80 -0
- package/dist/places/search.js.map +7 -0
- package/dist/places/types.js +1 -0
- package/dist/places/types.js.map +7 -0
- package/dist/react/cart.js +30 -0
- package/dist/react/cart.js.map +7 -0
- package/dist/react/hooks.js +91 -0
- package/dist/react/hooks.js.map +7 -0
- package/dist/react/index.js +18 -1
- package/dist/react/index.js.map +7 -1
- package/dist/react/provider.js +34 -0
- package/dist/react/provider.js.map +7 -0
- package/dist/server/index.js +32 -2
- package/dist/server/index.js.map +7 -1
- package/dist/server/storefront-url/build-v1.js +75 -0
- package/dist/server/storefront-url/build-v1.js.map +7 -0
- package/dist/server/storefront-url/build-v2.js +79 -0
- package/dist/server/storefront-url/build-v2.js.map +7 -0
- package/dist/server/storefront-url/build.js +19 -0
- package/dist/server/storefront-url/build.js.map +7 -0
- package/dist/server/storefront-url/contract.js +25 -0
- package/dist/server/storefront-url/contract.js.map +7 -0
- package/dist/server/storefront-url/index.js +16 -0
- package/dist/server/storefront-url/index.js.map +7 -0
- package/dist/server/storefront-url/installation.js +58 -0
- package/dist/server/storefront-url/installation.js.map +7 -0
- package/dist/server/storefront-url/params.js +72 -0
- package/dist/server/storefront-url/params.js.map +7 -0
- package/dist/server/storefront-url/parse-v1.js +135 -0
- package/dist/server/storefront-url/parse-v1.js.map +7 -0
- package/dist/server/storefront-url/parse-v2.js +139 -0
- package/dist/server/storefront-url/parse-v2.js.map +7 -0
- package/dist/server/storefront-url/parse.js +9 -0
- package/dist/server/storefront-url/parse.js.map +7 -0
- package/dist/server/storefront-url/redirect.js +30 -0
- package/dist/server/storefront-url/redirect.js.map +7 -0
- package/dist/server/storefront-url/sign-in.js +17 -0
- package/dist/server/storefront-url/sign-in.js.map +7 -0
- package/dist/server/storefront-url/types.js +55 -0
- package/dist/server/storefront-url/types.js.map +7 -0
- package/dist/server/storefront-url/url.js +61 -0
- package/dist/server/storefront-url/url.js.map +7 -0
- package/dist/server/webhook.js +96 -0
- package/dist/server/webhook.js.map +7 -0
- package/dist/site-config/helpers.js +59 -0
- package/dist/site-config/helpers.js.map +7 -0
- package/dist/site-config/sections.js +105 -0
- package/dist/site-config/sections.js.map +7 -0
- package/dist/site-config/types.js +31 -0
- package/dist/site-config/types.js.map +7 -0
- package/dist/site-config/validate.js +165 -0
- package/dist/site-config/validate.js.map +7 -0
- package/dist/template/index.js +46 -3
- package/dist/template/index.js.map +7 -1
- package/dist/template/react.js +81 -2
- package/dist/template/react.js.map +7 -1
- package/dist/testing/index.js +451 -2
- package/dist/testing/index.js.map +7 -1
- package/dist/transport/category-page.js +21 -2
- package/dist/transport/category-page.js.map +7 -1
- package/dist/transport/mappers.js +326 -0
- package/dist/transport/mappers.js.map +7 -0
- package/dist/transport/rest.js +313 -0
- package/dist/transport/rest.js.map +7 -0
- package/dist/transport/search.js +32 -2
- package/dist/transport/search.js.map +7 -1
- package/dist/transport/selected-menu.js +79 -2
- package/dist/transport/selected-menu.js.map +7 -1
- package/dist/transport/store.js +120 -2
- package/dist/transport/store.js.map +7 -1
- package/dist/transport/types.js +1 -0
- package/dist/transport/types.js.map +7 -0
- package/dist/url/index.js +16 -2
- package/dist/url/index.js.map +7 -1
- package/dist/visits/index.js +62 -1
- package/dist/visits/index.js.map +7 -1
- package/dist/visits/page-views.js +103 -0
- package/dist/visits/page-views.js.map +7 -0
- package/package.json +5 -4
- package/dist/cart/quote.js +0 -1
- package/dist/cart/quote.js.map +0 -1
- package/dist/chunk-I55A5QXJ.js +0 -2
- package/dist/chunk-I55A5QXJ.js.map +0 -1
- package/dist/chunk-VG7NKIKR.js +0 -2
- package/dist/chunk-VG7NKIKR.js.map +0 -1
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// src/server/storefront-url/parse-v2.ts
|
|
2
|
+
import { CART_MODAL, CHECKOUT_MODAL, SIGN_IN_MODALS } from "./contract.js";
|
|
3
|
+
import { normalizedPath, segment } from "./installation.js";
|
|
4
|
+
import { parseV1 } from "./parse-v1.js";
|
|
5
|
+
import { signInFromOverlay } from "./sign-in.js";
|
|
6
|
+
import { ITEM_MODAL_PREFIX, inputUrl, pageState } from "./url.js";
|
|
7
|
+
var branch = (url) => url.searchParams.has("branch") ? { branch: url.searchParams.get("branch") ?? "" } : {};
|
|
8
|
+
var canonical = (url, state, business) => {
|
|
9
|
+
const pathname = normalizedPath(url.pathname);
|
|
10
|
+
const parts = pathname.split("/").filter(Boolean);
|
|
11
|
+
const scoped = branch(url);
|
|
12
|
+
if (pathname === "/") {
|
|
13
|
+
return { type: "order-menu", business, ...scoped, state };
|
|
14
|
+
}
|
|
15
|
+
if (parts[0] === "item" && parts[1] && parts.length === 2) {
|
|
16
|
+
return {
|
|
17
|
+
type: "item",
|
|
18
|
+
business,
|
|
19
|
+
...scoped,
|
|
20
|
+
item: segment(parts, 1),
|
|
21
|
+
state
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
if (pathname === "/cart" || pathname === "/checkout") {
|
|
25
|
+
return {
|
|
26
|
+
type: pathname === "/cart" ? "cart" : "checkout",
|
|
27
|
+
business,
|
|
28
|
+
...scoped,
|
|
29
|
+
state
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
if (pathname === "/checkout/return") {
|
|
33
|
+
const session = url.searchParams.get("session");
|
|
34
|
+
return {
|
|
35
|
+
type: "checkout-return",
|
|
36
|
+
business,
|
|
37
|
+
...scoped,
|
|
38
|
+
...session !== null ? { session } : {},
|
|
39
|
+
state
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
if (pathname === "/sign-in") {
|
|
43
|
+
const returnTo = url.searchParams.get("return");
|
|
44
|
+
return {
|
|
45
|
+
type: "sign-in",
|
|
46
|
+
business,
|
|
47
|
+
...scoped,
|
|
48
|
+
...returnTo !== null ? { returnTo } : {},
|
|
49
|
+
state
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (parts[0] === "pages" && parts[1] && parts.length === 2) {
|
|
53
|
+
return {
|
|
54
|
+
type: "content-page",
|
|
55
|
+
business,
|
|
56
|
+
...scoped,
|
|
57
|
+
slug: segment(parts, 1),
|
|
58
|
+
state
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (parts[0] === "orders" && parts.length <= 2) {
|
|
62
|
+
return {
|
|
63
|
+
type: "profile",
|
|
64
|
+
page: "orders",
|
|
65
|
+
...parts[1] ? { order: segment(parts, 1) } : {},
|
|
66
|
+
state
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
if (parts[0] === "account" && parts.length <= 2) {
|
|
70
|
+
const pages = {
|
|
71
|
+
"payment-methods": "payment-methods",
|
|
72
|
+
transactions: "transactions",
|
|
73
|
+
"store-credit": "add-store-credit"
|
|
74
|
+
};
|
|
75
|
+
if (parts.length === 1) {
|
|
76
|
+
return { type: "profile", page: "edit", state };
|
|
77
|
+
}
|
|
78
|
+
const page = parts[1];
|
|
79
|
+
if (page && Object.hasOwn(pages, page)) {
|
|
80
|
+
return {
|
|
81
|
+
type: "profile",
|
|
82
|
+
page: pages[page],
|
|
83
|
+
state
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
};
|
|
89
|
+
var overlay = (route, installation) => {
|
|
90
|
+
if (route.type !== "order-menu") {
|
|
91
|
+
return route;
|
|
92
|
+
}
|
|
93
|
+
const { authModalId, modalId } = route.state;
|
|
94
|
+
if (authModalId && SIGN_IN_MODALS.has(authModalId)) {
|
|
95
|
+
return signInFromOverlay(route, installation);
|
|
96
|
+
}
|
|
97
|
+
if (modalId?.startsWith(ITEM_MODAL_PREFIX)) {
|
|
98
|
+
return {
|
|
99
|
+
type: "item",
|
|
100
|
+
business: route.business,
|
|
101
|
+
...route.branch !== void 0 ? { branch: route.branch } : {},
|
|
102
|
+
item: modalId.slice(ITEM_MODAL_PREFIX.length),
|
|
103
|
+
state: route.state
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (modalId === CART_MODAL || modalId === CHECKOUT_MODAL) {
|
|
107
|
+
return {
|
|
108
|
+
type: modalId === CART_MODAL ? "cart" : "checkout",
|
|
109
|
+
business: route.business,
|
|
110
|
+
...route.branch !== void 0 ? { branch: route.branch } : {},
|
|
111
|
+
state: route.state
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
return route;
|
|
115
|
+
};
|
|
116
|
+
var parseV2 = (input, options) => {
|
|
117
|
+
try {
|
|
118
|
+
const url = inputUrl(input);
|
|
119
|
+
const state = pageState(url);
|
|
120
|
+
const installation = options.installation;
|
|
121
|
+
if (!installation) {
|
|
122
|
+
return parseV1(input, options);
|
|
123
|
+
}
|
|
124
|
+
const route = canonical(url, state, installation.business);
|
|
125
|
+
if (route) {
|
|
126
|
+
return route.type === "order-menu" ? overlay(route, installation) : route;
|
|
127
|
+
}
|
|
128
|
+
return overlay(
|
|
129
|
+
parseV1(input, { ...options, contract: "v1" }),
|
|
130
|
+
installation
|
|
131
|
+
);
|
|
132
|
+
} catch {
|
|
133
|
+
return { type: "unknown", pathname: "", state: { query: {} } };
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
export {
|
|
137
|
+
parseV2
|
|
138
|
+
};
|
|
139
|
+
//# sourceMappingURL=parse-v2.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/server/storefront-url/parse-v2.ts"],
|
|
4
|
+
"sourcesContent": ["import { CART_MODAL, CHECKOUT_MODAL, SIGN_IN_MODALS } from \"./contract\";\nimport { normalizedPath, segment } from \"./installation\";\nimport { parseV1 } from \"./parse-v1\";\nimport { signInFromOverlay } from \"./sign-in\";\nimport type {\n StorefrontPageState,\n StorefrontRoute,\n StorefrontUrlInput,\n StorefrontUrlOptions,\n} from \"./types\";\nimport { ITEM_MODAL_PREFIX, inputUrl, pageState } from \"./url\";\n\nconst branch = (url: URL) =>\n url.searchParams.has(\"branch\")\n ? { branch: url.searchParams.get(\"branch\") ?? \"\" }\n : {};\n\nconst canonical = (\n url: URL,\n state: StorefrontPageState,\n business: string,\n): StorefrontRoute | null => {\n const pathname = normalizedPath(url.pathname);\n const parts = pathname.split(\"/\").filter(Boolean);\n const scoped = branch(url);\n if (pathname === \"/\") {\n return { type: \"order-menu\", business, ...scoped, state };\n }\n if (parts[0] === \"item\" && parts[1] && parts.length === 2) {\n return {\n type: \"item\",\n business,\n ...scoped,\n item: segment(parts, 1),\n state,\n };\n }\n if (pathname === \"/cart\" || pathname === \"/checkout\") {\n return {\n type: pathname === \"/cart\" ? \"cart\" : \"checkout\",\n business,\n ...scoped,\n state,\n };\n }\n if (pathname === \"/checkout/return\") {\n const session = url.searchParams.get(\"session\");\n return {\n type: \"checkout-return\",\n business,\n ...scoped,\n ...(session !== null ? { session } : {}),\n state,\n };\n }\n if (pathname === \"/sign-in\") {\n const returnTo = url.searchParams.get(\"return\");\n return {\n type: \"sign-in\",\n business,\n ...scoped,\n ...(returnTo !== null ? { returnTo } : {}),\n state,\n };\n }\n if (parts[0] === \"pages\" && parts[1] && parts.length === 2) {\n return {\n type: \"content-page\",\n business,\n ...scoped,\n slug: segment(parts, 1),\n state,\n };\n }\n if (parts[0] === \"orders\" && parts.length <= 2) {\n return {\n type: \"profile\",\n page: \"orders\",\n ...(parts[1] ? { order: segment(parts, 1) } : {}),\n state,\n };\n }\n if (parts[0] === \"account\" && parts.length <= 2) {\n const pages = {\n \"payment-methods\": \"payment-methods\",\n transactions: \"transactions\",\n \"store-credit\": \"add-store-credit\",\n } as const;\n if (parts.length === 1) {\n return { type: \"profile\", page: \"edit\", state };\n }\n const page = parts[1];\n if (page && Object.hasOwn(pages, page)) {\n return {\n type: \"profile\",\n page: pages[page as keyof typeof pages],\n state,\n };\n }\n }\n return null;\n};\n\nconst overlay = (\n route: StorefrontRoute,\n installation: NonNullable<StorefrontUrlOptions[\"installation\"]>,\n): StorefrontRoute => {\n if (route.type !== \"order-menu\") {\n return route;\n }\n const { authModalId, modalId } = route.state;\n if (authModalId && SIGN_IN_MODALS.has(authModalId)) {\n return signInFromOverlay(route, installation);\n }\n if (modalId?.startsWith(ITEM_MODAL_PREFIX)) {\n return {\n type: \"item\",\n business: route.business,\n ...(route.branch !== undefined ? { branch: route.branch } : {}),\n item: modalId.slice(ITEM_MODAL_PREFIX.length),\n state: route.state,\n };\n }\n if (modalId === CART_MODAL || modalId === CHECKOUT_MODAL) {\n return {\n type: modalId === CART_MODAL ? \"cart\" : \"checkout\",\n business: route.business,\n ...(route.branch !== undefined ? { branch: route.branch } : {}),\n state: route.state,\n };\n }\n return route;\n};\n\nexport const parseV2 = (\n input: StorefrontUrlInput,\n options: StorefrontUrlOptions,\n): StorefrontRoute => {\n try {\n const url = inputUrl(input);\n const state = pageState(url);\n const installation = options.installation;\n if (!installation) {\n return parseV1(input, options);\n }\n const route = canonical(url, state, installation.business);\n if (route) {\n return route.type === \"order-menu\" ? overlay(route, installation) : route;\n }\n return overlay(\n parseV1(input, { ...options, contract: \"v1\" }),\n installation,\n );\n } catch {\n return { type: \"unknown\", pathname: \"\", state: { query: {} } };\n }\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// src/server/storefront-url/parse.ts
|
|
2
|
+
import { usesV2 } from "./contract.js";
|
|
3
|
+
import { parseV1 } from "./parse-v1.js";
|
|
4
|
+
import { parseV2 } from "./parse-v2.js";
|
|
5
|
+
var parseStorefrontUrl = (input, options = {}) => usesV2(options) ? parseV2(input, options) : parseV1(input, options);
|
|
6
|
+
export {
|
|
7
|
+
parseStorefrontUrl
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/server/storefront-url/parse.ts"],
|
|
4
|
+
"sourcesContent": ["import { usesV2 } from \"./contract\";\nimport { parseV1 } from \"./parse-v1\";\nimport { parseV2 } from \"./parse-v2\";\nimport type {\n StorefrontRoute,\n StorefrontUrlInput,\n StorefrontUrlOptions,\n} from \"./types\";\n\n/**\n * Parse a storefront URL into a route and its page state.\n * Uses v2 when installation metadata is present unless you select v1 explicitly.\n *\n * @param input - A URL string, URL object or Request.\n * @param options - Contract, installation and origin settings.\n * @returns A recognized route or an unknown route retaining the pathname.\n */\nexport const parseStorefrontUrl = (\n input: StorefrontUrlInput,\n options: StorefrontUrlOptions = {},\n): StorefrontRoute =>\n usesV2(options) ? parseV2(input, options) : parseV1(input, options);\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,cAAc;AACvB,SAAS,eAAe;AACxB,SAAS,eAAe;AAejB,IAAM,qBAAqB,CAChC,OACA,UAAgC,CAAC,MAEjC,OAAO,OAAO,IAAI,QAAQ,OAAO,OAAO,IAAI,QAAQ,OAAO,OAAO;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// src/server/storefront-url/redirect.ts
|
|
2
|
+
import { buildStorefrontUrl } from "./build.js";
|
|
3
|
+
import { usesV2 } from "./contract.js";
|
|
4
|
+
import { normalizedPath } from "./installation.js";
|
|
5
|
+
import { parseStorefrontUrl } from "./parse.js";
|
|
6
|
+
import { inputUrl } from "./url.js";
|
|
7
|
+
var comparable = (value) => {
|
|
8
|
+
const url = inputUrl(value);
|
|
9
|
+
url.searchParams.sort();
|
|
10
|
+
return `${normalizedPath(url.pathname)}${url.search}`;
|
|
11
|
+
};
|
|
12
|
+
var storefrontRedirect = (input, options = {}) => {
|
|
13
|
+
if (!usesV2(options)) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const route = parseStorefrontUrl(input, options);
|
|
18
|
+
if (route.type === "unknown") {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
const target = buildStorefrontUrl(route, options);
|
|
22
|
+
return comparable(inputUrl(input)) === comparable(target) ? null : target;
|
|
23
|
+
} catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
export {
|
|
28
|
+
storefrontRedirect
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=redirect.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/server/storefront-url/redirect.ts"],
|
|
4
|
+
"sourcesContent": ["import { buildStorefrontUrl } from \"./build\";\nimport { usesV2 } from \"./contract\";\nimport { normalizedPath } from \"./installation\";\nimport { parseStorefrontUrl } from \"./parse\";\nimport type { StorefrontUrlInput, StorefrontUrlOptions } from \"./types\";\nimport { inputUrl } from \"./url\";\n\nconst comparable = (value: string | URL) => {\n const url = inputUrl(value);\n url.searchParams.sort();\n return `${normalizedPath(url.pathname)}${url.search}`;\n};\n\n/**\n * Find the canonical v2 URL for a recognized storefront route.\n * Compares normalized paths and sorted query parameters to avoid unnecessary redirects.\n *\n * @returns A redirect target, or null for v1, an unknown route, a parse/build failure or an equivalent URL.\n */\nexport const storefrontRedirect = (\n input: StorefrontUrlInput,\n options: StorefrontUrlOptions = {},\n): string | null => {\n if (!usesV2(options)) {\n return null;\n }\n try {\n const route = parseStorefrontUrl(input, options);\n if (route.type === \"unknown\") {\n return null;\n }\n const target = buildStorefrontUrl(route, options);\n return comparable(inputUrl(input)) === comparable(target) ? null : target;\n } catch {\n return null;\n }\n};\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,0BAA0B;AACnC,SAAS,cAAc;AACvB,SAAS,sBAAsB;AAC/B,SAAS,0BAA0B;AAEnC,SAAS,gBAAgB;AAEzB,IAAM,aAAa,CAAC,UAAwB;AAC1C,QAAM,MAAM,SAAS,KAAK;AAC1B,MAAI,aAAa,KAAK;AACtB,SAAO,GAAG,eAAe,IAAI,QAAQ,CAAC,GAAG,IAAI,MAAM;AACrD;AAQO,IAAM,qBAAqB,CAChC,OACA,UAAgC,CAAC,MACf;AAClB,MAAI,CAAC,OAAO,OAAO,GAAG;AACpB,WAAO;AAAA,EACT;AACA,MAAI;AACF,UAAM,QAAQ,mBAAmB,OAAO,OAAO;AAC/C,QAAI,MAAM,SAAS,WAAW;AAC5B,aAAO;AAAA,IACT;AACA,UAAM,SAAS,mBAAmB,OAAO,OAAO;AAChD,WAAO,WAAW,SAAS,KAAK,CAAC,MAAM,WAAW,MAAM,IAAI,OAAO;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// src/server/storefront-url/sign-in.ts
|
|
2
|
+
import { v2Params } from "./params.js";
|
|
3
|
+
var signInFromOverlay = (route, installation) => {
|
|
4
|
+
const params = v2Params(route, installation);
|
|
5
|
+
params.delete("auth_modal_id");
|
|
6
|
+
const search = params.toString();
|
|
7
|
+
return {
|
|
8
|
+
type: "sign-in",
|
|
9
|
+
business: route.business,
|
|
10
|
+
state: { query: {} },
|
|
11
|
+
returnTo: `/${search ? `?${search}` : ""}`
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
export {
|
|
15
|
+
signInFromOverlay
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=sign-in.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/server/storefront-url/sign-in.ts"],
|
|
4
|
+
"sourcesContent": ["import { v2Params } from \"./params\";\nimport type { StorefrontInstallation, StorefrontRoute } from \"./types\";\n\nexport const signInFromOverlay = (\n route: Extract<StorefrontRoute, { type: \"order-menu\" }>,\n installation: StorefrontInstallation,\n): Extract<StorefrontRoute, { type: \"sign-in\" }> => {\n const params = v2Params(route, installation);\n params.delete(\"auth_modal_id\");\n const search = params.toString();\n return {\n type: \"sign-in\",\n business: route.business,\n state: { query: {} },\n returnTo: `/${search ? `?${search}` : \"\"}`,\n };\n};\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,gBAAgB;AAGlB,IAAM,oBAAoB,CAC/B,OACA,iBACkD;AAClD,QAAM,SAAS,SAAS,OAAO,YAAY;AAC3C,SAAO,OAAO,eAAe;AAC7B,QAAM,SAAS,OAAO,SAAS;AAC/B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU,MAAM;AAAA,IAChB,OAAO,EAAE,OAAO,CAAC,EAAE;AAAA,IACnB,UAAU,IAAI,SAAS,IAAI,MAAM,KAAK,EAAE;AAAA,EAC1C;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// src/server/storefront-url/types.ts
|
|
2
|
+
var STOREFRONT_V1_QUERY_PARAMETERS = [
|
|
3
|
+
"ref",
|
|
4
|
+
"utm_source",
|
|
5
|
+
"payment_id",
|
|
6
|
+
"context",
|
|
7
|
+
"prefetch",
|
|
8
|
+
"business_tag",
|
|
9
|
+
"pay_point_id",
|
|
10
|
+
"dine_in_order_id",
|
|
11
|
+
"no_context",
|
|
12
|
+
"payment_context_id",
|
|
13
|
+
"ws",
|
|
14
|
+
"preview",
|
|
15
|
+
"device",
|
|
16
|
+
"auto_scroll",
|
|
17
|
+
"pickup",
|
|
18
|
+
"branch_closed",
|
|
19
|
+
"order_id",
|
|
20
|
+
"modal_id",
|
|
21
|
+
"lightbox",
|
|
22
|
+
"menu_id",
|
|
23
|
+
"payment_method",
|
|
24
|
+
"beacon_id",
|
|
25
|
+
"menu_group_id",
|
|
26
|
+
"category_id",
|
|
27
|
+
"menu_layout",
|
|
28
|
+
"can_schedule",
|
|
29
|
+
"refresh",
|
|
30
|
+
"success",
|
|
31
|
+
"grant",
|
|
32
|
+
"portal",
|
|
33
|
+
"can_download_receipt",
|
|
34
|
+
"auth_modal_id",
|
|
35
|
+
"experimental_otp",
|
|
36
|
+
"branch",
|
|
37
|
+
"business",
|
|
38
|
+
"env",
|
|
39
|
+
"switched_branch",
|
|
40
|
+
"from",
|
|
41
|
+
"template",
|
|
42
|
+
"catalog_rendering",
|
|
43
|
+
"catalogue_search",
|
|
44
|
+
"catalogue_categories"
|
|
45
|
+
];
|
|
46
|
+
var STOREFRONT_QUERY_PARAMETERS = [
|
|
47
|
+
...STOREFRONT_V1_QUERY_PARAMETERS,
|
|
48
|
+
"return",
|
|
49
|
+
"session"
|
|
50
|
+
];
|
|
51
|
+
export {
|
|
52
|
+
STOREFRONT_QUERY_PARAMETERS,
|
|
53
|
+
STOREFRONT_V1_QUERY_PARAMETERS
|
|
54
|
+
};
|
|
55
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/server/storefront-url/types.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * A URL string, URL object or Request you can parse as a storefront route.\n */\nexport type StorefrontUrlInput = string | URL | Request;\n\n/**\n * The business and optional default branch bound to an installed storefront.\n */\nexport type StorefrontInstallation = {\n business: string;\n defaultBranch?: string;\n};\n\n/**\n * URL contract, installation and origin settings for parsing and building storefront routes.\n * An installation selects v2 unless you explicitly request v1.\n */\nexport type StorefrontUrlOptions = {\n contract?: \"v1\" | \"v2\";\n installation?: StorefrontInstallation;\n origin?: string;\n};\n\n/** Query keys that URL contract v1 keeps. */\nexport const STOREFRONT_V1_QUERY_PARAMETERS = [\n \"ref\",\n \"utm_source\",\n \"payment_id\",\n \"context\",\n \"prefetch\",\n \"business_tag\",\n \"pay_point_id\",\n \"dine_in_order_id\",\n \"no_context\",\n \"payment_context_id\",\n \"ws\",\n \"preview\",\n \"device\",\n \"auto_scroll\",\n \"pickup\",\n \"branch_closed\",\n \"order_id\",\n \"modal_id\",\n \"lightbox\",\n \"menu_id\",\n \"payment_method\",\n \"beacon_id\",\n \"menu_group_id\",\n \"category_id\",\n \"menu_layout\",\n \"can_schedule\",\n \"refresh\",\n \"success\",\n \"grant\",\n \"portal\",\n \"can_download_receipt\",\n \"auth_modal_id\",\n \"experimental_otp\",\n \"branch\",\n \"business\",\n \"env\",\n \"switched_branch\",\n \"from\",\n \"template\",\n \"catalog_rendering\",\n \"catalogue_search\",\n \"catalogue_categories\",\n] as const;\n\n/**\n * Recognized storefront query keys, including the v1 keys and checkout return and session keys.\n */\nexport const STOREFRONT_QUERY_PARAMETERS = [\n ...STOREFRONT_V1_QUERY_PARAMETERS,\n \"return\",\n \"session\",\n] as const;\n\n/**\n * Readonly query parameter names and string values carried by storefront page state.\n */\nexport type StorefrontQuery = Readonly<Record<string, string>>;\n\n/**\n * Query parameters and named UI selections carried alongside a storefront route.\n */\nexport type StorefrontPageState = {\n query: StorefrontQuery;\n menuId?: string;\n categoryId?: string;\n menuLayout?: string;\n mode?: \"delivery\" | \"pickup\";\n modalId?: string;\n authModalId?: string;\n paymentId?: string;\n lightbox?: string;\n catalogueSearch?: string;\n catalogueCategories?: string;\n};\n\nexport type WithState = { state: StorefrontPageState };\n\n/**\n * A parsed storefront destination with its route identifiers and page state.\n * Unrecognized paths use the unknown variant.\n */\nexport type StorefrontRoute =\n | ({\n type: \"order-menu\";\n business: string;\n branch?: string;\n cataloguePath?: boolean;\n } & WithState)\n | ({\n type: \"item\";\n business: string;\n branch?: string;\n item: string;\n } & WithState)\n | ({ type: \"cart\"; business: string; branch?: string } & WithState)\n | ({ type: \"checkout\"; business: string; branch?: string } & WithState)\n | ({\n type: \"checkout-return\";\n business: string;\n branch?: string;\n session?: string;\n } & WithState)\n | ({\n type: \"sign-in\";\n business: string;\n branch?: string;\n returnTo?: string;\n } & WithState)\n | ({\n type: \"content-page\";\n business: string;\n slug: string;\n branch?: string;\n } & WithState)\n | ({ type: \"dine-in\"; order: string } & WithState)\n | ({ type: \"dine-in-menus\" } & WithState)\n | ({ type: \"self-service-menus\" } & WithState)\n | ({ type: \"pay-point\"; payPoint: string } & WithState)\n | ({ type: \"beacon\"; beacon: string } & WithState)\n | ({ type: \"link\"; link: string } & WithState)\n | ({ type: \"collect-payment\" } & WithState)\n | ({ type: \"reservation\" } & WithState)\n | ({ type: \"pay-session\"; session: string } & WithState)\n | ({\n type: \"payment-step\";\n payment: string;\n step: \"payment\" | \"successful\" | \"failed\" | \"refunded\";\n } & WithState)\n | ({\n type: \"payment-card\";\n transaction: string;\n } & WithState)\n | ({\n type: \"profile\";\n page:\n | \"add-store-credit\"\n | \"edit\"\n | \"orders\"\n | \"payment-methods\"\n | \"transactions\";\n order?: string;\n } & WithState)\n | ({ type: \"explore\"; home?: boolean } & WithState)\n | ({ type: \"unknown\"; pathname: string } & WithState);\n"],
|
|
5
|
+
"mappings": ";AAwBO,IAAM,iCAAiC;AAAA,EAC5C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAKO,IAAM,8BAA8B;AAAA,EACzC,GAAG;AAAA,EACH;AAAA,EACA;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// src/server/storefront-url/url.ts
|
|
2
|
+
import {
|
|
3
|
+
STOREFRONT_QUERY_PARAMETERS,
|
|
4
|
+
STOREFRONT_V1_QUERY_PARAMETERS
|
|
5
|
+
} from "./types.js";
|
|
6
|
+
var FALLBACK_ORIGIN = "https://storefront.invalid";
|
|
7
|
+
var ITEM_MODAL_PREFIX = "product_";
|
|
8
|
+
var decode = (value) => {
|
|
9
|
+
try {
|
|
10
|
+
return decodeURIComponent(value);
|
|
11
|
+
} catch {
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
var encode = (value) => encodeURIComponent(value);
|
|
16
|
+
var inputUrl = (input) => {
|
|
17
|
+
if (input instanceof URL) {
|
|
18
|
+
return new URL(input.toString());
|
|
19
|
+
}
|
|
20
|
+
const value = typeof input === "string" ? input : input.url;
|
|
21
|
+
return new URL(value, FALLBACK_ORIGIN);
|
|
22
|
+
};
|
|
23
|
+
var queryRecord = (params, contract) => {
|
|
24
|
+
const query = {};
|
|
25
|
+
params.forEach((value, key) => {
|
|
26
|
+
const allowed = contract === "v2" ? STOREFRONT_QUERY_PARAMETERS : STOREFRONT_V1_QUERY_PARAMETERS;
|
|
27
|
+
if (allowed.includes(key)) {
|
|
28
|
+
query[key] = value;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
return query;
|
|
32
|
+
};
|
|
33
|
+
var pageState = (url, contract = "v2") => {
|
|
34
|
+
const query = queryRecord(url.searchParams, contract);
|
|
35
|
+
const pickup = url.searchParams.get("pickup");
|
|
36
|
+
return {
|
|
37
|
+
query,
|
|
38
|
+
...url.searchParams.has("menu_id") ? { menuId: url.searchParams.get("menu_id") ?? "" } : {},
|
|
39
|
+
...url.searchParams.has("category_id") ? { categoryId: url.searchParams.get("category_id") ?? "" } : {},
|
|
40
|
+
...url.searchParams.has("menu_layout") ? { menuLayout: url.searchParams.get("menu_layout") ?? "" } : {},
|
|
41
|
+
...pickup === "true" ? { mode: "pickup" } : pickup === "false" ? { mode: "delivery" } : {},
|
|
42
|
+
...url.searchParams.has("modal_id") ? { modalId: url.searchParams.get("modal_id") ?? "" } : {},
|
|
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
|
+
};
|
|
51
|
+
};
|
|
52
|
+
export {
|
|
53
|
+
FALLBACK_ORIGIN,
|
|
54
|
+
ITEM_MODAL_PREFIX,
|
|
55
|
+
decode,
|
|
56
|
+
encode,
|
|
57
|
+
inputUrl,
|
|
58
|
+
pageState,
|
|
59
|
+
queryRecord
|
|
60
|
+
};
|
|
61
|
+
//# sourceMappingURL=url.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 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 query: Record<string, string> = {};\n params.forEach((value, key) => {\n const allowed: readonly string[] =\n contract === \"v2\"\n ? STOREFRONT_QUERY_PARAMETERS\n : STOREFRONT_V1_QUERY_PARAMETERS;\n if (allowed.includes(key)) {\n query[key] = value;\n }\n });\n return query;\n};\n\nexport const pageState = (\n url: URL,\n contract: \"v1\" | \"v2\" = \"v2\",\n): StorefrontPageState => {\n const query = queryRecord(url.searchParams, contract);\n const pickup = url.searchParams.get(\"pickup\");\n return {\n query,\n ...(url.searchParams.has(\"menu_id\")\n ? { menuId: url.searchParams.get(\"menu_id\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"category_id\")\n ? { categoryId: url.searchParams.get(\"category_id\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"menu_layout\")\n ? { menuLayout: url.searchParams.get(\"menu_layout\") ?? \"\" }\n : {}),\n ...(pickup === \"true\"\n ? { mode: \"pickup\" as const }\n : pickup === \"false\"\n ? { mode: \"delivery\" as const }\n : {}),\n ...(url.searchParams.has(\"modal_id\")\n ? { modalId: url.searchParams.get(\"modal_id\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"auth_modal_id\")\n ? { authModalId: url.searchParams.get(\"auth_modal_id\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"payment_id\")\n ? { paymentId: url.searchParams.get(\"payment_id\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"lightbox\")\n ? { lightbox: url.searchParams.get(\"lightbox\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"catalogue_search\")\n ? { catalogueSearch: url.searchParams.get(\"catalogue_search\") ?? \"\" }\n : {}),\n ...(url.searchParams.has(\"catalogue_categories\")\n ? {\n catalogueCategories:\n url.searchParams.get(\"catalogue_categories\") ?? \"\",\n }\n : {}),\n };\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,cAAc,CAAC,QAAyB,aAA0B;AAC7E,QAAM,QAAgC,CAAC;AACvC,SAAO,QAAQ,CAAC,OAAO,QAAQ;AAC7B,UAAM,UACJ,aAAa,OACT,8BACA;AACN,QAAI,QAAQ,SAAS,GAAG,GAAG;AACzB,YAAM,GAAG,IAAI;AAAA,IACf;AAAA,EACF,CAAC;AACD,SAAO;AACT;AAEO,IAAM,YAAY,CACvB,KACA,WAAwB,SACA;AACxB,QAAM,QAAQ,YAAY,IAAI,cAAc,QAAQ;AACpD,QAAM,SAAS,IAAI,aAAa,IAAI,QAAQ;AAC5C,SAAO;AAAA,IACL;AAAA,IACA,GAAI,IAAI,aAAa,IAAI,SAAS,IAC9B,EAAE,QAAQ,IAAI,aAAa,IAAI,SAAS,KAAK,GAAG,IAChD,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,aAAa,IAClC,EAAE,YAAY,IAAI,aAAa,IAAI,aAAa,KAAK,GAAG,IACxD,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,aAAa,IAClC,EAAE,YAAY,IAAI,aAAa,IAAI,aAAa,KAAK,GAAG,IACxD,CAAC;AAAA,IACL,GAAI,WAAW,SACX,EAAE,MAAM,SAAkB,IAC1B,WAAW,UACT,EAAE,MAAM,WAAoB,IAC5B,CAAC;AAAA,IACP,GAAI,IAAI,aAAa,IAAI,UAAU,IAC/B,EAAE,SAAS,IAAI,aAAa,IAAI,UAAU,KAAK,GAAG,IAClD,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,eAAe,IACpC,EAAE,aAAa,IAAI,aAAa,IAAI,eAAe,KAAK,GAAG,IAC3D,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,YAAY,IACjC,EAAE,WAAW,IAAI,aAAa,IAAI,YAAY,KAAK,GAAG,IACtD,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,UAAU,IAC/B,EAAE,UAAU,IAAI,aAAa,IAAI,UAAU,KAAK,GAAG,IACnD,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,kBAAkB,IACvC,EAAE,iBAAiB,IAAI,aAAa,IAAI,kBAAkB,KAAK,GAAG,IAClE,CAAC;AAAA,IACL,GAAI,IAAI,aAAa,IAAI,sBAAsB,IAC3C;AAAA,MACE,qBACE,IAAI,aAAa,IAAI,sBAAsB,KAAK;AAAA,IACpD,IACA,CAAC;AAAA,EACP;AACF;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
// src/server/webhook.ts
|
|
2
|
+
import { ZappieError } from "../errors.js";
|
|
3
|
+
var ZappieWebhookSignatureError = class extends ZappieError {
|
|
4
|
+
constructor() {
|
|
5
|
+
super("invalid_request", "Zappie could not verify this webhook signature.");
|
|
6
|
+
this.name = "ZappieWebhookSignatureError";
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
var encoder = new TextEncoder();
|
|
10
|
+
async function verifyWebhook({
|
|
11
|
+
payload,
|
|
12
|
+
header,
|
|
13
|
+
secret,
|
|
14
|
+
toleranceSec = 300,
|
|
15
|
+
now = /* @__PURE__ */ new Date()
|
|
16
|
+
}) {
|
|
17
|
+
const parsed = signatureHeader(header);
|
|
18
|
+
if (secret.length === 0 || !parsed || !Number.isFinite(toleranceSec) || toleranceSec < 0 || Math.abs(now.getTime() / 1e3 - parsed.seconds) > toleranceSec) {
|
|
19
|
+
throw new ZappieWebhookSignatureError();
|
|
20
|
+
}
|
|
21
|
+
const body = typeof payload === "string" ? encoder.encode(payload) : payload;
|
|
22
|
+
const prefix = encoder.encode(`${parsed.timestamp}.`);
|
|
23
|
+
const signed = new Uint8Array(prefix.length + body.length);
|
|
24
|
+
signed.set(prefix);
|
|
25
|
+
signed.set(body, prefix.length);
|
|
26
|
+
const key = await crypto.subtle.importKey(
|
|
27
|
+
"raw",
|
|
28
|
+
encoder.encode(secret),
|
|
29
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
30
|
+
false,
|
|
31
|
+
["verify"]
|
|
32
|
+
);
|
|
33
|
+
const matches = await Promise.all(
|
|
34
|
+
parsed.signatures.map(async (candidate) => {
|
|
35
|
+
const valid = /^[0-9a-f]{64}$/.test(candidate);
|
|
36
|
+
const bytes = valid ? hex(candidate) : new Uint8Array(32);
|
|
37
|
+
const match = await crypto.subtle.verify("HMAC", key, bytes, signed);
|
|
38
|
+
return valid && match;
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
if (!matches.some(Boolean)) {
|
|
42
|
+
throw new ZappieWebhookSignatureError();
|
|
43
|
+
}
|
|
44
|
+
let event;
|
|
45
|
+
try {
|
|
46
|
+
event = JSON.parse(new TextDecoder().decode(body));
|
|
47
|
+
} catch (cause) {
|
|
48
|
+
throw new ZappieError(
|
|
49
|
+
"invalid_request",
|
|
50
|
+
"The verified webhook payload is not valid JSON.",
|
|
51
|
+
{ cause }
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
if (!event || typeof event !== "object" || Array.isArray(event)) {
|
|
55
|
+
throw new ZappieError(
|
|
56
|
+
"invalid_request",
|
|
57
|
+
"The verified webhook payload is not a JSON object."
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
return event;
|
|
61
|
+
}
|
|
62
|
+
function signatureHeader(header) {
|
|
63
|
+
let timestamp = "";
|
|
64
|
+
const signatures = [];
|
|
65
|
+
for (const part of header?.split(",") ?? []) {
|
|
66
|
+
const value = part.trim();
|
|
67
|
+
const separator = value.indexOf("=");
|
|
68
|
+
if (separator < 0) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const key = value.slice(0, separator);
|
|
72
|
+
const item = value.slice(separator + 1);
|
|
73
|
+
if (key === "t") {
|
|
74
|
+
timestamp = item;
|
|
75
|
+
} else if (key === "v1") {
|
|
76
|
+
signatures.push(item);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (!/^[+-]?\d+$/.test(timestamp) || signatures.length === 0) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const seconds = Number(timestamp);
|
|
83
|
+
return Number.isSafeInteger(seconds) ? { timestamp, seconds, signatures } : null;
|
|
84
|
+
}
|
|
85
|
+
function hex(value) {
|
|
86
|
+
const bytes = new Uint8Array(value.length / 2);
|
|
87
|
+
for (let index = 0; index < bytes.length; index += 1) {
|
|
88
|
+
bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);
|
|
89
|
+
}
|
|
90
|
+
return bytes;
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
ZappieWebhookSignatureError,
|
|
94
|
+
verifyWebhook
|
|
95
|
+
};
|
|
96
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/server/webhook.ts"],
|
|
4
|
+
"sourcesContent": ["import { ZappieError } from \"../errors\";\n\n/** Event names sent by the Zappie webhook API. */\nexport type WebhookEventType =\n | \"menu.updated\"\n | \"branch.hours_changed\"\n | \"store.updated\"\n | \"checkout.session.completed\"\n | \"checkout.session.expired\"\n | \"order.created\"\n | \"order.paid\"\n | \"order.status_changed\"\n | \"customer.signed_in\"\n | \"payout.initiated\"\n | \"payout.paid\"\n | \"payout.failed\"\n | \"payout_request.created\"\n | \"payout_request.approved\"\n | \"payout_request.rejected\"\n | \"payment.received\";\n\n/** The event envelope sent in a Zappie webhook request. */\nexport type WebhookEvent = {\n id: string;\n type: WebhookEventType;\n version: string;\n created_at: string;\n livemode: boolean;\n business_id: string;\n branch_id?: string;\n idempotency_key: string;\n data: { object: Record<string, unknown> };\n previous_attributes: Record<string, unknown> | null;\n};\n\n/** Input for webhook signature verification. */\nexport type VerifyWebhookOptions = {\n payload: string | Uint8Array;\n header: string | null | undefined;\n secret: string;\n toleranceSec?: number;\n now?: Date;\n};\n\n/** A webhook signature that cannot be trusted. */\nexport class ZappieWebhookSignatureError extends ZappieError {\n constructor() {\n super(\"invalid_request\", \"Zappie could not verify this webhook signature.\");\n this.name = \"ZappieWebhookSignatureError\";\n }\n}\n\nconst encoder = new TextEncoder();\n\n/** Verify a webhook signature against its raw body and return the event. */\nexport async function verifyWebhook({\n payload,\n header,\n secret,\n toleranceSec = 300,\n now = new Date(),\n}: VerifyWebhookOptions): Promise<WebhookEvent> {\n const parsed = signatureHeader(header);\n if (\n secret.length === 0 ||\n !parsed ||\n !Number.isFinite(toleranceSec) ||\n toleranceSec < 0 ||\n Math.abs(now.getTime() / 1000 - parsed.seconds) > toleranceSec\n ) {\n throw new ZappieWebhookSignatureError();\n }\n const body = typeof payload === \"string\" ? encoder.encode(payload) : payload;\n const prefix = encoder.encode(`${parsed.timestamp}.`);\n const signed = new Uint8Array(prefix.length + body.length);\n signed.set(prefix);\n signed.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n );\n const matches = await Promise.all(\n parsed.signatures.map(async (candidate) => {\n const valid = /^[0-9a-f]{64}$/.test(candidate);\n const bytes = valid ? hex(candidate) : new Uint8Array(32);\n const match = await crypto.subtle.verify(\"HMAC\", key, bytes, signed);\n return valid && match;\n }),\n );\n if (!matches.some(Boolean)) {\n throw new ZappieWebhookSignatureError();\n }\n let event: unknown;\n try {\n event = JSON.parse(new TextDecoder().decode(body));\n } catch (cause) {\n throw new ZappieError(\n \"invalid_request\",\n \"The verified webhook payload is not valid JSON.\",\n { cause },\n );\n }\n if (!event || typeof event !== \"object\" || Array.isArray(event)) {\n throw new ZappieError(\n \"invalid_request\",\n \"The verified webhook payload is not a JSON object.\",\n );\n }\n return event as WebhookEvent;\n}\n\nfunction signatureHeader(header: string | null | undefined) {\n let timestamp = \"\";\n const signatures: string[] = [];\n for (const part of header?.split(\",\") ?? []) {\n const value = part.trim();\n const separator = value.indexOf(\"=\");\n if (separator < 0) {\n continue;\n }\n const key = value.slice(0, separator);\n const item = value.slice(separator + 1);\n if (key === \"t\") {\n timestamp = item;\n } else if (key === \"v1\") {\n signatures.push(item);\n }\n }\n if (!/^[+-]?\\d+$/.test(timestamp) || signatures.length === 0) {\n return null;\n }\n const seconds = Number(timestamp);\n return Number.isSafeInteger(seconds)\n ? { timestamp, seconds, signatures }\n : null;\n}\n\nfunction hex(value: string) {\n const bytes = new Uint8Array(value.length / 2);\n for (let index = 0; index < bytes.length; index += 1) {\n bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);\n }\n return bytes;\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
// src/site-config/helpers.ts
|
|
2
|
+
import { GLOBAL_PACKAGE_ALLOWLIST } from "./types.js";
|
|
3
|
+
var record = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
+
function distance(left, right) {
|
|
5
|
+
let row = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
6
|
+
for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {
|
|
7
|
+
const next = [leftIndex];
|
|
8
|
+
for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {
|
|
9
|
+
next[rightIndex] = Math.min(
|
|
10
|
+
(next[rightIndex - 1] ?? 0) + 1,
|
|
11
|
+
(row[rightIndex] ?? 0) + 1,
|
|
12
|
+
(row[rightIndex - 1] ?? 0) + (left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1)
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
row = next;
|
|
16
|
+
}
|
|
17
|
+
return row[right.length] ?? Infinity;
|
|
18
|
+
}
|
|
19
|
+
function unknownKeys(value, allowed, path, issue) {
|
|
20
|
+
for (const key of Object.keys(value)) {
|
|
21
|
+
if (allowed.includes(key)) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const closest = allowed.map((candidate) => ({ candidate, score: distance(key, candidate) })).sort((left, right) => left.score - right.score)[0];
|
|
25
|
+
const hint = closest && closest.score <= 2 ? closest.candidate : void 0;
|
|
26
|
+
issue({
|
|
27
|
+
path: path ? `${path}.${key}` : key,
|
|
28
|
+
code: "unknown_key",
|
|
29
|
+
message: hint ? `Unknown field "${key}". Rename it to "${hint}".` : `Unknown field "${key}". Remove it from the configuration.`,
|
|
30
|
+
severity: "error"
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
var nonblank = (value) => typeof value === "string" && value.trim().length > 0;
|
|
35
|
+
var packageName = (value) => value.length <= 214 && /^(?:@[a-z0-9][a-z0-9._~-]*\/[a-z0-9][a-z0-9._~-]*|[a-z0-9][a-z0-9._~-]*)$/.test(
|
|
36
|
+
value
|
|
37
|
+
);
|
|
38
|
+
var globallyAllowed = (value) => GLOBAL_PACKAGE_ALLOWLIST.some(
|
|
39
|
+
(allowed) => allowed.endsWith("/*") ? value.startsWith(allowed.slice(0, -1)) : value === allowed
|
|
40
|
+
);
|
|
41
|
+
function hostname(value) {
|
|
42
|
+
const wildcard = value.startsWith("*.");
|
|
43
|
+
const host = wildcard ? value.slice(2) : value;
|
|
44
|
+
if (!host.includes(".") || /^\d+(?:\.\d+){3}$/.test(host) || host.length > 253 || host.includes("..")) {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
return host.split(".").every(
|
|
48
|
+
(label) => label.length > 0 && label.length <= 63 && /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
export {
|
|
52
|
+
globallyAllowed,
|
|
53
|
+
hostname,
|
|
54
|
+
nonblank,
|
|
55
|
+
packageName,
|
|
56
|
+
record,
|
|
57
|
+
unknownKeys
|
|
58
|
+
};
|
|
59
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/site-config/helpers.ts"],
|
|
4
|
+
"sourcesContent": ["import { GLOBAL_PACKAGE_ALLOWLIST, type ConfigIssue } from \"./types\";\n\nexport const record = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nfunction distance(left: string, right: string) {\n let row = Array.from({ length: right.length + 1 }, (_, index) => index);\n for (let leftIndex = 1; leftIndex <= left.length; leftIndex += 1) {\n const next = [leftIndex];\n for (let rightIndex = 1; rightIndex <= right.length; rightIndex += 1) {\n next[rightIndex] = Math.min(\n (next[rightIndex - 1] ?? 0) + 1,\n (row[rightIndex] ?? 0) + 1,\n (row[rightIndex - 1] ?? 0) +\n (left[leftIndex - 1] === right[rightIndex - 1] ? 0 : 1),\n );\n }\n row = next;\n }\n return row[right.length] ?? Infinity;\n}\n\nexport function unknownKeys(\n value: Record<string, unknown>,\n allowed: readonly string[],\n path: string,\n issue: (value: ConfigIssue) => void,\n) {\n for (const key of Object.keys(value)) {\n if (allowed.includes(key)) {\n continue;\n }\n const closest = allowed\n .map((candidate) => ({ candidate, score: distance(key, candidate) }))\n .sort((left, right) => left.score - right.score)[0];\n const hint = closest && closest.score <= 2 ? closest.candidate : undefined;\n issue({\n path: path ? `${path}.${key}` : key,\n code: \"unknown_key\",\n message: hint\n ? `Unknown field \"${key}\". Rename it to \"${hint}\".`\n : `Unknown field \"${key}\". Remove it from the configuration.`,\n severity: \"error\",\n });\n }\n}\n\nexport const nonblank = (value: unknown): value is string =>\n typeof value === \"string\" && value.trim().length > 0;\n\nexport const packageName = (value: string) =>\n value.length <= 214 &&\n /^(?:@[a-z0-9][a-z0-9._~-]*\\/[a-z0-9][a-z0-9._~-]*|[a-z0-9][a-z0-9._~-]*)$/.test(\n value,\n );\n\nexport const globallyAllowed = (value: string) =>\n GLOBAL_PACKAGE_ALLOWLIST.some((allowed) =>\n allowed.endsWith(\"/*\")\n ? value.startsWith(allowed.slice(0, -1))\n : value === allowed,\n );\n\nexport function hostname(value: string) {\n const wildcard = value.startsWith(\"*.\");\n const host = wildcard ? value.slice(2) : value;\n if (\n !host.includes(\".\") ||\n /^\\d+(?:\\.\\d+){3}$/.test(host) ||\n host.length > 253 ||\n host.includes(\"..\")\n ) {\n return false;\n }\n return host\n .split(\".\")\n .every(\n (label) =>\n label.length > 0 &&\n label.length <= 63 &&\n /^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/i.test(label),\n );\n}\n"],
|
|
5
|
+
"mappings": ";AAAA,SAAS,gCAAkD;AAEpD,IAAM,SAAS,CAAC,UACrB,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAErE,SAAS,SAAS,MAAc,OAAe;AAC7C,MAAI,MAAM,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,EAAE,GAAG,CAAC,GAAG,UAAU,KAAK;AACtE,WAAS,YAAY,GAAG,aAAa,KAAK,QAAQ,aAAa,GAAG;AAChE,UAAM,OAAO,CAAC,SAAS;AACvB,aAAS,aAAa,GAAG,cAAc,MAAM,QAAQ,cAAc,GAAG;AACpE,WAAK,UAAU,IAAI,KAAK;AAAA,SACrB,KAAK,aAAa,CAAC,KAAK,KAAK;AAAA,SAC7B,IAAI,UAAU,KAAK,KAAK;AAAA,SACxB,IAAI,aAAa,CAAC,KAAK,MACrB,KAAK,YAAY,CAAC,MAAM,MAAM,aAAa,CAAC,IAAI,IAAI;AAAA,MACzD;AAAA,IACF;AACA,UAAM;AAAA,EACR;AACA,SAAO,IAAI,MAAM,MAAM,KAAK;AAC9B;AAEO,SAAS,YACd,OACA,SACA,MACA,OACA;AACA,aAAW,OAAO,OAAO,KAAK,KAAK,GAAG;AACpC,QAAI,QAAQ,SAAS,GAAG,GAAG;AACzB;AAAA,IACF;AACA,UAAM,UAAU,QACb,IAAI,CAAC,eAAe,EAAE,WAAW,OAAO,SAAS,KAAK,SAAS,EAAE,EAAE,EACnE,KAAK,CAAC,MAAM,UAAU,KAAK,QAAQ,MAAM,KAAK,EAAE,CAAC;AACpD,UAAM,OAAO,WAAW,QAAQ,SAAS,IAAI,QAAQ,YAAY;AACjE,UAAM;AAAA,MACJ,MAAM,OAAO,GAAG,IAAI,IAAI,GAAG,KAAK;AAAA,MAChC,MAAM;AAAA,MACN,SAAS,OACL,kBAAkB,GAAG,oBAAoB,IAAI,OAC7C,kBAAkB,GAAG;AAAA,MACzB,UAAU;AAAA,IACZ,CAAC;AAAA,EACH;AACF;AAEO,IAAM,WAAW,CAAC,UACvB,OAAO,UAAU,YAAY,MAAM,KAAK,EAAE,SAAS;AAE9C,IAAM,cAAc,CAAC,UAC1B,MAAM,UAAU,OAChB,4EAA4E;AAAA,EAC1E;AACF;AAEK,IAAM,kBAAkB,CAAC,UAC9B,yBAAyB;AAAA,EAAK,CAAC,YAC7B,QAAQ,SAAS,IAAI,IACjB,MAAM,WAAW,QAAQ,MAAM,GAAG,EAAE,CAAC,IACrC,UAAU;AAChB;AAEK,SAAS,SAAS,OAAe;AACtC,QAAM,WAAW,MAAM,WAAW,IAAI;AACtC,QAAM,OAAO,WAAW,MAAM,MAAM,CAAC,IAAI;AACzC,MACE,CAAC,KAAK,SAAS,GAAG,KAClB,oBAAoB,KAAK,IAAI,KAC7B,KAAK,SAAS,OACd,KAAK,SAAS,IAAI,GAClB;AACA,WAAO;AAAA,EACT;AACA,SAAO,KACJ,MAAM,GAAG,EACT;AAAA,IACC,CAAC,UACC,MAAM,SAAS,KACf,MAAM,UAAU,MAChB,qCAAqC,KAAK,KAAK;AAAA,EACnD;AACJ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|