@kotao/storefront 0.2.4 → 0.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +50 -2
  2. package/dist/bridge-ZKbKqgFd.d.ts +239 -0
  3. package/dist/cart-documents-BLavRDiu.d.ts +89 -0
  4. package/dist/cart-documents.d.ts +1 -2
  5. package/dist/cart-documents.js +1 -1
  6. package/dist/{chunk-M7BPQ54D.js → chunk-2MRB6SMP.js} +4 -3
  7. package/dist/chunk-2MRB6SMP.js.map +1 -0
  8. package/dist/chunk-CKGI3Y7L.js +19 -0
  9. package/dist/chunk-CKGI3Y7L.js.map +1 -0
  10. package/dist/{chunk-4TEFGD42.js → chunk-EG34HLSX.js} +209 -162
  11. package/dist/chunk-EG34HLSX.js.map +1 -0
  12. package/dist/chunk-O6YZEY7X.js +1382 -0
  13. package/dist/chunk-O6YZEY7X.js.map +1 -0
  14. package/dist/{chunk-7MTCGXIG.js → chunk-R4N565GX.js} +8 -4
  15. package/dist/chunk-R4N565GX.js.map +1 -0
  16. package/dist/{chunk-XMTWFJCZ.js → chunk-RFM27BKZ.js} +31 -7
  17. package/dist/chunk-RFM27BKZ.js.map +1 -0
  18. package/dist/{chunk-MYDKIJRH.js → chunk-SVMYFYIA.js} +2 -2
  19. package/dist/{chunk-MYDKIJRH.js.map → chunk-SVMYFYIA.js.map} +1 -1
  20. package/dist/{chunk-H3D7BAOL.js → chunk-VOTBNOWH.js} +21 -3
  21. package/dist/chunk-VOTBNOWH.js.map +1 -0
  22. package/dist/{chunk-PXVDVUFX.js → chunk-W74FGUZH.js} +10 -3
  23. package/dist/chunk-W74FGUZH.js.map +1 -0
  24. package/dist/{chunk-2IWNUDSZ.js → chunk-WNXI3MPM.js} +2 -2
  25. package/dist/chunk-WNXI3MPM.js.map +1 -0
  26. package/dist/chunk-XXNCFWXT.js +2118 -0
  27. package/dist/chunk-XXNCFWXT.js.map +1 -0
  28. package/dist/{client-bsiNPHBi.d.ts → client-CwOPPpFF.d.ts} +11 -1
  29. package/dist/{createCartHandler-C4RrPwSG.d.ts → createCartHandler-7DdKB-GF.d.ts} +1 -1
  30. package/dist/custom-css-Bl7Ur3-H.d.ts +6 -0
  31. package/dist/editor.d.ts +57 -104
  32. package/dist/editor.js +270 -1
  33. package/dist/editor.js.map +1 -1
  34. package/dist/events-react.d.ts +1 -1
  35. package/dist/events-react.js +1 -1
  36. package/dist/events.d.ts +3 -3
  37. package/dist/events.js +1 -1
  38. package/dist/{fetch-M3Y-fQrW.d.ts → fetch-Bq_cc8_G.d.ts} +5 -0
  39. package/dist/hydrogen-Bu7k0kE4.d.ts +259 -0
  40. package/dist/index.d.ts +74 -51
  41. package/dist/index.js +19 -15
  42. package/dist/index.js.map +1 -1
  43. package/dist/react-router.d.ts +30 -9
  44. package/dist/react-router.js +16 -7
  45. package/dist/react-router.js.map +1 -1
  46. package/dist/react.d.ts +79 -11
  47. package/dist/react.js +279 -10
  48. package/dist/react.js.map +1 -1
  49. package/dist/{routing-sEonP93J.d.ts → routing-Bz3Cg0BW.d.ts} +36 -6
  50. package/dist/seo.d.ts +7 -4
  51. package/dist/seo.js +2 -2
  52. package/dist/settings.d.ts +14 -4
  53. package/dist/settings.js +2 -2
  54. package/dist/{shop-BJSvtmnV.d.ts → shop-CnrnSAJw.d.ts} +33 -6
  55. package/dist/{store-CtCWHI8H.d.ts → store-DO08fzJi.d.ts} +1 -1
  56. package/dist/storefront-api-types.d.ts +12 -0
  57. package/dist/{types-BDhHWZsP.d.ts → types-BkY0yET-.d.ts} +3 -3
  58. package/dist/{types-bcbQzx87.d.ts → types-DZX8ScsJ.d.ts} +2 -0
  59. package/package.json +4 -4
  60. package/dist/cart-documents-CwwRTvm8.d.ts +0 -21
  61. package/dist/chunk-2IWNUDSZ.js.map +0 -1
  62. package/dist/chunk-4TEFGD42.js.map +0 -1
  63. package/dist/chunk-7MTCGXIG.js.map +0 -1
  64. package/dist/chunk-H3D7BAOL.js.map +0 -1
  65. package/dist/chunk-M7BPQ54D.js.map +0 -1
  66. package/dist/chunk-PXVDVUFX.js.map +0 -1
  67. package/dist/chunk-PXZ737N3.js +0 -439
  68. package/dist/chunk-PXZ737N3.js.map +0 -1
  69. package/dist/chunk-XMTWFJCZ.js.map +0 -1
