@kotao/storefront 0.2.1 → 0.2.3
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/dist/chunk-4OQYNUGM.js +29 -0
- package/dist/chunk-4OQYNUGM.js.map +1 -0
- package/dist/{chunk-U5677AEA.js → chunk-4TEFGD42.js} +343 -40
- package/dist/chunk-4TEFGD42.js.map +1 -0
- package/dist/chunk-7MTCGXIG.js +144 -0
- package/dist/chunk-7MTCGXIG.js.map +1 -0
- package/dist/{chunk-GCQI6OKH.js → chunk-H3D7BAOL.js} +3 -26
- package/dist/chunk-H3D7BAOL.js.map +1 -0
- package/dist/chunk-IIOHENCG.js +239 -0
- package/dist/chunk-IIOHENCG.js.map +1 -0
- package/dist/chunk-M7BPQ54D.js +26 -0
- package/dist/chunk-M7BPQ54D.js.map +1 -0
- package/dist/{chunk-ISAFEOR2.js → chunk-PXVDVUFX.js} +3 -2
- package/dist/chunk-PXVDVUFX.js.map +1 -0
- package/dist/chunk-VV653S52.js +246 -0
- package/dist/chunk-VV653S52.js.map +1 -0
- package/dist/chunk-WG7HYVHJ.js +38 -0
- package/dist/chunk-WG7HYVHJ.js.map +1 -0
- package/dist/{client-D9YYA2w6.d.ts → client-D51WdvYR.d.ts} +55 -8
- package/dist/client-bsiNPHBi.d.ts +159 -0
- package/dist/createCartHandler-C4RrPwSG.d.ts +58 -0
- package/dist/editor.d.ts +1 -1
- package/dist/events-react.d.ts +68 -0
- package/dist/events-react.js +557 -0
- package/dist/events-react.js.map +1 -0
- package/dist/events.d.ts +18 -0
- package/dist/events.js +5 -0
- package/dist/events.js.map +1 -0
- package/dist/fetch-M3Y-fQrW.d.ts +47 -0
- package/dist/forms.d.ts +58 -0
- package/dist/forms.js +3 -0
- package/dist/forms.js.map +1 -0
- package/dist/http-types-CGh8WGHB.d.ts +11 -0
- package/dist/index.d.ts +75 -12
- package/dist/index.js +55 -8
- package/dist/index.js.map +1 -1
- package/dist/offer-token-C-nk_nj8.d.ts +16 -0
- package/dist/{pagination-CPgH3fAa.d.ts → pagination-DCrQk02Q.d.ts} +1 -1
- package/dist/product.d.ts +1 -1
- package/dist/react-router.d.ts +12 -6
- package/dist/react-router.js +4 -2
- package/dist/react-router.js.map +1 -1
- package/dist/react.d.ts +30 -7
- package/dist/react.js +275 -156
- package/dist/react.js.map +1 -1
- package/dist/{routing-BfUp49o8.d.ts → routing-sEonP93J.d.ts} +26 -59
- package/dist/seo.d.ts +4 -1
- package/dist/seo.js +1 -1
- package/dist/settings.d.ts +6 -39
- package/dist/settings.js +2 -1
- package/dist/{shop-DkQmro-Y.d.ts → shop-BJSvtmnV.d.ts} +2 -2
- package/dist/{store-DQK1nhob.d.ts → store-CtCWHI8H.d.ts} +1 -1
- package/dist/types-CSNXbGFW.d.ts +108 -0
- package/dist/{types-Df3bGbKU.d.ts → types-bcbQzx87.d.ts} +1 -1
- package/package.json +13 -1
- package/dist/chunk-GCQI6OKH.js.map +0 -1
- package/dist/chunk-ISAFEOR2.js.map +0 -1
- package/dist/chunk-U5677AEA.js.map +0 -1
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// src/events/cart.ts
|
|
2
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
3
|
+
var SHOPIFY_CART_GID_RE = new RegExp(
|
|
4
|
+
`^gid://shopify/Cart/(${UUID_RE.source.slice(1, -1)})$`,
|
|
5
|
+
"iu"
|
|
6
|
+
);
|
|
7
|
+
var EventCartPreparationError = class extends Error {
|
|
8
|
+
constructor() {
|
|
9
|
+
super("Unable to prepare event cart");
|
|
10
|
+
this.name = "EventCartPreparationError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
function eventCartToken(cartId) {
|
|
14
|
+
if (UUID_RE.test(cartId)) return cartId;
|
|
15
|
+
const gidToken = SHOPIFY_CART_GID_RE.exec(cartId)?.[1];
|
|
16
|
+
if (gidToken !== void 0) return gidToken;
|
|
17
|
+
throw new EventCartPreparationError();
|
|
18
|
+
}
|
|
19
|
+
async function prepareEventCart(cart) {
|
|
20
|
+
const existing = await cart.get();
|
|
21
|
+
if (existing) return { cartToken: eventCartToken(existing.id), headers: new Headers() };
|
|
22
|
+
const created = await cart.create();
|
|
23
|
+
if (!created.cart || created.userErrors.length > 0) throw new EventCartPreparationError();
|
|
24
|
+
return { cartToken: eventCartToken(created.cart.id), headers: created.headers };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export { EventCartPreparationError, eventCartToken, prepareEventCart };
|
|
28
|
+
//# sourceMappingURL=chunk-4OQYNUGM.js.map
|
|
29
|
+
//# sourceMappingURL=chunk-4OQYNUGM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/events/cart.ts"],"names":[],"mappings":";AAEA,IAAM,OAAA,GAAU,6EAAA;AAChB,IAAM,sBAAsB,IAAI,MAAA;AAAA,EAC9B,wBAAwB,OAAA,CAAQ,MAAA,CAAO,KAAA,CAAM,CAAA,EAAG,EAAE,CAAC,CAAA,EAAA,CAAA;AAAA,EACnD;AACF,CAAA;AAEO,IAAM,yBAAA,GAAN,cAAwC,KAAA,CAAM;AAAA,EACnD,WAAA,GAAc;AACZ,IAAA,KAAA,CAAM,8BAA8B,CAAA;AACpC,IAAA,IAAA,CAAK,IAAA,GAAO,2BAAA;AAAA,EACd;AACF;AAEO,SAAS,eAAe,MAAA,EAAwB;AACrD,EAAA,IAAI,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,MAAA;AACjC,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,IAAA,CAAK,MAAM,IAAI,CAAC,CAAA;AACrD,EAAA,IAAI,QAAA,KAAa,QAAW,OAAO,QAAA;AACnC,EAAA,MAAM,IAAI,yBAAA,EAA0B;AACtC;AAEA,eAAsB,iBACpB,IAAA,EACkD;AAClD,EAAA,MAAM,QAAA,GAAW,MAAM,IAAA,CAAK,GAAA,EAAI;AAChC,EAAA,IAAI,QAAA,EAAU,OAAO,EAAE,SAAA,EAAW,cAAA,CAAe,QAAA,CAAS,EAAE,CAAA,EAAG,OAAA,EAAS,IAAI,OAAA,EAAQ,EAAE;AACtF,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,MAAA,EAAO;AAClC,EAAA,IAAI,CAAC,QAAQ,IAAA,IAAQ,OAAA,CAAQ,WAAW,MAAA,GAAS,CAAA,EAAG,MAAM,IAAI,yBAAA,EAA0B;AACxF,EAAA,OAAO,EAAE,WAAW,cAAA,CAAe,OAAA,CAAQ,KAAK,EAAE,CAAA,EAAG,OAAA,EAAS,OAAA,CAAQ,OAAA,EAAQ;AAChF","file":"chunk-4OQYNUGM.js","sourcesContent":["import type { CartHandler } from '../cart/createCartHandler'\n\nconst UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu\nconst SHOPIFY_CART_GID_RE = new RegExp(\n `^gid://shopify/Cart/(${UUID_RE.source.slice(1, -1)})$`,\n 'iu',\n)\n\nexport class EventCartPreparationError extends Error {\n constructor() {\n super('Unable to prepare event cart')\n this.name = 'EventCartPreparationError'\n }\n}\n\nexport function eventCartToken(cartId: string): string {\n if (UUID_RE.test(cartId)) return cartId\n const gidToken = SHOPIFY_CART_GID_RE.exec(cartId)?.[1]\n if (gidToken !== undefined) return gidToken\n throw new EventCartPreparationError()\n}\n\nexport async function prepareEventCart(\n cart: CartHandler,\n): Promise<{ cartToken: string; headers: Headers }> {\n const existing = await cart.get()\n if (existing) return { cartToken: eventCartToken(existing.id), headers: new Headers() }\n const created = await cart.create()\n if (!created.cart || created.userErrors.length > 0) throw new EventCartPreparationError()\n return { cartToken: eventCartToken(created.cart.id), headers: created.headers }\n}\n"]}
|
|
@@ -1,30 +1,44 @@
|
|
|
1
1
|
import { CONSENT_BUCKETS, readConsentCookie, CART_FORM_ACTIONS } from './chunk-OGWYTYYS.js';
|
|
2
|
-
import {
|
|
2
|
+
import { fetchThemeSettings } from './chunk-M7BPQ54D.js';
|
|
3
|
+
import { createEventsClient, normalizeStorefrontHeaders } from './chunk-7MTCGXIG.js';
|
|
4
|
+
import { SHOP_HEADER, SHOP_SIGNATURE_HEADER, SHOP_ORIGIN_HEADER, autoRedirectEnabled, AUTO_REDIRECT_LANGUAGE_HEADER, AUTO_REDIRECT_COUNTRY_HEADER, signShopContext } from '@kotao/storefront-contracts';
|
|
3
5
|
|
|
4
6
|
// src/cache/cache.ts
|
|
5
|
-
var
|
|
7
|
+
var DEFAULT_STALE_IF_ERROR_SECONDS = 300;
|
|
8
|
+
var CacheNone = () => ({
|
|
9
|
+
mode: "none",
|
|
10
|
+
maxAge: 0,
|
|
11
|
+
staleWhileRevalidate: 0,
|
|
12
|
+
staleIfError: 0
|
|
13
|
+
});
|
|
6
14
|
var CacheShort = (o) => ({
|
|
7
15
|
mode: "short",
|
|
8
16
|
maxAge: o?.maxAge ?? 1,
|
|
9
|
-
staleWhileRevalidate: o?.staleWhileRevalidate ?? 9
|
|
17
|
+
staleWhileRevalidate: o?.staleWhileRevalidate ?? 9,
|
|
18
|
+
staleIfError: o?.staleIfError ?? DEFAULT_STALE_IF_ERROR_SECONDS
|
|
10
19
|
});
|
|
11
20
|
var CacheLong = (o) => ({
|
|
12
21
|
mode: "long",
|
|
13
22
|
maxAge: o?.maxAge ?? 3600,
|
|
14
|
-
staleWhileRevalidate: o?.staleWhileRevalidate ?? 82800
|
|
23
|
+
staleWhileRevalidate: o?.staleWhileRevalidate ?? 82800,
|
|
24
|
+
staleIfError: o?.staleIfError ?? DEFAULT_STALE_IF_ERROR_SECONDS
|
|
15
25
|
});
|
|
16
26
|
var CacheCustom = (s) => ({
|
|
17
27
|
mode: "custom",
|
|
28
|
+
staleIfError: DEFAULT_STALE_IF_ERROR_SECONDS,
|
|
18
29
|
...s
|
|
19
30
|
});
|
|
20
31
|
var StorefrontDefaultCache = () => ({
|
|
21
32
|
mode: "custom",
|
|
22
33
|
maxAge: 1,
|
|
23
|
-
staleWhileRevalidate: 86399
|
|
34
|
+
staleWhileRevalidate: 86399,
|
|
35
|
+
staleIfError: DEFAULT_STALE_IF_ERROR_SECONDS
|
|
24
36
|
});
|
|
25
37
|
function generateCacheControlHeader(strategy) {
|
|
26
38
|
if (strategy.mode === "none") return "no-store";
|
|
27
|
-
|
|
39
|
+
const staleIfError = strategy.staleIfError ?? 0;
|
|
40
|
+
const staleIfErrorDirective = staleIfError > 0 ? `, stale-if-error=${String(staleIfError)}` : "";
|
|
41
|
+
return `public, max-age=${String(strategy.maxAge)}, stale-while-revalidate=${String(strategy.staleWhileRevalidate)}${staleIfErrorDirective}`;
|
|
28
42
|
}
|
|
29
43
|
var requestFor = (key) => new Request(`https://kotao.cache/${encodeURIComponent(key)}`);
|
|
30
44
|
function createCache(opts) {
|
|
@@ -41,7 +55,7 @@ function createCache(opts) {
|
|
|
41
55
|
};
|
|
42
56
|
const write = async (key, value, strategy) => {
|
|
43
57
|
const body = { value, storedAt: now() };
|
|
44
|
-
const ttl = strategy.maxAge + strategy.staleWhileRevalidate;
|
|
58
|
+
const ttl = strategy.maxAge + strategy.staleWhileRevalidate + (strategy.staleIfError ?? 0);
|
|
45
59
|
await cache.put(
|
|
46
60
|
requestFor(key),
|
|
47
61
|
new Response(JSON.stringify(body), {
|
|
@@ -51,7 +65,7 @@ function createCache(opts) {
|
|
|
51
65
|
};
|
|
52
66
|
return {
|
|
53
67
|
raw: cache,
|
|
54
|
-
async run(key, strategy, fn) {
|
|
68
|
+
async run(key, strategy, fn, onStaleIfError) {
|
|
55
69
|
if (strategy.mode === "none") return fn();
|
|
56
70
|
const stored = await read(key);
|
|
57
71
|
if (stored) {
|
|
@@ -62,10 +76,23 @@ function createCache(opts) {
|
|
|
62
76
|
(async () => {
|
|
63
77
|
const fresh = await fn();
|
|
64
78
|
await write(key, fresh, strategy);
|
|
65
|
-
})()
|
|
79
|
+
})().catch(() => void 0)
|
|
66
80
|
);
|
|
67
81
|
return stored.value;
|
|
68
82
|
}
|
|
83
|
+
if (ageSec <= strategy.maxAge + strategy.staleWhileRevalidate + (strategy.staleIfError ?? 0)) {
|
|
84
|
+
try {
|
|
85
|
+
const value2 = await fn();
|
|
86
|
+
opts.waitUntil(write(key, value2, strategy));
|
|
87
|
+
return value2;
|
|
88
|
+
} catch (error) {
|
|
89
|
+
try {
|
|
90
|
+
onStaleIfError?.({ ageSeconds: ageSec, error });
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
return stored.value;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
69
96
|
}
|
|
70
97
|
const value = await fn();
|
|
71
98
|
opts.waitUntil(write(key, value, strategy));
|
|
@@ -609,7 +636,8 @@ function createCartHandler(opts) {
|
|
|
609
636
|
const id = await currentCartId();
|
|
610
637
|
if (!id) return null;
|
|
611
638
|
const data = await opts.storefront.query(CART_QUERY, {
|
|
612
|
-
variables: { cartId: id }
|
|
639
|
+
variables: { cartId: id },
|
|
640
|
+
cache: CacheNone()
|
|
613
641
|
});
|
|
614
642
|
return withCheckoutUrl(data.cart);
|
|
615
643
|
},
|
|
@@ -707,6 +735,12 @@ function appendSetCartIdHeaders(headers, value) {
|
|
|
707
735
|
// src/customer-account/session.ts
|
|
708
736
|
var CUSTOMER_SESSION_COOKIE = "kotao_customer_session";
|
|
709
737
|
var DEFAULT_SESSION_MAX_AGE = 60 * 60 * 24 * 30;
|
|
738
|
+
var HOSTED_CUSTOMER_SESSION_COOKIE = "__Host-kotao_customer_session";
|
|
739
|
+
var HOSTED_CUSTOMER_CSRF_COOKIE = "__Host-kotao_customer_csrf";
|
|
740
|
+
var HOSTED_CUSTOMER_CSRF_HEADER = "x-kotao-csrf-token";
|
|
741
|
+
var MAX_HOSTED_SESSION_MAX_AGE = 60 * 60 * 24 * 365;
|
|
742
|
+
var DEFAULT_HOSTED_SESSION_MAX_AGE = MAX_HOSTED_SESSION_MAX_AGE;
|
|
743
|
+
var MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH = 4096;
|
|
710
744
|
var assertHostname = (hostname) => {
|
|
711
745
|
if (hostname === "" || hostname.startsWith(".") || hostname.endsWith(".")) {
|
|
712
746
|
throw new Error(`invalid shop hostname for the customer session cookie: '${hostname}'`);
|
|
@@ -736,6 +770,48 @@ function readCustomerSessionToken(cookieHeader) {
|
|
|
736
770
|
return null;
|
|
737
771
|
}
|
|
738
772
|
}
|
|
773
|
+
function buildHostedCustomerSessionCookie(token, attrs = {}) {
|
|
774
|
+
if (token === "") throw new Error("hosted customer session token must not be empty");
|
|
775
|
+
const maxAge = attrs.maxAgeSeconds ?? DEFAULT_HOSTED_SESSION_MAX_AGE;
|
|
776
|
+
if (!Number.isInteger(maxAge) || maxAge <= 0 || maxAge > MAX_HOSTED_SESSION_MAX_AGE) {
|
|
777
|
+
throw new Error("hosted customer session Max-Age must be between 1 second and 365 days");
|
|
778
|
+
}
|
|
779
|
+
return `${HOSTED_CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
|
|
780
|
+
}
|
|
781
|
+
function clearHostedCustomerSessionCookie() {
|
|
782
|
+
return `${HOSTED_CUSTOMER_SESSION_COOKIE}=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
|
|
783
|
+
}
|
|
784
|
+
function readHostedCustomerSessionToken(cookieHeader) {
|
|
785
|
+
return readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_SESSION_COOKIE);
|
|
786
|
+
}
|
|
787
|
+
function readHostedCustomerCsrfToken(cookieHeader) {
|
|
788
|
+
const token = readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_CSRF_COOKIE, 43);
|
|
789
|
+
return token !== null && /^[A-Za-z0-9_-]{43}$/.test(token) ? token : null;
|
|
790
|
+
}
|
|
791
|
+
function readLegacyCustomerSessionToken(cookieHeader, options) {
|
|
792
|
+
if (!options.allowLegacy) return null;
|
|
793
|
+
return readBoundedCookie(
|
|
794
|
+
cookieHeader,
|
|
795
|
+
CUSTOMER_SESSION_COOKIE,
|
|
796
|
+
MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
function clearLegacyCustomerSessionCookie(attrs) {
|
|
800
|
+
return clearCustomerSessionCookie(attrs);
|
|
801
|
+
}
|
|
802
|
+
function readBoundedCookie(cookieHeader, name, maxLength = MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH) {
|
|
803
|
+
if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
|
|
804
|
+
const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${name}=`));
|
|
805
|
+
if (match === void 0) return null;
|
|
806
|
+
const raw = match.slice(name.length + 1);
|
|
807
|
+
if (raw === "" || raw.length > maxLength) return null;
|
|
808
|
+
try {
|
|
809
|
+
const decoded = decodeURIComponent(raw);
|
|
810
|
+
return decoded.length <= maxLength ? decoded : null;
|
|
811
|
+
} catch {
|
|
812
|
+
return null;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
739
815
|
|
|
740
816
|
// src/customer-account/types.ts
|
|
741
817
|
var CustomerAccountError = class extends Error {
|
|
@@ -760,7 +836,11 @@ function createCustomerAccountClient(opts) {
|
|
|
760
836
|
}
|
|
761
837
|
const doFetch = opts.fetch ?? fetch;
|
|
762
838
|
const cookieHeader = opts.request.headers.get("cookie");
|
|
763
|
-
const
|
|
839
|
+
const hostedToken = readHostedCustomerSessionToken(cookieHeader);
|
|
840
|
+
const legacyToken = hostedToken === null && (opts.allowLegacySessionForwarding ?? true) ? readCustomerSessionToken(cookieHeader) : null;
|
|
841
|
+
const token = hostedToken ?? legacyToken;
|
|
842
|
+
const sessionCookie = hostedToken !== null ? `${HOSTED_CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(hostedToken)}` : legacyToken !== null ? `${CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(legacyToken)}` : null;
|
|
843
|
+
const configuredShopOrigin = configuredHttpsOrigin(opts.shopOrigin);
|
|
764
844
|
const hydrogenCustomerAccountId = opts.customerAccountId?.trim();
|
|
765
845
|
const hydrogenShopId = opts.shopId?.trim();
|
|
766
846
|
const hasHydrogenCustomerAccount = hydrogenCustomerAccountId !== void 0 && hydrogenCustomerAccountId.length > 0 && hydrogenShopId !== void 0 && hydrogenShopId.length > 0;
|
|
@@ -768,7 +848,8 @@ function createCustomerAccountClient(opts) {
|
|
|
768
848
|
const proxyGet = async (path) => {
|
|
769
849
|
try {
|
|
770
850
|
return await doFetch(`${proxyBase}${path}`, {
|
|
771
|
-
|
|
851
|
+
redirect: "manual",
|
|
852
|
+
headers: sessionCookie !== null ? { cookie: sessionCookie } : {}
|
|
772
853
|
});
|
|
773
854
|
} catch (cause) {
|
|
774
855
|
throw new CustomerAccountError(
|
|
@@ -791,21 +872,45 @@ function createCustomerAccountClient(opts) {
|
|
|
791
872
|
}
|
|
792
873
|
};
|
|
793
874
|
const proxyPost = async (path, body) => {
|
|
875
|
+
const csrf = await csrfHeaders();
|
|
876
|
+
if (csrf === null) return new Response(null, { status: 503 });
|
|
794
877
|
return doFetch(`${proxyBase}${path}`, {
|
|
795
878
|
method: "POST",
|
|
796
|
-
|
|
879
|
+
redirect: "manual",
|
|
880
|
+
headers: { "content-type": "application/json", ...csrf.headers },
|
|
797
881
|
body: JSON.stringify(body)
|
|
798
882
|
});
|
|
799
883
|
};
|
|
800
884
|
const proxyWrite = async (path, method, body) => {
|
|
801
|
-
const
|
|
802
|
-
if (
|
|
885
|
+
const csrf = await csrfHeaders();
|
|
886
|
+
if (csrf === null) return new Response(null, { status: 503 });
|
|
887
|
+
const headers = { "content-type": "application/json", ...csrf.headers };
|
|
803
888
|
return doFetch(`${proxyBase}${path}`, {
|
|
804
889
|
method,
|
|
890
|
+
redirect: "manual",
|
|
805
891
|
headers,
|
|
806
892
|
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
807
893
|
});
|
|
808
894
|
};
|
|
895
|
+
const csrfHeaders = async () => {
|
|
896
|
+
if (configuredShopOrigin === null) return null;
|
|
897
|
+
let csrfToken = readHostedCustomerCsrfToken(cookieHeader);
|
|
898
|
+
if (csrfToken === null) {
|
|
899
|
+
const bootstrap = await doFetch(`${proxyBase}/account/csrf`, {
|
|
900
|
+
redirect: "manual",
|
|
901
|
+
headers: sessionCookie !== null ? { cookie: sessionCookie } : {}
|
|
902
|
+
});
|
|
903
|
+
csrfToken = csrfTokenFromSetCookie(bootstrap.headers);
|
|
904
|
+
if (csrfToken === null) return null;
|
|
905
|
+
}
|
|
906
|
+
return {
|
|
907
|
+
headers: {
|
|
908
|
+
Origin: configuredShopOrigin,
|
|
909
|
+
[HOSTED_CUSTOMER_CSRF_HEADER]: csrfToken,
|
|
910
|
+
cookie: [sessionCookie, `${HOSTED_CUSTOMER_CSRF_COOKIE}=${csrfToken}`].filter((value) => value !== null).join("; ")
|
|
911
|
+
}
|
|
912
|
+
};
|
|
913
|
+
};
|
|
809
914
|
const returnTo = () => {
|
|
810
915
|
const url = new URL(opts.request.url);
|
|
811
916
|
return `${url.pathname}${url.search}`;
|
|
@@ -1045,11 +1150,11 @@ function createCustomerAccountClient(opts) {
|
|
|
1045
1150
|
async requestLoginCode(input) {
|
|
1046
1151
|
try {
|
|
1047
1152
|
const res = await proxyPost("/account/send", { email: input.email });
|
|
1048
|
-
if (res.status === 200) return { status: "sent" };
|
|
1049
|
-
if (res.status === 429) return { status: "rate_limited" };
|
|
1050
|
-
return { status: "error" };
|
|
1153
|
+
if (res.status === 200) return { status: "sent", response: res };
|
|
1154
|
+
if (res.status === 429) return { status: "rate_limited", response: res };
|
|
1155
|
+
return { status: "error", response: res };
|
|
1051
1156
|
} catch {
|
|
1052
|
-
return { status: "error" };
|
|
1157
|
+
return { status: "error", response: new Response(null, { status: 503 }) };
|
|
1053
1158
|
}
|
|
1054
1159
|
},
|
|
1055
1160
|
async verifyLoginCode(input) {
|
|
@@ -1082,18 +1187,23 @@ function createCustomerAccountClient(opts) {
|
|
|
1082
1187
|
await commitHydrogenSession(headers);
|
|
1083
1188
|
}
|
|
1084
1189
|
} else {
|
|
1085
|
-
|
|
1190
|
+
try {
|
|
1191
|
+
return await proxyWrite("/account/logout", "POST");
|
|
1192
|
+
} catch {
|
|
1193
|
+
headers.set("location", "/");
|
|
1194
|
+
}
|
|
1086
1195
|
}
|
|
1087
1196
|
headers.append(
|
|
1088
1197
|
"set-cookie",
|
|
1089
1198
|
clearCustomerSessionCookie({ hostname: shopHostname(opts.request) })
|
|
1090
1199
|
);
|
|
1200
|
+
headers.append("set-cookie", clearHostedCustomerSessionCookie());
|
|
1091
1201
|
return new Response(null, { status: 302, headers });
|
|
1092
1202
|
},
|
|
1093
1203
|
async getAccessToken() {
|
|
1094
1204
|
const directAccessToken = await hydrogenAccessToken();
|
|
1095
1205
|
if (directAccessToken !== null) return directAccessToken;
|
|
1096
|
-
return token;
|
|
1206
|
+
return hasHydrogenCustomerAccount ? token : null;
|
|
1097
1207
|
},
|
|
1098
1208
|
async isLoggedIn() {
|
|
1099
1209
|
if (await hydrogenAccessToken() !== null) return true;
|
|
@@ -1139,6 +1249,26 @@ function randomOAuthToken() {
|
|
|
1139
1249
|
for (const byte of bytes) raw += String.fromCharCode(byte);
|
|
1140
1250
|
return base64UrlEncode(raw);
|
|
1141
1251
|
}
|
|
1252
|
+
function configuredHttpsOrigin(value) {
|
|
1253
|
+
if (!value) return null;
|
|
1254
|
+
try {
|
|
1255
|
+
const candidate = value.includes("://") ? value : `https://${value}`;
|
|
1256
|
+
const url = new URL(candidate);
|
|
1257
|
+
if (url.protocol !== "https:" || url.username || url.password || url.port || url.pathname !== "/")
|
|
1258
|
+
return null;
|
|
1259
|
+
return url.origin;
|
|
1260
|
+
} catch {
|
|
1261
|
+
return null;
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1264
|
+
function csrfTokenFromSetCookie(headers) {
|
|
1265
|
+
const values = "getSetCookie" in headers && typeof headers.getSetCookie === "function" ? headers.getSetCookie() : [headers.get("set-cookie") ?? ""];
|
|
1266
|
+
for (const value of values) {
|
|
1267
|
+
const match = value.match(/(?:^|,\s*)__Host-kotao_customer_csrf=([A-Za-z0-9_-]{43})(?:;|$)/);
|
|
1268
|
+
if (match?.[1]) return match[1];
|
|
1269
|
+
}
|
|
1270
|
+
return null;
|
|
1271
|
+
}
|
|
1142
1272
|
function isHydrogenSessionLike(value) {
|
|
1143
1273
|
return value !== null && typeof value === "object" && "get" in value && "set" in value && typeof value.get === "function" && typeof value.set === "function";
|
|
1144
1274
|
}
|
|
@@ -1354,9 +1484,32 @@ function localizePath(path, locale, options = {}) {
|
|
|
1354
1484
|
}
|
|
1355
1485
|
|
|
1356
1486
|
// src/storefront-client/client.ts
|
|
1487
|
+
var StorefrontQueryTimeoutError = class extends Error {
|
|
1488
|
+
operationName;
|
|
1489
|
+
timeoutMs;
|
|
1490
|
+
constructor(operationName, timeoutMs) {
|
|
1491
|
+
super(`Storefront query ${operationName} timed out after ${String(timeoutMs)}ms`);
|
|
1492
|
+
this.name = "StorefrontQueryTimeoutError";
|
|
1493
|
+
this.operationName = operationName;
|
|
1494
|
+
this.timeoutMs = timeoutMs;
|
|
1495
|
+
}
|
|
1496
|
+
};
|
|
1497
|
+
var StorefrontUpstreamError = class extends Error {
|
|
1498
|
+
operationName;
|
|
1499
|
+
status;
|
|
1500
|
+
cause;
|
|
1501
|
+
constructor(operationName, message, options) {
|
|
1502
|
+
super(message);
|
|
1503
|
+
this.name = "StorefrontUpstreamError";
|
|
1504
|
+
this.operationName = operationName;
|
|
1505
|
+
this.status = options?.status;
|
|
1506
|
+
this.cause = options?.cause;
|
|
1507
|
+
}
|
|
1508
|
+
};
|
|
1357
1509
|
var hashKey = (query, variables) => `sf:${query.replace(/\s+/g, " ").trim()}:${variables ? JSON.stringify(variables) : ""}`;
|
|
1358
1510
|
var COUNTRY_RE = /^[A-Z]{2}$/;
|
|
1359
1511
|
var DEFAULT_HYDROGEN_STOREFRONT_API_VERSION = "2025-01";
|
|
1512
|
+
var DEFAULT_QUERY_TIMEOUT_MS = 5e3;
|
|
1360
1513
|
function endpointForStorefrontApiVersion(endpoint, version) {
|
|
1361
1514
|
if (version === void 0 || version.length === 0) return endpoint;
|
|
1362
1515
|
try {
|
|
@@ -1381,6 +1534,7 @@ function createStorefrontClient(opts) {
|
|
|
1381
1534
|
cache: createCache({ cache: opts.cache, waitUntil: opts.waitUntil }),
|
|
1382
1535
|
fetch: opts.fetch,
|
|
1383
1536
|
defaultStrategy: opts.defaultStrategy,
|
|
1537
|
+
queryTimeoutMs: opts.queryTimeoutMs,
|
|
1384
1538
|
extraHeaders: opts.storefrontHeaders,
|
|
1385
1539
|
i18n
|
|
1386
1540
|
});
|
|
@@ -1391,11 +1545,13 @@ function createStorefrontClient(opts) {
|
|
|
1391
1545
|
function createStorefrontClientCore(opts) {
|
|
1392
1546
|
const doFetch = opts.fetch ?? fetch;
|
|
1393
1547
|
const defaultStrategy = opts.defaultStrategy ?? StorefrontDefaultCache();
|
|
1548
|
+
const defaultQueryTimeoutMs = opts.queryTimeoutMs ?? DEFAULT_QUERY_TIMEOUT_MS;
|
|
1394
1549
|
const tokenHeader = opts.tokenHeader ?? "x-kotao-storefront-token";
|
|
1395
1550
|
const localeKey = opts.locale !== void 0 && opts.locale.length > 0 ? opts.locale : "";
|
|
1396
1551
|
const countryKey = opts.country !== void 0 && COUNTRY_RE.test(opts.country) ? opts.country : "";
|
|
1397
1552
|
const i18n = normalizeStorefrontI18n(opts.i18n, opts.locale, countryKey);
|
|
1398
|
-
const execute = async (document, options) => {
|
|
1553
|
+
const execute = async (document, options, signal, timing) => {
|
|
1554
|
+
const operationStartedAt = timing === void 0 ? 0 : Date.now();
|
|
1399
1555
|
const endpoint = endpointForStorefrontApiVersion(opts.endpoint, options?.storefrontApiVersion);
|
|
1400
1556
|
const headers = {
|
|
1401
1557
|
"content-type": "application/json",
|
|
@@ -1412,13 +1568,67 @@ function createStorefrontClientCore(opts) {
|
|
|
1412
1568
|
if (countryKey.length > 0) {
|
|
1413
1569
|
headers["x-kotao-country"] = countryKey;
|
|
1414
1570
|
}
|
|
1415
|
-
const
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1571
|
+
const operationName = operationNameFromDocument(document);
|
|
1572
|
+
let res;
|
|
1573
|
+
try {
|
|
1574
|
+
res = await doFetch(endpoint, {
|
|
1575
|
+
method: "POST",
|
|
1576
|
+
headers,
|
|
1577
|
+
body: JSON.stringify({ query: document, variables: options?.variables }),
|
|
1578
|
+
...signal === void 0 ? {} : { signal }
|
|
1579
|
+
});
|
|
1580
|
+
} catch (cause) {
|
|
1581
|
+
if (signal?.aborted === true) {
|
|
1582
|
+
const timeoutMs = options?.timeoutMs ?? defaultQueryTimeoutMs;
|
|
1583
|
+
console.error(
|
|
1584
|
+
JSON.stringify({
|
|
1585
|
+
event: "storefront_query_failed",
|
|
1586
|
+
failure: "timeout",
|
|
1587
|
+
operationName,
|
|
1588
|
+
timeoutMs
|
|
1589
|
+
})
|
|
1590
|
+
);
|
|
1591
|
+
throw new StorefrontQueryTimeoutError(operationName, timeoutMs);
|
|
1592
|
+
}
|
|
1593
|
+
console.error(
|
|
1594
|
+
JSON.stringify({
|
|
1595
|
+
event: "storefront_query_failed",
|
|
1596
|
+
failure: "transport",
|
|
1597
|
+
operationName
|
|
1598
|
+
})
|
|
1599
|
+
);
|
|
1600
|
+
throw new StorefrontUpstreamError(operationName, "Storefront API request failed", { cause });
|
|
1601
|
+
}
|
|
1602
|
+
const opName = operationName;
|
|
1603
|
+
let raw;
|
|
1604
|
+
try {
|
|
1605
|
+
raw = await res.text();
|
|
1606
|
+
} catch (cause) {
|
|
1607
|
+
if (signal?.aborted === true) {
|
|
1608
|
+
const timeoutMs = options?.timeoutMs ?? defaultQueryTimeoutMs;
|
|
1609
|
+
console.error(
|
|
1610
|
+
JSON.stringify({
|
|
1611
|
+
event: "storefront_query_failed",
|
|
1612
|
+
failure: "timeout",
|
|
1613
|
+
operationName,
|
|
1614
|
+
timeoutMs
|
|
1615
|
+
})
|
|
1616
|
+
);
|
|
1617
|
+
throw new StorefrontQueryTimeoutError(operationName, timeoutMs);
|
|
1618
|
+
}
|
|
1619
|
+
console.error(
|
|
1620
|
+
JSON.stringify({
|
|
1621
|
+
event: "storefront_query_failed",
|
|
1622
|
+
failure: "response_body",
|
|
1623
|
+
operationName,
|
|
1624
|
+
status: res.status
|
|
1625
|
+
})
|
|
1626
|
+
);
|
|
1627
|
+
throw new StorefrontUpstreamError(operationName, "Storefront API response body failed", {
|
|
1628
|
+
status: res.status,
|
|
1629
|
+
cause
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1422
1632
|
let body;
|
|
1423
1633
|
try {
|
|
1424
1634
|
body = JSON.parse(raw);
|
|
@@ -1426,13 +1636,22 @@ function createStorefrontClientCore(opts) {
|
|
|
1426
1636
|
console.error(
|
|
1427
1637
|
`[storefront] /api/storefront non-JSON response: status=${res.status} content-type=${res.headers.get("content-type") ?? ""} len=${raw.length} op="${opName}" body=${raw.slice(0, 180)}`
|
|
1428
1638
|
);
|
|
1429
|
-
throw new
|
|
1639
|
+
throw new StorefrontUpstreamError(
|
|
1640
|
+
operationName,
|
|
1641
|
+
`Storefront API returned a non-JSON response (status ${String(res.status)})`,
|
|
1642
|
+
{ status: res.status }
|
|
1643
|
+
);
|
|
1430
1644
|
}
|
|
1431
1645
|
if (!res.ok) {
|
|
1432
1646
|
const shopCtx = opts.signedShopContextHeaders !== void 0 ? "present" : "absent";
|
|
1433
1647
|
console.error(
|
|
1434
1648
|
`[storefront] /api/storefront HTTP ${res.status} endpoint=${endpoint} shopCtx=${shopCtx} op="${opName}" body=${raw.slice(0, 180)}`
|
|
1435
1649
|
);
|
|
1650
|
+
throw new StorefrontUpstreamError(
|
|
1651
|
+
operationName,
|
|
1652
|
+
`Storefront API returned HTTP ${String(res.status)}`,
|
|
1653
|
+
{ status: res.status }
|
|
1654
|
+
);
|
|
1436
1655
|
}
|
|
1437
1656
|
if (body.errors?.length) {
|
|
1438
1657
|
console.error(`[storefront] GraphQL query failed: ${JSON.stringify(body.errors)}`);
|
|
@@ -1444,6 +1663,19 @@ function createStorefrontClientCore(opts) {
|
|
|
1444
1663
|
);
|
|
1445
1664
|
throw new Error("Storefront API returned no data");
|
|
1446
1665
|
}
|
|
1666
|
+
if (timing !== void 0) {
|
|
1667
|
+
console.info(
|
|
1668
|
+
JSON.stringify({
|
|
1669
|
+
event: "storefront_operation_timing",
|
|
1670
|
+
operationName,
|
|
1671
|
+
wallTimeMs: Math.max(0, Date.now() - operationStartedAt),
|
|
1672
|
+
cacheStatus: timing.cacheStatus,
|
|
1673
|
+
queryCount: 1,
|
|
1674
|
+
payloadBytes: raw.length,
|
|
1675
|
+
...timing.timeoutMs !== void 0 ? { timeoutMs: timing.timeoutMs } : {}
|
|
1676
|
+
})
|
|
1677
|
+
);
|
|
1678
|
+
}
|
|
1447
1679
|
return body.data;
|
|
1448
1680
|
};
|
|
1449
1681
|
return {
|
|
@@ -1456,10 +1688,27 @@ function createStorefrontClientCore(opts) {
|
|
|
1456
1688
|
query(query, options) {
|
|
1457
1689
|
const strategy = options?.cache ?? defaultStrategy;
|
|
1458
1690
|
const versionKey = options?.storefrontApiVersion ?? "";
|
|
1691
|
+
const operationName = operationNameFromDocument(query);
|
|
1459
1692
|
return opts.cache.run(
|
|
1460
1693
|
`${localeKey}:${countryKey}:${versionKey}:${hashKey(query, options?.variables)}`,
|
|
1461
1694
|
strategy,
|
|
1462
|
-
() =>
|
|
1695
|
+
() => {
|
|
1696
|
+
const timeoutMs = options?.timeoutMs ?? defaultQueryTimeoutMs;
|
|
1697
|
+
return execute(query, { ...options, timeoutMs }, AbortSignal.timeout(timeoutMs), {
|
|
1698
|
+
cacheStatus: "miss",
|
|
1699
|
+
timeoutMs
|
|
1700
|
+
});
|
|
1701
|
+
},
|
|
1702
|
+
({ ageSeconds, error }) => {
|
|
1703
|
+
console.error(
|
|
1704
|
+
JSON.stringify({
|
|
1705
|
+
event: "storefront_query_cache_fallback",
|
|
1706
|
+
operationName,
|
|
1707
|
+
staleAgeSeconds: ageSeconds,
|
|
1708
|
+
failure: storefrontFailureKind(error)
|
|
1709
|
+
})
|
|
1710
|
+
);
|
|
1711
|
+
}
|
|
1463
1712
|
);
|
|
1464
1713
|
},
|
|
1465
1714
|
mutate(mutation2, options) {
|
|
@@ -1467,6 +1716,14 @@ function createStorefrontClientCore(opts) {
|
|
|
1467
1716
|
}
|
|
1468
1717
|
};
|
|
1469
1718
|
}
|
|
1719
|
+
function operationNameFromDocument(document) {
|
|
1720
|
+
return /\b(?:query|mutation)\s+([_A-Za-z][_0-9A-Za-z]*)/u.exec(document)?.[1] ?? "anonymous";
|
|
1721
|
+
}
|
|
1722
|
+
function storefrontFailureKind(error) {
|
|
1723
|
+
if (error instanceof StorefrontQueryTimeoutError) return "timeout";
|
|
1724
|
+
if (error instanceof StorefrontUpstreamError) return "upstream";
|
|
1725
|
+
return "unknown";
|
|
1726
|
+
}
|
|
1470
1727
|
function isHydrogenStorefrontClientOptions(opts) {
|
|
1471
1728
|
return "storeDomain" in opts && "publicStorefrontToken" in opts && "waitUntil" in opts;
|
|
1472
1729
|
}
|
|
@@ -1476,7 +1733,7 @@ function attachHydrogenResult(client) {
|
|
|
1476
1733
|
function headersRecord(headers) {
|
|
1477
1734
|
if (headers === void 0) return {};
|
|
1478
1735
|
const result = {};
|
|
1479
|
-
|
|
1736
|
+
normalizeStorefrontHeaders(headers).forEach((value, key) => {
|
|
1480
1737
|
result[key] = value;
|
|
1481
1738
|
});
|
|
1482
1739
|
return result;
|
|
@@ -1547,6 +1804,24 @@ async function localSignedShopContextHeaders(key, siteId, hostname) {
|
|
|
1547
1804
|
}
|
|
1548
1805
|
var CACHE_NAME = "kotao-storefront-v1";
|
|
1549
1806
|
var CACHE_VERSION_HEADER = "x-kotao-cache-version";
|
|
1807
|
+
var REQUEST_ID_HEADER = "x-kotao-request-id";
|
|
1808
|
+
var DEPLOYMENT_ID_HEADER = "x-kotao-deployment-id";
|
|
1809
|
+
function trustedShopOrigin(value) {
|
|
1810
|
+
if (!value) return void 0;
|
|
1811
|
+
try {
|
|
1812
|
+
const url = new URL(value);
|
|
1813
|
+
if (url.protocol !== "https:" || url.username || url.password || url.port || url.pathname !== "/" || url.search || url.hash) {
|
|
1814
|
+
return void 0;
|
|
1815
|
+
}
|
|
1816
|
+
return url.origin;
|
|
1817
|
+
} catch {
|
|
1818
|
+
return void 0;
|
|
1819
|
+
}
|
|
1820
|
+
}
|
|
1821
|
+
function trustedShopOriginFromHeaders(headers) {
|
|
1822
|
+
if (!headers.has(SHOP_HEADER) || !headers.has(SHOP_SIGNATURE_HEADER)) return void 0;
|
|
1823
|
+
return trustedShopOrigin(headers.get(SHOP_ORIGIN_HEADER));
|
|
1824
|
+
}
|
|
1550
1825
|
var API_LOCALE_RE = /^[a-z]{2,3}(-[a-zA-Z]{2,4})?$/;
|
|
1551
1826
|
var API_COUNTRY_RE = /^[A-Z]{2}$/;
|
|
1552
1827
|
var SAME_ORIGIN_PATH2 = /^\/(?![/\\])/;
|
|
@@ -1596,12 +1871,21 @@ async function createKotaoContext(request, env, executionCtx, deps) {
|
|
|
1596
1871
|
const pathLocale = parseLocale(request);
|
|
1597
1872
|
const localizationCookie = readLocalizationCookie(request.headers.get("cookie"));
|
|
1598
1873
|
const cookieLocale = localizationCookie.locale;
|
|
1599
|
-
const
|
|
1874
|
+
const autoLanguage = autoRedirectEnabled(request.headers, AUTO_REDIRECT_LANGUAGE_HEADER);
|
|
1875
|
+
const autoCountry = autoRedirectEnabled(request.headers, AUTO_REDIRECT_COUNTRY_HEADER);
|
|
1876
|
+
const browserLocale = autoLanguage ? localeFromAcceptLanguage(request.headers.get("accept-language")) : null;
|
|
1600
1877
|
const selectedLocale = pathLocale ?? cookieLocale ?? browserLocale?.split("-")[0] ?? null;
|
|
1601
1878
|
const apiLocale = selectedLocale !== null && API_LOCALE_RE.test(selectedLocale) ? selectedLocale : void 0;
|
|
1602
1879
|
const cookieCountry = localizationCookie.country !== null && API_COUNTRY_RE.test(localizationCookie.country) ? localizationCookie.country : null;
|
|
1603
|
-
const geoCountry = geo?.country?.trim().toUpperCase() ?? null;
|
|
1880
|
+
const geoCountry = autoCountry ? geo?.country?.trim().toUpperCase() ?? null : null;
|
|
1604
1881
|
const apiCountry = cookieCountry ?? (geoCountry !== null && API_COUNTRY_RE.test(geoCountry) ? geoCountry : null);
|
|
1882
|
+
const extraHeaders = {};
|
|
1883
|
+
const requestId = request.headers.get(REQUEST_ID_HEADER)?.trim();
|
|
1884
|
+
if (requestId !== void 0 && requestId.length > 0) extraHeaders[REQUEST_ID_HEADER] = requestId;
|
|
1885
|
+
const deploymentId = request.headers.get(DEPLOYMENT_ID_HEADER)?.trim();
|
|
1886
|
+
if (deploymentId !== void 0 && deploymentId.length > 0) {
|
|
1887
|
+
extraHeaders[DEPLOYMENT_ID_HEADER] = deploymentId;
|
|
1888
|
+
}
|
|
1605
1889
|
const storefront = createStorefrontClient({
|
|
1606
1890
|
endpoint: resolvedEnv.STOREFRONT_API_ENDPOINT,
|
|
1607
1891
|
token: resolvedEnv.STOREFRONT_API_TOKEN,
|
|
@@ -1610,21 +1894,34 @@ async function createKotaoContext(request, env, executionCtx, deps) {
|
|
|
1610
1894
|
...signedShopContextHeaders ? { signedShopContextHeaders } : {},
|
|
1611
1895
|
...apiLocale !== void 0 ? { locale: apiLocale } : {},
|
|
1612
1896
|
...apiCountry !== null ? { country: apiCountry } : {},
|
|
1897
|
+
...Object.keys(extraHeaders).length > 0 ? { extraHeaders } : {},
|
|
1613
1898
|
cache
|
|
1614
1899
|
});
|
|
1900
|
+
const eventHeaders = new Headers(signedShopContextHeaders);
|
|
1901
|
+
if (apiLocale !== void 0) eventHeaders.set("x-kotao-locale", apiLocale);
|
|
1902
|
+
if (apiCountry !== null) eventHeaders.set("x-kotao-country", apiCountry);
|
|
1903
|
+
for (const [name, value] of Object.entries(extraHeaders)) eventHeaders.set(name, value);
|
|
1904
|
+
const events = createEventsClient({
|
|
1905
|
+
baseUrl: resolvedEnv.STOREFRONT_API_ENDPOINT,
|
|
1906
|
+
fetch,
|
|
1907
|
+
defaultHeaders: eventHeaders
|
|
1908
|
+
});
|
|
1615
1909
|
const cart = createCartHandler({ request, storefront });
|
|
1616
1910
|
const contextSession = withSessionPresenceHint(
|
|
1617
1911
|
deps?.session,
|
|
1618
|
-
readCustomerSessionToken(request.headers.get("cookie")) !== null
|
|
1912
|
+
readHostedCustomerSessionToken(request.headers.get("cookie")) !== null || readCustomerSessionToken(request.headers.get("cookie")) !== null
|
|
1619
1913
|
);
|
|
1620
1914
|
const customerAccount = createCustomerAccountClient({
|
|
1621
1915
|
request,
|
|
1622
1916
|
customerAccountId: resolvedEnv.PUBLIC_CUSTOMER_ACCOUNT_API_CLIENT_ID,
|
|
1623
1917
|
shopId: resolvedEnv.SHOP_ID,
|
|
1624
|
-
session: contextSession
|
|
1918
|
+
session: contextSession,
|
|
1919
|
+
shopOrigin: trustedShopOriginFromHeaders(request.headers) ?? (inboundShop === null && inboundShopSignature === null ? trustedShopOrigin(resolvedEnv.STOREFRONT_SHOP_ORIGIN) : void 0)
|
|
1625
1920
|
});
|
|
1921
|
+
const settingsEndpoint = `${resolvedEnv.STOREFRONT_API_ENDPOINT.replace(/\/+$/, "")}/settings`;
|
|
1626
1922
|
return {
|
|
1627
1923
|
storefront,
|
|
1924
|
+
events,
|
|
1628
1925
|
cart,
|
|
1629
1926
|
customerAccount,
|
|
1630
1927
|
geo,
|
|
@@ -1633,7 +1930,13 @@ async function createKotaoContext(request, env, executionCtx, deps) {
|
|
|
1633
1930
|
// Cookie-presence hint only — the theme cannot validate the HMAC; the authoritative check is the proxy.
|
|
1634
1931
|
session: contextSession,
|
|
1635
1932
|
env: resolvedEnv,
|
|
1636
|
-
waitUntil
|
|
1933
|
+
waitUntil,
|
|
1934
|
+
loadThemeSettings: (opts) => fetchThemeSettings({
|
|
1935
|
+
endpoint: settingsEndpoint,
|
|
1936
|
+
allowCrossOrigin: true,
|
|
1937
|
+
...signedShopContextHeaders ? { shopContextHeaders: signedShopContextHeaders } : {},
|
|
1938
|
+
...opts?.fetch ? { fetch: opts.fetch } : {}
|
|
1939
|
+
})
|
|
1637
1940
|
};
|
|
1638
1941
|
}
|
|
1639
1942
|
function withSessionPresenceHint(session, isLoggedIn) {
|
|
@@ -1685,6 +1988,6 @@ function createEphemeralSession(isLoggedIn) {
|
|
|
1685
1988
|
};
|
|
1686
1989
|
}
|
|
1687
1990
|
|
|
1688
|
-
export { CART_ID_COOKIE, CHECKOUT_CONSENT_CATEGORIES, CHECKOUT_CONSENT_PARAM_PREFIX, CHECKOUT_DESIGN_TOKEN_INPUTS, CUSTOMER_SESSION_COOKIE, CacheCustom, CacheLong, CacheNone, CacheShort, CustomerAccountError, DEFAULT_SESSION_MAX_AGE, GEO_HEADER, GEO_SIGNATURE_HEADER, LOCALIZATION_COOKIE, ROUTING_LOCALE_HEADER, ROUTING_ORIGINAL_PATHNAME_HEADER, StorefrontDefaultCache, buildCartIdCookie, buildCustomerSessionCookie, buildLocalizationCookie, cartGetIdDefault, cartSetIdDefault, clearCustomerSessionCookie, createCache, createCartHandler, createCustomerAccountClient, createKotaoContext, createStorefrontClient, createWithCache, decodeCheckoutConsent, encodeCheckoutConsent, extractCheckoutDesignTokens, generateCacheControlHeader, isLocalePathSegment, localeFromAcceptLanguage, localeFromPathname, localeFromRequest, localizePath, originalPathnameFromRequest, readCartIdCookie, readCustomerSessionToken, readLocalizationCookie, resolveCheckoutUrl, shopHostname, signGeo, stripLocalePrefixFromPathname, stripLocalePrefixFromRequest, verifyGeo };
|
|
1689
|
-
//# sourceMappingURL=chunk-
|
|
1690
|
-
//# sourceMappingURL=chunk-
|
|
1991
|
+
export { CART_ID_COOKIE, CHECKOUT_CONSENT_CATEGORIES, CHECKOUT_CONSENT_PARAM_PREFIX, CHECKOUT_DESIGN_TOKEN_INPUTS, CUSTOMER_SESSION_COOKIE, CacheCustom, CacheLong, CacheNone, CacheShort, CustomerAccountError, DEFAULT_HOSTED_SESSION_MAX_AGE, DEFAULT_SESSION_MAX_AGE, GEO_HEADER, GEO_SIGNATURE_HEADER, HOSTED_CUSTOMER_CSRF_COOKIE, HOSTED_CUSTOMER_CSRF_HEADER, HOSTED_CUSTOMER_SESSION_COOKIE, LOCALIZATION_COOKIE, MAX_HOSTED_SESSION_MAX_AGE, MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH, ROUTING_LOCALE_HEADER, ROUTING_ORIGINAL_PATHNAME_HEADER, StorefrontDefaultCache, StorefrontQueryTimeoutError, StorefrontUpstreamError, buildCartIdCookie, buildCustomerSessionCookie, buildHostedCustomerSessionCookie, buildLocalizationCookie, cartGetIdDefault, cartSetIdDefault, clearCustomerSessionCookie, clearHostedCustomerSessionCookie, clearLegacyCustomerSessionCookie, createCache, createCartHandler, createCustomerAccountClient, createKotaoContext, createStorefrontClient, createWithCache, decodeCheckoutConsent, encodeCheckoutConsent, extractCheckoutDesignTokens, generateCacheControlHeader, isLocalePathSegment, localeFromAcceptLanguage, localeFromPathname, localeFromRequest, localizePath, originalPathnameFromRequest, readCartIdCookie, readCustomerSessionToken, readHostedCustomerCsrfToken, readHostedCustomerSessionToken, readLegacyCustomerSessionToken, readLocalizationCookie, resolveCheckoutUrl, shopHostname, signGeo, stripLocalePrefixFromPathname, stripLocalePrefixFromRequest, trustedShopOriginFromHeaders, verifyGeo };
|
|
1992
|
+
//# sourceMappingURL=chunk-4TEFGD42.js.map
|
|
1993
|
+
//# sourceMappingURL=chunk-4TEFGD42.js.map
|