@kotao/storefront 0.2.5 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +57 -2
  2. package/dist/bridge-CfNBWu0H.d.ts +260 -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-GGOZELAA.js → chunk-DTKLAOKR.js} +231 -165
  11. package/dist/chunk-DTKLAOKR.js.map +1 -0
  12. package/dist/{chunk-MCIFKJQK.js → chunk-R4N565GX.js} +5 -2
  13. package/dist/chunk-R4N565GX.js.map +1 -0
  14. package/dist/chunk-RFKLO6TD.js +1594 -0
  15. package/dist/chunk-RFKLO6TD.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 +4 -2
  35. package/dist/events-react.js +6 -4
  36. package/dist/events-react.js.map +1 -1
  37. package/dist/events.d.ts +3 -3
  38. package/dist/events.js +1 -1
  39. package/dist/{fetch-M3Y-fQrW.d.ts → fetch-Bq_cc8_G.d.ts} +5 -0
  40. package/dist/hydrogen-CqDMW3YC.d.ts +259 -0
  41. package/dist/index.d.ts +75 -51
  42. package/dist/index.js +19 -15
  43. package/dist/index.js.map +1 -1
  44. package/dist/react-router.d.ts +40 -9
  45. package/dist/react-router.js +16 -7
  46. package/dist/react-router.js.map +1 -1
  47. package/dist/react.d.ts +79 -11
  48. package/dist/react.js +279 -10
  49. package/dist/react.js.map +1 -1
  50. package/dist/{routing-sEonP93J.d.ts → routing-Bz3Cg0BW.d.ts} +36 -6
  51. package/dist/seo.d.ts +7 -4
  52. package/dist/seo.js +2 -2
  53. package/dist/settings.d.ts +14 -4
  54. package/dist/settings.js +2 -2
  55. package/dist/{shop-BJSvtmnV.d.ts → shop-CnrnSAJw.d.ts} +33 -6
  56. package/dist/{store-CtCWHI8H.d.ts → store-ZzoBbWir.d.ts} +1 -1
  57. package/dist/storefront-api-types.d.ts +12 -0
  58. package/dist/{types-BDhHWZsP.d.ts → types-BkY0yET-.d.ts} +3 -3
  59. package/dist/{types-bcbQzx87.d.ts → types-DZX8ScsJ.d.ts} +2 -0
  60. package/package.json +4 -4
  61. package/dist/cart-documents-CwwRTvm8.d.ts +0 -21
  62. package/dist/chunk-2IWNUDSZ.js.map +0 -1
  63. package/dist/chunk-GGOZELAA.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-MCIFKJQK.js.map +0 -1
  67. package/dist/chunk-PXVDVUFX.js.map +0 -1
  68. package/dist/chunk-PXZ737N3.js +0 -439
  69. package/dist/chunk-PXZ737N3.js.map +0 -1
  70. 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-MCIFKJQK.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, rolloutVisitorCookieHeader, 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;