@@ -1,7 +1,9 @@
1
1
  import { CONSENT_BUCKETS, readConsentCookie, CART_FORM_ACTIONS } from './chunk-OGWYTYYS.js';
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';
2
+ import { fetchThemeSettings } from './chunk-2MRB6SMP.js';
3
+ import { encodeUtf8Base64Url, toBase64Url, fromBase64Url, decodeBase64UrlUtf8 } from './chunk-CKGI3Y7L.js';
4
+ import { createEventsClient, normalizeStorefrontHeaders } from './chunk-R4N565GX.js';
5
+ import { HOSTED_SURFACE_DESIGN_INPUTS, MARKET_ID_HEADER, MARKET_DEFAULT_LOCALE_HEADER, MARKET_CANONICAL_URL_HEADER, MARKET_ROOT_URLS_HEADER, MARKET_PATH_PREFIX_HEADER, MARKET_THEME_ID_HEADER, MARKET_SETTINGS_ENVIRONMENT_HEADER, MARKET_ALTERNATE_LOCALES_HEADER, SHOP_HEADER, SHOP_SIGNATURE_HEADER, SHOP_ORIGIN_HEADER, autoRedirectEnabled, AUTO_REDIRECT_COUNTRY_HEADER, signShopContext } from '@kotao/storefront-contracts';
6
+ export { MARKET_ALTERNATE_LOCALES_HEADER, MARKET_CANONICAL_URL_HEADER, MARKET_DEFAULT_LOCALE_HEADER, MARKET_ID_HEADER, MARKET_PATH_PREFIX_HEADER, MARKET_ROOT_URLS_HEADER, MARKET_SETTINGS_ENVIRONMENT_HEADER, MARKET_THEME_ID_HEADER } from '@kotao/storefront-contracts';
5
7
 
6
8
  // src/cache/cache.ts
7
9
  var DEFAULT_STALE_IF_ERROR_SECONDS = 300;
@@ -115,6 +117,87 @@ function buildCartIdCookie(cartId) {
115
117
  return `${CART_ID_COOKIE}=${encodeURIComponent(cartId)}; Path=/; Max-Age=${CART_MAX_AGE}; SameSite=Lax; Secure; HttpOnly`;
116
118
  }
117
119
 
120
+ // src/customer-account/session.ts
121
+ var CUSTOMER_SESSION_COOKIE = "kotao_customer_session";
122
+ var DEFAULT_SESSION_MAX_AGE = 60 * 60 * 24 * 30;
123
+ var HOSTED_CUSTOMER_SESSION_COOKIE = "__Host-kotao_customer_session";
124
+ var HOSTED_CUSTOMER_CSRF_COOKIE = "__Host-kotao_customer_csrf";
125
+ var HOSTED_CUSTOMER_CSRF_HEADER = "x-kotao-csrf-token";
126
+ var MAX_HOSTED_SESSION_MAX_AGE = 60 * 60 * 24 * 365;
127
+ var DEFAULT_HOSTED_SESSION_MAX_AGE = MAX_HOSTED_SESSION_MAX_AGE;
128
+ var MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH = 4096;
129
+ var assertHostname = (hostname) => {
130
+ if (hostname === "" || hostname.startsWith(".") || hostname.endsWith(".")) {
131
+ throw new Error(`invalid shop hostname for the customer session cookie: '${hostname}'`);
132
+ }
133
+ };
134
+ function shopHostname(request) {
135
+ return new URL(request.url).hostname;
136
+ }
137
+ function buildCustomerSessionCookie(token, attrs) {
138
+ assertHostname(attrs.hostname);
139
+ const maxAge = attrs.maxAgeSeconds ?? DEFAULT_SESSION_MAX_AGE;
140
+ return `${CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Domain=${attrs.hostname}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
141
+ }
142
+ function clearCustomerSessionCookie(attrs) {
143
+ assertHostname(attrs.hostname);
144
+ return `${CUSTOMER_SESSION_COOKIE}=; Domain=${attrs.hostname}; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
145
+ }
146
+ function readCustomerSessionToken(cookieHeader) {
147
+ if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
148
+ const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${CUSTOMER_SESSION_COOKIE}=`));
149
+ if (match === void 0) return null;
150
+ const raw = match.slice(CUSTOMER_SESSION_COOKIE.length + 1);
151
+ if (raw === "") return null;
152
+ try {
153
+ return decodeURIComponent(raw);
154
+ } catch {
155
+ return null;
156
+ }
157
+ }
158
+ function buildHostedCustomerSessionCookie(token, attrs = {}) {
159
+ if (token === "") throw new Error("hosted customer session token must not be empty");
160
+ const maxAge = attrs.maxAgeSeconds ?? DEFAULT_HOSTED_SESSION_MAX_AGE;
161
+ if (!Number.isInteger(maxAge) || maxAge <= 0 || maxAge > MAX_HOSTED_SESSION_MAX_AGE) {
162
+ throw new Error("hosted customer session Max-Age must be between 1 second and 365 days");
163
+ }
164
+ return `${HOSTED_CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
165
+ }
166
+ function clearHostedCustomerSessionCookie() {
167
+ return `${HOSTED_CUSTOMER_SESSION_COOKIE}=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
168
+ }
169
+ function readHostedCustomerSessionToken(cookieHeader) {
170
+ return readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_SESSION_COOKIE);
171
+ }
172
+ function readHostedCustomerCsrfToken(cookieHeader) {
173
+ const token = readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_CSRF_COOKIE, 43);
174
+ return token !== null && /^[A-Za-z0-9_-]{43}$/.test(token) ? token : null;
175
+ }
176
+ function readLegacyCustomerSessionToken(cookieHeader, options) {
177
+ if (!options.allowLegacy) return null;
178
+ return readBoundedCookie(
179
+ cookieHeader,
180
+ CUSTOMER_SESSION_COOKIE,
181
+ MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH
182
+ );
183
+ }
184
+ function clearLegacyCustomerSessionCookie(attrs) {
185
+ return clearCustomerSessionCookie(attrs);
186
+ }
187
+ function readBoundedCookie(cookieHeader, name, maxLength = MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH) {
188
+ if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
189
+ const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${name}=`));
190
+ if (match === void 0) return null;
191
+ const raw = match.slice(name.length + 1);
192
+ if (raw === "" || raw.length > maxLength) return null;
193
+ try {
194
+ const decoded = decodeURIComponent(raw);
195
+ return decoded.length <= maxLength ? decoded : null;
196
+ } catch {
197
+ return null;
198
+ }
199
+ }
200
+
118
201
  // src/checkout/consent.ts
119
202
  var PARAM_PREFIX = "consent_";
120
203
  var VALID_PARAM_VALUES = /* @__PURE__ */ new Set(["0", "1"]);
@@ -214,51 +297,18 @@ function assertNoZoneIdentityLeak(url) {
214
297
  }