@@ -108,12 +110,100 @@ function readCartIdCookie(cookieHeader) {
108
110
  if (cookieHeader == null || cookieHeader === "") return null;
109
111
  const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${CART_ID_COOKIE}=`));
110
112
  if (match === void 0) return null;
111
- const value = decodeURIComponent(match.slice(CART_ID_COOKIE.length + 1));
112
- return value === "" ? null : value;
113
+ try {
114
+ const value = decodeURIComponent(match.slice(CART_ID_COOKIE.length + 1));
115
+ return value === "" ? null : value;
116
+ } catch {
117
+ return null;
118
+ }
113
119
  }
114
120
  function buildCartIdCookie(cartId) {
115
121
  return `${CART_ID_COOKIE}=${encodeURIComponent(cartId)}; Path=/; Max-Age=${CART_MAX_AGE}; SameSite=Lax; Secure; HttpOnly`;
116
122
  }
123
+ function clearCartIdCookie() {
124
+ return `${CART_ID_COOKIE}=; Path=/; Max-Age=0; SameSite=Lax; Secure; HttpOnly`;
125
+ }
126
+
127
+ // src/customer-account/session.ts
128
+ var CUSTOMER_SESSION_COOKIE = "kotao_customer_session";
129
+ var DEFAULT_SESSION_MAX_AGE = 60 * 60 * 24 * 30;
130
+ var HOSTED_CUSTOMER_SESSION_COOKIE = "__Host-kotao_customer_session";
131
+ var HOSTED_CUSTOMER_CSRF_COOKIE = "__Host-kotao_customer_csrf";
132
+ var HOSTED_CUSTOMER_CSRF_HEADER = "x-kotao-csrf-token";
133
+ var MAX_HOSTED_SESSION_MAX_AGE = 60 * 60 * 24 * 365;
134
+ var DEFAULT_HOSTED_SESSION_MAX_AGE = MAX_HOSTED_SESSION_MAX_AGE;
135
+ var MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH = 4096;
136
+ var assertHostname = (hostname) => {
137
+ if (hostname === "" || hostname.startsWith(".") || hostname.endsWith(".")) {
138
+ throw new Error(`invalid shop hostname for the customer session cookie: '${hostname}'`);
139
+ }
140
+ };
141
+ function shopHostname(request) {
142
+ return new URL(request.url).hostname;
143
+ }
144
+ function buildCustomerSessionCookie(token, attrs) {
145
+ assertHostname(attrs.hostname);
146
+ const maxAge = attrs.maxAgeSeconds ?? DEFAULT_SESSION_MAX_AGE;
147
+ return `${CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Domain=${attrs.hostname}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
148
+ }
149
+ function clearCustomerSessionCookie(attrs) {
150
+ assertHostname(attrs.hostname);
151
+ return `${CUSTOMER_SESSION_COOKIE}=; Domain=${attrs.hostname}; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
152
+ }
153
+ function readCustomerSessionToken(cookieHeader) {
154
+ if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
155
+ const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${CUSTOMER_SESSION_COOKIE}=`));
156
+ if (match === void 0) return null;
157
+ const raw = match.slice(CUSTOMER_SESSION_COOKIE.length + 1);
158
+ if (raw === "") return null;
159
+ try {
160
+ return decodeURIComponent(raw);
161
+ } catch {
162
+ return null;
163
+ }
164
+ }
165
+ function buildHostedCustomerSessionCookie(token, attrs = {}) {
166
+ if (token === "") throw new Error("hosted customer session token must not be empty");
167
+ const maxAge = attrs.maxAgeSeconds ?? DEFAULT_HOSTED_SESSION_MAX_AGE;
168
+ if (!Number.isInteger(maxAge) || maxAge <= 0 || maxAge > MAX_HOSTED_SESSION_MAX_AGE) {
169
+ throw new Error("hosted customer session Max-Age must be between 1 second and 365 days");
170
+ }
171
+ return `${HOSTED_CUSTOMER_SESSION_COOKIE}=${encodeURIComponent(token)}; Path=/; Max-Age=${maxAge}; HttpOnly; Secure; SameSite=Lax`;
172
+ }
173
+ function clearHostedCustomerSessionCookie() {
174
+ return `${HOSTED_CUSTOMER_SESSION_COOKIE}=; Path=/; Max-Age=0; HttpOnly; Secure; SameSite=Lax`;
175
+ }
176
+ function readHostedCustomerSessionToken(cookieHeader) {
177
+ return readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_SESSION_COOKIE);
178
+ }
179
+ function readHostedCustomerCsrfToken(cookieHeader) {
180
+ const token = readBoundedCookie(cookieHeader, HOSTED_CUSTOMER_CSRF_COOKIE, 43);
181
+ return token !== null && /^[A-Za-z0-9_-]{43}$/.test(token) ? token : null;
182
+ }
183
+ function readLegacyCustomerSessionToken(cookieHeader, options) {
184
+ if (!options.allowLegacy) return null;
185
+ return readBoundedCookie(
186
+ cookieHeader,
187
+ CUSTOMER_SESSION_COOKIE,
188
+ MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH
189
+ );
190
+ }
191
+ function clearLegacyCustomerSessionCookie(attrs) {
192
+ return clearCustomerSessionCookie(attrs);
193
+ }
194
+ function readBoundedCookie(cookieHeader, name, maxLength = MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH) {
195
+ if (cookieHeader === null || cookieHeader === void 0 || cookieHeader === "") return null;
196
+ const match = cookieHeader.split(";").map((part) => part.trim()).find((part) => part.startsWith(`${name}=`));
197
+ if (match === void 0) return null;
198
+ const raw = match.slice(name.length + 1);
199
+ if (raw === "" || raw.length > maxLength) return null;
200
+ try {
201
+ const decoded = decodeURIComponent(raw);
202
+ return decoded.length <= maxLength ? decoded : null;
203
+ } catch {
204
+ return null;
205
+ }
206
+ }
117
207
 