215
298
  }
216
299
  }
217
-
218
- // src/checkout/design-tokens.ts
219
- var CHECKOUT_DESIGN_TOKEN_INPUTS = [
220
- {
221
- type: "url",
222
- name: "checkoutLogoUrl",
223
- label: "Checkout logo URL"
224
- },
225
- {
226
- type: "text",
227
- name: "checkoutLogoAlt",
228
- label: "Checkout logo alt text",
229
- defaultValue: ""
230
- },
231
- {
232
- type: "color",
233
- name: "checkoutColorAccent",
234
- label: "Checkout accent color",
235
- defaultValue: "#005bd3"
236
- },
237
- {
238
- type: "color",
239
- name: "checkoutColorBackground",
240
- label: "Checkout background color",
241
- defaultValue: "#ffffff"
242
- },
243
- {
244
- type: "color",
245
- name: "checkoutColorForeground",
246
- label: "Checkout foreground color",
247
- defaultValue: "#111827"
248
- },
249
- {
250
- type: "font",
251
- name: "checkoutFontBody",
252
- label: "Checkout body font",
253
- defaultValue: "Inter"
254
- },
255
- {
256
- type: "font",
257
- name: "checkoutFontHeading",
258
- label: "Checkout heading font",
259
- defaultValue: "Inter"
260
- }
261
- ];
300
+ var CHECKOUT_TOKEN_DEFAULTS = {
301
+ checkoutLogoAlt: "",
302
+ checkoutColorAccent: "#005bd3",
303
+ checkoutColorBackground: "#ffffff",
304
+ checkoutColorForeground: "#111827",
305
+ checkoutFontBody: "Inter",
306
+ checkoutFontHeading: "Inter"
307
+ };
308
+ var CHECKOUT_DESIGN_TOKEN_INPUTS = HOSTED_SURFACE_DESIGN_INPUTS.map((input) => ({
309
+ ...input,
310
+ ...input.name in CHECKOUT_TOKEN_DEFAULTS ? { defaultValue: CHECKOUT_TOKEN_DEFAULTS[input.name] } : {}
311
+ }));
262
312
  function extractCheckoutDesignTokens(snapshot) {
263
313
  const global = snapshot.global;
264
314
  const logoUrl = optionalString(global["checkoutLogoUrl"], "checkoutLogoUrl");
@@ -316,6 +366,7 @@ var CART_FRAGMENT = (
316
366
  email
317
367
  phone
318
368
  countryCode
369
+ companyLocationId
319
370
  }
320
371
  note
321
372
  attributes {
@@ -575,6 +626,8 @@ function createCartHandler(opts) {
575
626
  cartId = void 0;
576
627
  }
577
628
  const consent = readConsentCookie(request?.headers.get("cookie"));
629
+ const cookieHeader = request?.headers.get("cookie");
630
+ const customerAccessToken = readHostedCustomerSessionToken(cookieHeader) ?? readCustomerSessionToken(cookieHeader);
578
631
  const currentCartId = async () => {
579
632
  if (cartId !== void 0) return cartId;
580
633
  cartId = await getCartId() ?? null;
@@ -611,9 +664,16 @@ function createCartHandler(opts) {
611
664
  return headers;
612
665
  };
613
666
  const create = async (input = {}) => {
667
+ const effectiveInput = customerAccessToken === null ? input : {
668
+ ...input,
669
+ buyerIdentity: {
670
+ ...input.buyerIdentity,
671
+ customerAccessToken: input.buyerIdentity?.customerAccessToken ?? customerAccessToken
672
+ }
673
+ };
614
674
  const data = await opts.storefront.mutate(
615
675
  CART_CREATE_MUTATION,
616
- { variables: { input } }
676
+ { variables: { input: effectiveInput } }
617
677
  );
618
678
  return withCookie(data.cartCreate);
619
679
  };
@@ -732,87 +792,6 @@ function appendSetCartIdHeaders(headers, value) {
732
792
  }
733
793
  }
734
794
 
735
- // src/customer-account/session.ts
736
- var CUSTOMER_SESSION_COOKIE = "kotao_customer_session";
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;
744
- var assertHostname = (hostname) => {
745
- if (hostname === "" || hostname.startsWith(".") || hostname.endsWith(".")) {
746
- throw new Error(`invalid shop hostname for the customer session cookie: '${hostname}'`);
747
- }
748
- };
749
- function shopHostname(request) {
750
- return new URL(request.url).hostname;
751
- }
752
- function buildCustomerSessionCookie(token, attrs) {
753
- assertHostname(attrs.hostname);
754
- const maxAge = attrs.maxAgeSeconds ?? DEFAULT_SESSION_MAX_AGE;
755
- return `${CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Domain=${attrs.hostname}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
756
- }
757
- function clearCustomerSessionCookie(attrs) {
758
- assertHostname(attrs.hostname);
759
- return `${CUSTOMER_SESSION_COOKIE}=; Domain=${attrs.hostname}; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
760
- }
761
- function readCustomerSessionToken(cookieHeader) {
762
- if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
763
- const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${CUSTOMER_SESSION_COOKIE}=`));
764
- if (match === void 0) return null;
765
- const raw = match.slice(CUSTOMER_SESSION_COOKIE.length + 1);
766
- if (raw === "") return null;
767
- try {
768
- return decodeURIComponent(raw);
769
- } catch {
770
- return null;
771
- }
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
- }
815
-
816
795
  // src/customer-account/types.ts
817
796
  var CustomerAccountError = class extends Error {
818
797
  code;
@@ -1294,22 +1273,6 @@ function idTokenNonce(idToken) {
1294
1273
  }
1295
1274
  }
1296
1275
 
1297
- // src/geo/base64url.ts
1298
- var toBase64Url = (bytes) => {
1299
- let bin = "";
1300
- for (const b of bytes) bin += String.fromCharCode(b);
1301
- return btoa(bin).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
1302
- };
1303
- var fromBase64Url = (s) => {
1304
- const b64 = s.replace(/-/g, "+").replace(/_/g, "/");
1305
- const bin = atob(b64);
1306
- const out = new Uint8Array(bin.length);
1307
- for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
1308
- return out;
1309
- };
1310
- var encodeUtf8Base64Url = (text) => toBase64Url(new TextEncoder().encode(text));
1311
- var decodeBase64UrlUtf8 = (s) => new TextDecoder().decode(fromBase64Url(s));
1312
-
1313
1276
  // src/geo/geo.ts
1314
1277
  var GEO_HEADER = "x-kotao-geo";
1315
1278
  var GEO_SIGNATURE_HEADER = "x-kotao-geo-signature";
@@ -1384,7 +1347,10 @@ function splitFirstPathSegment(pathname) {
1384
1347
  const withoutSlash = pathname.slice(1);
1385
1348
  const slash = withoutSlash.indexOf("/");
1386
1349
  if (slash === -1) return { segment: withoutSlash, rest: "" };
1387
- return { segment: withoutSlash.slice(0, slash), rest: withoutSlash.slice(slash) };
1350
+ return {
1351
+ segment: withoutSlash.slice(0, slash),
1352
+ rest: withoutSlash.slice(slash)
1353
+ };
1388
1354
  }
1389
1355
  function isLocalePathSegment(segment) {
1390
1356
  return LOCALE_SEGMENT_RE.test(segment);
@@ -1475,12 +1441,16 @@ function localizePath(path, locale, options = {}) {
1475
1441
  const targetLocale = normalizeLocale(locale);
1476
1442
  const primaryLocale = normalizeLocale(options.primaryLocale);
1477
1443
  const url = new URL(path.startsWith("/") ? path : "/", "https://storefront.local");
1478
- const stripped = stripLocalePrefixFromPathname(url.pathname).pathname;
1444
+ const marketPrefix = options.marketPathPrefix !== null && options.marketPathPrefix !== void 0 && options.marketPathPrefix.startsWith("/") ? options.marketPathPrefix.replace(/\/+$/u, "") : null;
1445
+ const withoutMarket = marketPrefix !== null && (url.pathname === marketPrefix || url.pathname.startsWith(`${marketPrefix}/`)) ? url.pathname.slice(marketPrefix.length) || "/" : url.pathname;
1446
+ const stripped = stripLocalePrefixFromPathname(withoutMarket).pathname;
1479
1447
  const suffix = `${url.search}${url.hash}`;
1448
+ const marketBase = marketPrefix ?? "";
1480
1449
  if (targetLocale === null || primaryLocale !== null && targetLocale === primaryLocale) {
1481
- return `${stripped}${suffix}`;
1450
+ return `${marketBase}${stripped}${suffix}` || "/";
1482
1451
  }
1483
- return `${stripped === "/" ? `/${targetLocale}` : `/${targetLocale}${stripped}`}${suffix}`;
1452
+ const localized = stripped === "/" ? `/${targetLocale}` : `/${targetLocale}${stripped}`;
1453
+ return `${marketBase}${localized}${suffix}`;
1484
1454
  }
1485
1455
 
1486
1456
  // src/storefront-client/client.ts
@@ -1802,6 +1772,40 @@ async function localSignedShopContextHeaders(key, siteId, hostname) {
1802
1772
  );
1803
1773
  return { [SHOP_HEADER]: payload, [SHOP_SIGNATURE_HEADER]: signature };
1804
1774
  }
1775
+ function marketContextFromHeaders(headers) {
1776
+ const id = headers.get(MARKET_ID_HEADER)?.trim();
1777
+ const defaultLocale = headers.get(MARKET_DEFAULT_LOCALE_HEADER)?.trim();
1778
+ const canonicalUrl = headers.get(MARKET_CANONICAL_URL_HEADER)?.trim();
1779
+ const encodedRoots = headers.get(MARKET_ROOT_URLS_HEADER);
1780
+ if (!id || !defaultLocale || !canonicalUrl?.startsWith("https://") || encodedRoots === null || encodedRoots.length > 32768) {
1781
+ return null;
1782
+ }
1783
+ let rootUrls;
1784
+ try {
1785
+ const parsed = JSON.parse(encodedRoots);
1786
+ if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(
1787
+ (root) => typeof root === "object" && root !== null && "locale" in root && typeof root.locale === "string" && "url" in root && typeof root.url === "string" && root.url.startsWith("https://")
1788
+ )) {
1789
+ return null;
1790
+ }
1791
+ rootUrls = parsed;
1792
+ } catch {
1793
+ return null;
1794
+ }
1795
+ const pathPrefix = headers.get(MARKET_PATH_PREFIX_HEADER)?.trim();
1796
+ const themeId = headers.get(MARKET_THEME_ID_HEADER)?.trim();
1797
+ const settingsEnvironmentHandle = headers.get(MARKET_SETTINGS_ENVIRONMENT_HEADER)?.trim();
1798
+ return {
1799
+ id,
1800
+ pathPrefix: pathPrefix ? pathPrefix : null,
1801
+ defaultLocale,
1802
+ alternateLocales: headers.get(MARKET_ALTERNATE_LOCALES_HEADER)?.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0) ?? [],
1803
+ rootUrls,
1804
+ canonicalUrl,
1805
+ themeId: themeId ? themeId : null,
1806
+ settingsEnvironmentHandle: settingsEnvironmentHandle ? settingsEnvironmentHandle : null
1807
+ };
1808
+ }
1805
1809
  var CACHE_NAME = "kotao-storefront-v1";
1806
1810
  var CACHE_VERSION_HEADER = "x-kotao-cache-version";
1807
1811
  var REQUEST_ID_HEADER = "x-kotao-request-id";
@@ -1842,6 +1846,36 @@ function resolveStorefrontApiEndpoint(endpoint, requestUrl) {
1842
1846
  return new URL("/api/storefront", requestUrl).toString();
1843
1847
  return endpoint;
1844
1848
  }
1849
+ var STOREFRONT_API_PROTECTED_HEADERS = [
1850
+ SHOP_HEADER,
1851
+ SHOP_ORIGIN_HEADER,
1852
+ SHOP_SIGNATURE_HEADER,
1853
+ "x-kotao-locale",
1854
+ "x-kotao-country",
1855
+ REQUEST_ID_HEADER,
1856
+ DEPLOYMENT_ID_HEADER
1857
+ ];
1858
+ function createStorefrontApiFetch(endpoint, defaultHeaders) {
1859
+ const base = new URL(endpoint);
1860
+ const basePath = base.pathname.replace(/\/+$/, "") || "/";
1861
+ return async (input, init) => {
1862
+ const inputUrl = input instanceof Request ? input.url : String(input);
1863
+ const target = new URL(inputUrl, base);
1864
+ const withinBasePath = basePath === "/" || target.pathname === basePath || target.pathname.startsWith(`${basePath}/`);
1865
+ if (target.username !== "" || target.password !== "" || target.origin !== base.origin || !withinBasePath) {
1866
+ throw new TypeError("storefront API fetch target is outside the configured endpoint");
1867
+ }
1868
+ const request = new Request(input instanceof Request ? input : target, {
1869
+ ...init,
1870
+ // Never forward signed shop headers across a redirect selected by untrusted theme code.
1871
+ redirect: "manual"
1872
+ });
1873
+ const headers = new Headers(request.headers);
1874
+ for (const name of STOREFRONT_API_PROTECTED_HEADERS) headers.delete(name);
1875
+ defaultHeaders.forEach((value, name) => headers.set(name, value));
1876
+ return fetch(new Request(request, { headers }));
1877
+ };
1878
+ }
1845
1879
  async function createKotaoContext(request, env, executionCtx, deps) {
1846
1880
  const waitUntil = (p) => {
1847
1881
  executionCtx.waitUntil(p);
@@ -1863,22 +1897,28 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1863
1897
  const siteId = resolvedEnv.KOTAO_SITE_ID ?? resolvedEnv.KOTAO_SHOP_ID;
1864
1898
  const inboundShop = request.headers.get(SHOP_HEADER);
1865
1899
  const inboundShopSignature = request.headers.get(SHOP_SIGNATURE_HEADER);
1866
- const signedShopContextHeaders = inboundShop !== null && inboundShopSignature !== null ? { [SHOP_HEADER]: inboundShop, [SHOP_SIGNATURE_HEADER]: inboundShopSignature } : await localSignedShopContextHeaders(
1900
+ const signedShopContextHeaders = inboundShop !== null && inboundShopSignature !== null ? {
1901
+ [SHOP_HEADER]: inboundShop,
1902
+ [SHOP_SIGNATURE_HEADER]: inboundShopSignature
1903
+ } : await localSignedShopContextHeaders(
1867
1904
  resolvedEnv.STOREFRONT_SHOP_CONTEXT_KEY,
1868
1905
  siteId,
1869
1906
  new URL(request.url).hostname
1870
1907
  );
1871
- const pathLocale = parseLocale(request);
1908
+ const requestUrl = new URL(request.url);
1909
+ const editorMode = requestUrl.searchParams.get("kotao_editor") === "1";
1910
+ const requestedEditorLocale = editorMode ? requestUrl.searchParams.get("kotao_locale")?.trim() : void 0;
1911
+ const requestedEditorCountry = editorMode ? requestUrl.searchParams.get("kotao_country")?.trim().toUpperCase() : void 0;
1912
+ const editorLocale = requestedEditorLocale !== void 0 && API_LOCALE_RE.test(requestedEditorLocale) ? requestedEditorLocale : null;
1913
+ const editorCountry = requestedEditorCountry !== void 0 && API_COUNTRY_RE.test(requestedEditorCountry) ? requestedEditorCountry : null;
1914
+ const pathLocale = editorLocale ?? parseLocale(request);
1915
+ const market = marketContextFromHeaders(request.headers);
1872
1916
  const localizationCookie = readLocalizationCookie(request.headers.get("cookie"));
1873
- const cookieLocale = localizationCookie.locale;
1874
- const autoLanguage = autoRedirectEnabled(request.headers, AUTO_REDIRECT_LANGUAGE_HEADER);
1875
1917
  const autoCountry = autoRedirectEnabled(request.headers, AUTO_REDIRECT_COUNTRY_HEADER);
1876
- const browserLocale = autoLanguage ? localeFromAcceptLanguage(request.headers.get("accept-language")) : null;
1877
- const selectedLocale = pathLocale ?? cookieLocale ?? browserLocale?.split("-")[0] ?? null;
1878
- const apiLocale = selectedLocale !== null && API_LOCALE_RE.test(selectedLocale) ? selectedLocale : void 0;
1918
+ const apiLocale = pathLocale !== null && API_LOCALE_RE.test(pathLocale) ? pathLocale : void 0;
1879
1919
  const cookieCountry = localizationCookie.country !== null && API_COUNTRY_RE.test(localizationCookie.country) ? localizationCookie.country : null;
1880
1920
  const geoCountry = autoCountry ? geo?.country?.trim().toUpperCase() ?? null : null;
1881
- const apiCountry = cookieCountry ?? (geoCountry !== null && API_COUNTRY_RE.test(geoCountry) ? geoCountry : null);
1921
+ const apiCountry = editorCountry ?? cookieCountry ?? (geoCountry !== null && API_COUNTRY_RE.test(geoCountry) ? geoCountry : null);
1882
1922
  const extraHeaders = {};
1883
1923
  const requestId = request.headers.get(REQUEST_ID_HEADER)?.trim();
1884
1924
  if (requestId !== void 0 && requestId.length > 0) extraHeaders[REQUEST_ID_HEADER] = requestId;
@@ -1906,6 +1946,10 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1906
1946
  fetch,
1907
1947
  defaultHeaders: eventHeaders
1908
1948
  });
1949
+ const storefrontApiFetch = createStorefrontApiFetch(
1950
+ resolvedEnv.STOREFRONT_API_ENDPOINT,
1951
+ eventHeaders
1952
+ );
1909
1953
  const cart = createCartHandler({ request, storefront });
1910
1954
  const contextSession = withSessionPresenceHint(
1911
1955
  deps?.session,
@@ -1921,12 +1965,14 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1921
1965
  const settingsEndpoint = `${resolvedEnv.STOREFRONT_API_ENDPOINT.replace(/\/+$/, "")}/settings`;
1922
1966
  return {
1923
1967
  storefront,
1968
+ fetch: storefrontApiFetch,
1924
1969
  events,
1925
1970
  cart,
1926
1971
  customerAccount,
1927
1972
  geo,
1928
1973
  withCache: createWithCache(cache),
1929
1974
  locale: pathLocale,
1975
+ market,
1930
1976
  // Cookie-presence hint only — the theme cannot validate the HMAC; the authoritative check is the proxy.
1931
1977
  session: contextSession,
1932
1978
  env: resolvedEnv,
@@ -1935,7 +1981,8 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1935
1981
  endpoint: settingsEndpoint,
1936
1982
  allowCrossOrigin: true,
1937
1983
  ...signedShopContextHeaders ? { shopContextHeaders: signedShopContextHeaders } : {},
1938
- ...opts?.fetch ? { fetch: opts.fetch } : {}
1984
+ ...opts?.fetch ? { fetch: opts.fetch } : {},
1985
+ ...opts?.templateHandle ? { templateHandle: opts.templateHandle } : {}
1939
1986
  })
1940
1987
  };
1941
1988
  }
@@ -1988,6 +2035,6 @@ function createEphemeralSession(isLoggedIn) {
1988
2035
  };
1989
2036
  }
1990
2037
 
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
2038
+ 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, marketContextFromHeaders, originalPathnameFromRequest, readCartIdCookie, readCustomerSessionToken, readHostedCustomerCsrfToken, readHostedCustomerSessionToken, readLegacyCustomerSessionToken, readLocalizationCookie, resolveCheckoutUrl, shopHostname, signGeo, stripLocalePrefixFromPathname, stripLocalePrefixFromRequest, trustedShopOriginFromHeaders, verifyGeo };
2039
+ //# sourceMappingURL=chunk-EG34HLSX.js.map
2040
+ //# sourceMappingURL=chunk-EG34HLSX.js.map