118
208
  // src/checkout/consent.ts
119
209
  var PARAM_PREFIX = "consent_";
@@ -214,51 +304,18 @@ function assertNoZoneIdentityLeak(url) {
214
304
  }
215
305
  }
216
306
  }
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
- ];
307
+ var CHECKOUT_TOKEN_DEFAULTS = {
308
+ checkoutLogoAlt: "",
309
+ checkoutColorAccent: "#005bd3",
310
+ checkoutColorBackground: "#ffffff",
311
+ checkoutColorForeground: "#111827",
312
+ checkoutFontBody: "Inter",
313
+ checkoutFontHeading: "Inter"
314
+ };
315
+ var CHECKOUT_DESIGN_TOKEN_INPUTS = HOSTED_SURFACE_DESIGN_INPUTS.map((input) => ({
316
+ ...input,
317
+ ...input.name in CHECKOUT_TOKEN_DEFAULTS ? { defaultValue: CHECKOUT_TOKEN_DEFAULTS[input.name] } : {}
318
+ }));
262
319
  function extractCheckoutDesignTokens(snapshot) {
263
320
  const global = snapshot.global;
264
321
  const logoUrl = optionalString(global["checkoutLogoUrl"], "checkoutLogoUrl");
@@ -316,6 +373,7 @@ var CART_FRAGMENT = (
316
373
  email
317
374
  phone
318
375
  countryCode
376
+ companyLocationId
319
377
  }
320
378
  note
321
379
  attributes {
@@ -575,6 +633,8 @@ function createCartHandler(opts) {
575
633
  cartId = void 0;
576
634
  }
577
635
  const consent = readConsentCookie(request?.headers.get("cookie"));
636
+ const cookieHeader = request?.headers.get("cookie");
637
+ const customerAccessToken = readHostedCustomerSessionToken(cookieHeader) ?? readCustomerSessionToken(cookieHeader);
578
638
  const currentCartId = async () => {
579
639
  if (cartId !== void 0) return cartId;
580
640
  cartId = await getCartId() ?? null;
@@ -611,9 +671,16 @@ function createCartHandler(opts) {
611
671
  return headers;
612
672
  };
613
673
  const create = async (input = {}) => {
674
+ const effectiveInput = customerAccessToken === null ? input : {
675
+ ...input,
676
+ buyerIdentity: {
677
+ ...input.buyerIdentity,
678
+ customerAccessToken: input.buyerIdentity?.customerAccessToken ?? customerAccessToken
679
+ }
680
+ };
614
681
  const data = await opts.storefront.mutate(
615
682
  CART_CREATE_MUTATION,
616
- { variables: { input } }
683
+ { variables: { input: effectiveInput } }
617
684
  );
618
685
  return withCookie(data.cartCreate);
619
686
  };
@@ -732,87 +799,6 @@ function appendSetCartIdHeaders(headers, value) {
732
799
  }
733
800
  }
734
801
 
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
802
  // src/customer-account/types.ts
817
803
  var CustomerAccountError = class extends Error {
818
804
  code;
@@ -1216,6 +1202,9 @@ function createCustomerAccountClient(opts) {
1216
1202
  }
1217
1203
  },
1218
1204
  async account() {
1205
+ if (token === null) {
1206
+ throw new CustomerAccountError("unauthenticated", "account read: not logged in");
1207
+ }
1219
1208
  return readJson(await proxyGet("/account"), "account read");
1220
1209
  },
1221
1210
  async orders(options) {
@@ -1294,22 +1283,6 @@ function idTokenNonce(idToken) {
1294
1283
  }
1295
1284
  }
1296
1285
 
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
1286
  // src/geo/geo.ts
1314
1287
  var GEO_HEADER = "x-kotao-geo";
1315
1288
  var GEO_SIGNATURE_HEADER = "x-kotao-geo-signature";
@@ -1384,7 +1357,10 @@ function splitFirstPathSegment(pathname) {
1384
1357
  const withoutSlash = pathname.slice(1);
1385
1358
  const slash = withoutSlash.indexOf("/");
1386
1359
  if (slash === -1) return { segment: withoutSlash, rest: "" };
1387
- return { segment: withoutSlash.slice(0, slash), rest: withoutSlash.slice(slash) };
1360
+ return {
1361
+ segment: withoutSlash.slice(0, slash),
1362
+ rest: withoutSlash.slice(slash)
1363
+ };
1388
1364
  }
1389
1365
  function isLocalePathSegment(segment) {
1390
1366
  return LOCALE_SEGMENT_RE.test(segment);
@@ -1475,12 +1451,16 @@ function localizePath(path, locale, options = {}) {
1475
1451
  const targetLocale = normalizeLocale(locale);
1476
1452
  const primaryLocale = normalizeLocale(options.primaryLocale);
1477
1453
  const url = new URL(path.startsWith("/") ? path : "/", "https://storefront.local");
1478
- const stripped = stripLocalePrefixFromPathname(url.pathname).pathname;
1454
+ const marketPrefix = options.marketPathPrefix !== null && options.marketPathPrefix !== void 0 && options.marketPathPrefix.startsWith("/") ? options.marketPathPrefix.replace(/\/+$/u, "") : null;
1455
+ const withoutMarket = marketPrefix !== null && (url.pathname === marketPrefix || url.pathname.startsWith(`${marketPrefix}/`)) ? url.pathname.slice(marketPrefix.length) || "/" : url.pathname;
1456
+ const stripped = stripLocalePrefixFromPathname(withoutMarket).pathname;
1479
1457
  const suffix = `${url.search}${url.hash}`;
1458
+ const marketBase = marketPrefix ?? "";
1480
1459
  if (targetLocale === null || primaryLocale !== null && targetLocale === primaryLocale) {
1481
- return `${stripped}${suffix}`;
1460
+ return `${marketBase}${stripped}${suffix}` || "/";
1482
1461
  }
1483
- return `${stripped === "/" ? `/${targetLocale}` : `/${targetLocale}${stripped}`}${suffix}`;
1462
+ const localized = stripped === "/" ? `/${targetLocale}` : `/${targetLocale}${stripped}`;
1463
+ return `${marketBase}${localized}${suffix}`;
1484
1464
  }
1485
1465
 
1486
1466
  // src/storefront-client/client.ts
@@ -1802,6 +1782,40 @@ async function localSignedShopContextHeaders(key, siteId, hostname) {
1802
1782
  );
1803
1783
  return { [SHOP_HEADER]: payload, [SHOP_SIGNATURE_HEADER]: signature };
1804
1784
  }
1785
+ function marketContextFromHeaders(headers) {
1786
+ const id = headers.get(MARKET_ID_HEADER)?.trim();
1787
+ const defaultLocale = headers.get(MARKET_DEFAULT_LOCALE_HEADER)?.trim();
1788
+ const canonicalUrl = headers.get(MARKET_CANONICAL_URL_HEADER)?.trim();
1789
+ const encodedRoots = headers.get(MARKET_ROOT_URLS_HEADER);
1790
+ if (!id || !defaultLocale || !canonicalUrl?.startsWith("https://") || encodedRoots === null || encodedRoots.length > 32768) {
1791
+ return null;
1792
+ }
1793
+ let rootUrls;
1794
+ try {
1795
+ const parsed = JSON.parse(encodedRoots);
1796
+ if (!Array.isArray(parsed) || parsed.length === 0 || !parsed.every(
1797
+ (root) => typeof root === "object" && root !== null && "locale" in root && typeof root.locale === "string" && "url" in root && typeof root.url === "string" && root.url.startsWith("https://")
1798
+ )) {
1799
+ return null;
1800
+ }
1801
+ rootUrls = parsed;
1802
+ } catch {
1803
+ return null;
1804
+ }
1805
+ const pathPrefix = headers.get(MARKET_PATH_PREFIX_HEADER)?.trim();
1806
+ const themeId = headers.get(MARKET_THEME_ID_HEADER)?.trim();
1807
+ const settingsEnvironmentHandle = headers.get(MARKET_SETTINGS_ENVIRONMENT_HEADER)?.trim();
1808
+ return {
1809
+ id,
1810
+ pathPrefix: pathPrefix ? pathPrefix : null,
1811
+ defaultLocale,
1812
+ alternateLocales: headers.get(MARKET_ALTERNATE_LOCALES_HEADER)?.split(",").map((locale) => locale.trim()).filter((locale) => locale.length > 0) ?? [],
1813
+ rootUrls,
1814
+ canonicalUrl,
1815
+ themeId: themeId ? themeId : null,
1816
+ settingsEnvironmentHandle: settingsEnvironmentHandle ? settingsEnvironmentHandle : null
1817
+ };
1818
+ }
1805
1819
  var CACHE_NAME = "kotao-storefront-v1";
1806
1820
  var CACHE_VERSION_HEADER = "x-kotao-cache-version";
1807
1821
  var REQUEST_ID_HEADER = "x-kotao-request-id";
@@ -1842,6 +1856,36 @@ function resolveStorefrontApiEndpoint(endpoint, requestUrl) {
1842
1856
  return new URL("/api/storefront", requestUrl).toString();
1843
1857
  return endpoint;
1844
1858
  }
1859
+ var STOREFRONT_API_PROTECTED_HEADERS = [
1860
+ SHOP_HEADER,
1861
+ SHOP_ORIGIN_HEADER,
1862
+ SHOP_SIGNATURE_HEADER,
1863
+ "x-kotao-locale",
1864
+ "x-kotao-country",
1865
+ REQUEST_ID_HEADER,
1866
+ DEPLOYMENT_ID_HEADER
1867
+ ];
1868
+ function createStorefrontApiFetch(endpoint, defaultHeaders) {
1869
+ const base = new URL(endpoint);
1870
+ const basePath = base.pathname.replace(/\/+$/, "") || "/";
1871
+ return async (input, init) => {
1872
+ const inputUrl = input instanceof Request ? input.url : String(input);
1873
+ const target = new URL(inputUrl, base);
1874
+ const withinBasePath = basePath === "/" || target.pathname === basePath || target.pathname.startsWith(`${basePath}/`);
1875
+ if (target.username !== "" || target.password !== "" || target.origin !== base.origin || !withinBasePath) {
1876
+ throw new TypeError("storefront API fetch target is outside the configured endpoint");
1877
+ }
1878
+ const request = new Request(input instanceof Request ? input : target, {
1879
+ ...init,
1880
+ // Never forward signed shop headers across a redirect selected by untrusted theme code.
1881
+ redirect: "manual"
1882
+ });
1883
+ const headers = new Headers(request.headers);
1884
+ for (const name of STOREFRONT_API_PROTECTED_HEADERS) headers.delete(name);
1885
+ defaultHeaders.forEach((value, name) => headers.set(name, value));
1886
+ return fetch(new Request(request, { headers }));
1887
+ };
1888
+ }
1845
1889
  async function createKotaoContext(request, env, executionCtx, deps) {
1846
1890
  const waitUntil = (p) => {
1847
1891
  executionCtx.waitUntil(p);
@@ -1863,23 +1907,31 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1863
1907
  const siteId = resolvedEnv.KOTAO_SITE_ID ?? resolvedEnv.KOTAO_SHOP_ID;
1864
1908
  const inboundShop = request.headers.get(SHOP_HEADER);
1865
1909
  const inboundShopSignature = request.headers.get(SHOP_SIGNATURE_HEADER);
1866
- const signedShopContextHeaders = inboundShop !== null && inboundShopSignature !== null ? { [SHOP_HEADER]: inboundShop, [SHOP_SIGNATURE_HEADER]: inboundShopSignature } : await localSignedShopContextHeaders(
1910
+ const signedShopContextHeaders = inboundShop !== null && inboundShopSignature !== null ? {
1911
+ [SHOP_HEADER]: inboundShop,
1912
+ [SHOP_SIGNATURE_HEADER]: inboundShopSignature
1913
+ } : await localSignedShopContextHeaders(
1867
1914
  resolvedEnv.STOREFRONT_SHOP_CONTEXT_KEY,
1868
1915
  siteId,
1869
1916
  new URL(request.url).hostname
1870
1917
  );
1871
- const pathLocale = parseLocale(request);
1918
+ const requestUrl = new URL(request.url);
1919
+ const editorMode = requestUrl.searchParams.get("kotao_editor") === "1";
1920
+ const requestedEditorLocale = editorMode ? requestUrl.searchParams.get("kotao_locale")?.trim() : void 0;
1921
+ const requestedEditorCountry = editorMode ? requestUrl.searchParams.get("kotao_country")?.trim().toUpperCase() : void 0;
1922
+ const editorLocale = requestedEditorLocale !== void 0 && API_LOCALE_RE.test(requestedEditorLocale) ? requestedEditorLocale : null;
1923
+ const editorCountry = requestedEditorCountry !== void 0 && API_COUNTRY_RE.test(requestedEditorCountry) ? requestedEditorCountry : null;
1924
+ const pathLocale = editorLocale ?? parseLocale(request);
1925
+ const market = marketContextFromHeaders(request.headers);
1872
1926
  const localizationCookie = readLocalizationCookie(request.headers.get("cookie"));
1873
- const cookieLocale = localizationCookie.locale;
1874
- const autoLanguage = autoRedirectEnabled(request.headers, AUTO_REDIRECT_LANGUAGE_HEADER);
1875
1927
  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;
1928
+ const apiLocale = pathLocale !== null && API_LOCALE_RE.test(pathLocale) ? pathLocale : void 0;
1879
1929
  const cookieCountry = localizationCookie.country !== null && API_COUNTRY_RE.test(localizationCookie.country) ? localizationCookie.country : null;
1880
1930
  const geoCountry = autoCountry ? geo?.country?.trim().toUpperCase() ?? null : null;
1881
- const apiCountry = cookieCountry ?? (geoCountry !== null && API_COUNTRY_RE.test(geoCountry) ? geoCountry : null);
1931
+ const apiCountry = editorCountry ?? cookieCountry ?? (geoCountry !== null && API_COUNTRY_RE.test(geoCountry) ? geoCountry : null);
1882
1932
  const extraHeaders = {};
1933
+ const rolloutVisitorCookie = rolloutVisitorCookieHeader(request.headers.get("cookie"));
1934
+ if (rolloutVisitorCookie !== null) extraHeaders["cookie"] = rolloutVisitorCookie;
1883
1935
  const requestId = request.headers.get(REQUEST_ID_HEADER)?.trim();
1884
1936
  if (requestId !== void 0 && requestId.length > 0) extraHeaders[REQUEST_ID_HEADER] = requestId;
1885
1937
  const deploymentId = request.headers.get(DEPLOYMENT_ID_HEADER)?.trim();
@@ -1898,6 +1950,7 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1898
1950
  cache
1899
1951
  });
1900
1952
  const eventHeaders = new Headers(signedShopContextHeaders);
1953
+ if (rolloutVisitorCookie !== null) eventHeaders.set("cookie", rolloutVisitorCookie);
1901
1954
  if (apiLocale !== void 0) eventHeaders.set("x-kotao-locale", apiLocale);
1902
1955
  if (apiCountry !== null) eventHeaders.set("x-kotao-country", apiCountry);
1903
1956
  for (const [name, value] of Object.entries(extraHeaders)) eventHeaders.set(name, value);
@@ -1906,6 +1959,10 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1906
1959
  fetch,
1907
1960
  defaultHeaders: eventHeaders
1908
1961
  });
1962
+ const storefrontApiFetch = createStorefrontApiFetch(
1963
+ resolvedEnv.STOREFRONT_API_ENDPOINT,
1964
+ eventHeaders
1965
+ );
1909
1966
  const cart = createCartHandler({ request, storefront });
1910
1967
  const contextSession = withSessionPresenceHint(
1911
1968
  deps?.session,
@@ -1921,12 +1978,14 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1921
1978
  const settingsEndpoint = `${resolvedEnv.STOREFRONT_API_ENDPOINT.replace(/\/+$/, "")}/settings`;
1922
1979
  return {
1923
1980
  storefront,
1981
+ fetch: storefrontApiFetch,
1924
1982
  events,
1925
1983
  cart,
1926
1984
  customerAccount,
1927
1985
  geo,
1928
1986
  withCache: createWithCache(cache),
1929
1987
  locale: pathLocale,
1988
+ market,
1930
1989
  // Cookie-presence hint only — the theme cannot validate the HMAC; the authoritative check is the proxy.
1931
1990
  session: contextSession,
1932
1991
  env: resolvedEnv,
@@ -1934,8 +1993,15 @@ async function createKotaoContext(request, env, executionCtx, deps) {
1934
1993
  loadThemeSettings: (opts) => fetchThemeSettings({
1935
1994
  endpoint: settingsEndpoint,
1936
1995
  allowCrossOrigin: true,
1937
- ...signedShopContextHeaders ? { shopContextHeaders: signedShopContextHeaders } : {},
1938
- ...opts?.fetch ? { fetch: opts.fetch } : {}
1996
+ ...signedShopContextHeaders || rolloutVisitorCookie !== null || apiCountry !== null ? {
1997
+ shopContextHeaders: {
1998
+ ...signedShopContextHeaders ?? {},
1999
+ ...rolloutVisitorCookie === null ? {} : { cookie: rolloutVisitorCookie },
2000
+ ...apiCountry === null ? {} : { "x-kotao-country": apiCountry }
2001
+ }
2002
+ } : {},
2003
+ ...opts?.fetch ? { fetch: opts.fetch } : {},
2004
+ ...opts?.templateHandle ? { templateHandle: opts.templateHandle } : {}
1939
2005
  })
1940
2006
  };
1941
2007
  }
@@ -1988,6 +2054,6 @@ function createEphemeralSession(isLoggedIn) {
1988
2054
  };
1989
2055
  }
1990
2056
 
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-GGOZELAA.js.map
1993
- //# sourceMappingURL=chunk-GGOZELAA.js.map
2057
+ 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, clearCartIdCookie, 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 };
2058
+ //# sourceMappingURL=chunk-DTKLAOKR.js.map
2059
+ //# sourceMappingURL=chunk-DTKLAOKR.js.map