@kotao/storefront 0.2.10 → 0.2.11

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.
@@ -1,6 +1,4 @@
1
1
  import { CART_FORM_ACTIONS } from './chunk-GR4QJ7EC.js';
2
- import * as ReactRuntime from 'react';
3
- import { createContext, createElement, useContext } from 'react';
4
2
 
5
3
  // src/cart/CartForm.ts
6
4
  function parseFormValue(value) {
@@ -34,21 +32,70 @@ var CartForm = Object.assign(
34
32
  },
35
33
  { ACTIONS: CART_FORM_ACTIONS, getFormInput: getCartFormInput }
36
34
  );
37
- var NonceContext = createContext(void 0);
38
- function createNonceProvider(nonce) {
39
- return function BoundNonceProvider(props) {
40
- return createElement(NonceContext.Provider, { value: nonce }, props.children);
35
+
36
+ // src/content-security-policy.ts
37
+ var QUOTED_TOKENS = /* @__PURE__ */ new Set([
38
+ "self",
39
+ "none",
40
+ "unsafe-eval",
41
+ "unsafe-hashes",
42
+ "unsafe-inline",
43
+ "strict-dynamic",
44
+ "wasm-unsafe-eval"
45
+ ]);
46
+ function createContentSecurityPolicy(options = {}) {
47
+ const nonce = createNonce();
48
+ const shopDomains = shopSources(options.shop);
49
+ const scriptSrc = uniqueSources([
50
+ ...normalizeSources(options.scriptSrc ?? ["self"]),
51
+ `'nonce-${nonce}'`
52
+ ]);
53
+ const connectSrc = uniqueSources([
54
+ "'self'",
55
+ ...shopDomains,
56
+ ...normalizeSources(options.connectSrc)
57
+ ]);
58
+ const imgSrc = uniqueSources([
59
+ "'self'",
60
+ "data:",
61
+ "https:",
62
+ ...shopDomains,
63
+ ...normalizeSources(options.imgSrc)
64
+ ]);
65
+ const styleSrc = uniqueSources(["'self'", "'unsafe-inline'", ...normalizeSources(options.styleSrc)]);
66
+ const directives = [
67
+ ["base-uri", ["'self'"]],
68
+ ["default-src", ["'self'"]],
69
+ ["connect-src", connectSrc],
70
+ ["img-src", imgSrc],
71
+ ["script-src", scriptSrc],
72
+ ["style-src", styleSrc]
73
+ ];
74
+ return {
75
+ nonce,
76
+ header: directives.map(([name, values]) => `${name} ${values.join(" ")}`).join("; ")
41
77
  };
42
78
  }
43
- function useNonce() {
44
- if (!hasReactDispatcher()) return void 0;
45
- return useContext(NonceContext);
79
+ function createNonce() {
80
+ const bytes = new Uint8Array(18);
81
+ crypto.getRandomValues(bytes);
82
+ return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
83
+ }
84
+ function shopSources(shop) {
85
+ if (shop === void 0) return [];
86
+ return [shop.storeDomain, shop.checkoutDomain].filter((domain) => domain !== void 0 && domain.trim() !== "").map((domain) => {
87
+ const trimmed = domain.trim();
88
+ return /^https?:\/\//i.test(trimmed) ? new URL(trimmed).origin : `https://${trimmed}`;
89
+ });
90
+ }
91
+ function normalizeSources(sources) {
92
+ return (sources ?? []).map((source) => {
93
+ const trimmed = source.trim();
94
+ return QUOTED_TOKENS.has(trimmed) ? `'${trimmed}'` : trimmed;
95
+ });
46
96
  }
47
- function hasReactDispatcher() {
48
- const runtime = ReactRuntime;
49
- return Boolean(
50
- runtime.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE?.H ?? runtime.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentDispatcher?.current
51
- );
97
+ function uniqueSources(sources) {
98
+ return Array.from(new Set(sources.filter((source) => source.length > 0)));
52
99
  }
53
100
 
54
101
  // src/analytics/attribution.ts
@@ -161,6 +208,6 @@ function createPixelTransport(options) {
161
208
  };
162
209
  }
163
210
 
164
- export { CartForm, collectAnalyticsAttribution, createAnalyticsBus, createAnalyticsEmitter, createNonceProvider, createPixelTransport, getCartFormInput, useNonce };
165
- //# sourceMappingURL=chunk-BV4OLXV4.js.map
166
- //# sourceMappingURL=chunk-BV4OLXV4.js.map
211
+ export { CartForm, collectAnalyticsAttribution, createAnalyticsBus, createAnalyticsEmitter, createContentSecurityPolicy, createPixelTransport, getCartFormInput };
212
+ //# sourceMappingURL=chunk-NRWS7HJ2.js.map
213
+ //# sourceMappingURL=chunk-NRWS7HJ2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cart/CartForm.ts","../src/content-security-policy.ts","../src/analytics/attribution.ts","../src/analytics/emitter.ts","../src/analytics/analytics-bus.ts","../src/analytics/pixel-transport.ts"],"names":["CartForm"],"mappings":"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","file":"chunk-NRWS7HJ2.js","sourcesContent":["/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { CART_FORM_ACTIONS, type CartFormAction } from './actions'\n\nexport interface CartFormProps {\n readonly action: CartFormAction\n}\n\nexport interface CartFormInputResult {\n readonly action: CartFormAction | null\n readonly inputs: Record<string, any>\n}\n\nfunction parseFormValue(value: unknown): unknown {\n if (typeof value !== 'string') return value\n const trimmed = value.trim()\n if (trimmed.startsWith('{') || trimmed.startsWith('[')) {\n try {\n return JSON.parse(trimmed) as unknown\n } catch {\n return value\n }\n }\n return value\n}\n\nexport function getCartFormInput(formData: FormData): CartFormInputResult {\n const action = formData.get('cartAction')\n const inputs: Record<string, any> = {}\n for (const key of new Set(formData.keys())) {\n if (key === 'cartAction') continue\n const values = formData.getAll(key).map(parseFormValue)\n inputs[key] = values.length === 1 ? values[0] : values\n }\n return {\n action: typeof action === 'string' ? (action as CartFormAction) : null,\n inputs,\n }\n}\n\n/**\n * Lightweight CartForm surface marker for Hydrogen-style imports. React render integration can wrap\n * this constant surface; the load-bearing API today is the stable ACTIONS contract used by handlers.\n */\nexport const CartForm = Object.assign(\n function CartForm(_props: CartFormProps): null {\n return null\n },\n { ACTIONS: CART_FORM_ACTIONS, getFormInput: getCartFormInput },\n)\n","export interface ContentSecurityPolicyShop {\n readonly checkoutDomain?: string\n readonly storeDomain?: string\n}\n\nexport interface CreateContentSecurityPolicyOptions {\n readonly shop?: ContentSecurityPolicyShop\n readonly scriptSrc?: readonly string[]\n readonly connectSrc?: readonly string[]\n readonly imgSrc?: readonly string[]\n readonly styleSrc?: readonly string[]\n}\n\nexport interface ContentSecurityPolicyResult {\n readonly nonce: string\n readonly header: string\n}\n\nconst QUOTED_TOKENS = new Set([\n 'self',\n 'none',\n 'unsafe-eval',\n 'unsafe-hashes',\n 'unsafe-inline',\n 'strict-dynamic',\n 'wasm-unsafe-eval',\n])\n\nexport function createContentSecurityPolicy(\n options: CreateContentSecurityPolicyOptions = {},\n): ContentSecurityPolicyResult {\n const nonce = createNonce()\n const shopDomains = shopSources(options.shop)\n const scriptSrc = uniqueSources([\n ...normalizeSources(options.scriptSrc ?? ['self']),\n `'nonce-${nonce}'`,\n ])\n const connectSrc = uniqueSources([\n \"'self'\",\n ...shopDomains,\n ...normalizeSources(options.connectSrc),\n ])\n const imgSrc = uniqueSources([\n \"'self'\",\n 'data:',\n 'https:',\n ...shopDomains,\n ...normalizeSources(options.imgSrc),\n ])\n const styleSrc = uniqueSources([\"'self'\", \"'unsafe-inline'\", ...normalizeSources(options.styleSrc)])\n const directives = [\n ['base-uri', [\"'self'\"]],\n ['default-src', [\"'self'\"]],\n ['connect-src', connectSrc],\n ['img-src', imgSrc],\n ['script-src', scriptSrc],\n ['style-src', styleSrc],\n ]\n return {\n nonce,\n header: directives\n .map(([name, values]) => `${name} ${(values as readonly string[]).join(' ')}`)\n .join('; '),\n }\n}\n\nfunction createNonce(): string {\n const bytes = new Uint8Array(18)\n crypto.getRandomValues(bytes)\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')\n}\n\nfunction shopSources(shop: ContentSecurityPolicyShop | undefined): readonly string[] {\n if (shop === undefined) return []\n return [shop.storeDomain, shop.checkoutDomain]\n .filter((domain): domain is string => domain !== undefined && domain.trim() !== '')\n .map((domain) => {\n const trimmed = domain.trim()\n return /^https?:\\/\\//i.test(trimmed) ? new URL(trimmed).origin : `https://${trimmed}`\n })\n}\n\nfunction normalizeSources(sources: readonly string[] | undefined): readonly string[] {\n return (sources ?? []).map((source) => {\n const trimmed = source.trim()\n return QUOTED_TOKENS.has(trimmed) ? `'${trimmed}'` : trimmed\n })\n}\n\nfunction uniqueSources(sources: readonly string[]): readonly string[] {\n return Array.from(new Set(sources.filter((source) => source.length > 0)))\n}\n","import type { AnalyticsContext, AnalyticsDeviceClass } from './events'\n\nexport interface AnalyticsAttributionEnvironment {\n readonly referrer?: string\n readonly search?: string\n readonly matchMedia?: (query: string) => { readonly matches: boolean }\n}\n\ntype AttributionContext = Pick<\n AnalyticsContext,\n 'referrer' | 'utmSource' | 'utmMedium' | 'utmCampaign' | 'deviceClass'\n>\n\nfunction deviceClass(\n matchMedia: AnalyticsAttributionEnvironment['matchMedia'],\n): AnalyticsDeviceClass | undefined {\n if (matchMedia === undefined) return undefined\n if (matchMedia('(max-width: 767px)').matches) return 'mobile'\n if (matchMedia('(max-width: 1023px)').matches) return 'tablet'\n return 'desktop'\n}\n\n/** Read static landing attribution plus the current responsive device class without retaining state\n * or identifiers. All values stay optional so non-DOM/SSR emitters keep their existing payload. */\nexport function collectAnalyticsAttribution(\n environment: AnalyticsAttributionEnvironment | null,\n): AttributionContext {\n if (environment === null) return {}\n const params = new URLSearchParams(environment.search ?? '')\n const referrer = environment.referrer || undefined\n const utmSource = params.get('utm_source') || undefined\n const utmMedium = params.get('utm_medium') || undefined\n const utmCampaign = params.get('utm_campaign') || undefined\n const classifiedDevice = deviceClass(environment.matchMedia)\n\n return {\n ...(referrer !== undefined ? { referrer } : {}),\n ...(utmSource !== undefined ? { utmSource } : {}),\n ...(utmMedium !== undefined ? { utmMedium } : {}),\n ...(utmCampaign !== undefined ? { utmCampaign } : {}),\n ...(classifiedDevice !== undefined ? { deviceClass: classifiedDevice } : {}),\n }\n}\n","import type { AnalyticsEventMap, AnalyticsEventName } from './events'\n\nexport type EventHandler<E extends AnalyticsEventName> = (payload: AnalyticsEventMap[E]) => void\n\n/** A framework-agnostic typed pub/sub bus (Hydrogen `useAnalytics` shape, minus React). */\nexport interface AnalyticsEmitter {\n subscribe<E extends AnalyticsEventName>(event: E, handler: EventHandler<E>): () => void\n publish<E extends AnalyticsEventName>(event: E, payload: AnalyticsEventMap[E]): void\n}\n\nexport function createAnalyticsEmitter(): AnalyticsEmitter {\n const handlers = new Map<AnalyticsEventName, Set<(payload: unknown) => void>>()\n return {\n subscribe(event, handler) {\n const set = handlers.get(event) ?? new Set<(payload: unknown) => void>()\n const erased = handler as (payload: unknown) => void\n set.add(erased)\n handlers.set(event, set)\n return () => {\n set.delete(erased)\n }\n },\n publish(event, payload) {\n const set = handlers.get(event)\n if (set === undefined) return\n // Snapshot so a handler unsubscribing mid-dispatch doesn't skip a sibling.\n for (const handler of [...set]) {\n try {\n handler(payload)\n } catch {\n // Isolate: a throwing subscriber must not break sibling handlers or the downstream pixel send.\n }\n }\n },\n }\n}\n","import type { AnonymousAnalyticsContext } from './anonymous-context'\nimport type { ConsentState } from './consent'\nimport { createAnalyticsEmitter, type AnalyticsEmitter } from './emitter'\nimport type { AnalyticsContext, AnalyticsEventMap, AnalyticsEventName } from './events'\nimport type { PixelTransport } from './pixel-transport'\n\nexport interface AnalyticsBusOptions {\n readonly transport: PixelTransport\n /** Legacy consent seam retained for API compatibility while Storefront consent UI is disabled. */\n readonly getConsent: () => ConsentState\n /** Ambient context (including attribution and device class) attached to consented events. */\n readonly getContext?: () => AnalyticsContext\n /** Sanitized same-origin page URL used only for the anonymous page-view fallback. */\n readonly getAnonymousContext?: () => AnonymousAnalyticsContext\n /** Clock seam for deterministic timestamps in tests. */\n readonly now?: () => string\n}\n\nexport interface AnalyticsBus {\n readonly emitter: AnalyticsEmitter\n publish<E extends AnalyticsEventName>(event: E, payload: AnalyticsEventMap[E]): void\n flush(): void\n}\n\n/**\n * Wire the emitter to the pixel. Every published event reaches theme subscribers (via the emitter).\n * First-party recording is consent-strict: denied visits get only an anonymous page_viewed row and\n * never evaluate ambient context, which may read attribution or device-class signals.\n */\nexport function createAnalyticsBus(options: AnalyticsBusOptions): AnalyticsBus {\n const emitter = createAnalyticsEmitter()\n const now = options.now ?? ((): string => new Date().toISOString())\n return {\n emitter,\n publish(event, payload) {\n emitter.publish(event, payload)\n const consented = options.getConsent().analytics === true\n if (consented) {\n const context = options.getContext?.() ?? {}\n options.transport.record({ event, payload, context, timestamp: now(), consent: true })\n return\n }\n if (event === 'page_viewed') {\n options.transport.record({\n event,\n payload: {} as AnalyticsEventMap[typeof event],\n context: options.getAnonymousContext?.() ?? {},\n timestamp: now(),\n consent: false,\n })\n }\n },\n flush() {\n options.transport.flush()\n },\n }\n}\n","import type { PixelEvent } from './events'\n\n/** The actual network send. Injectable so tests don't touch the network. */\nexport type PixelSend = (endpoint: string, body: string) => void\n\nexport interface PixelTransportOptions {\n /** Same-origin carve-out endpoint (default '/api/storefront/pixel') — never cross-origin. */\n readonly endpoint?: string\n readonly batchSize?: number\n readonly flushAfterMs?: number\n /**\n * The actual network send. Required + injected: the browser sender (`sendBeacon`/keepalive `fetch`)\n * is DOM-specific and lives in the React layer, keeping this batching core framework-agnostic and\n * unit-testable with a spy. The provider wires the real sender.\n */\n readonly send: PixelSend\n}\n\nexport interface PixelTransport {\n record(event: PixelEvent): void\n flush(): void\n}\n\nconst DEFAULT_ENDPOINT = '/api/storefront/pixel'\nconst DEFAULT_BATCH_SIZE = 10\n\n/**\n * Batches pixel events and POSTs them to the same-origin carve-out. Flushes on `batchSize` or an\n * explicit `flush()` (the provider flushes on page-hide), or after one second. The endpoint is same-origin so themes need\n * no CORS and no token is exposed in the browser.\n */\nexport function createPixelTransport(options: PixelTransportOptions): PixelTransport {\n const endpoint = options.endpoint ?? DEFAULT_ENDPOINT\n // SECURITY: the pixel must stay same-origin (no CORS, no token leak). Reject a non-relative or\n // protocol-relative endpoint so a misconfigured theme can't exfiltrate visitor data (e.g. clientIp).\n if (!/^\\/(?!\\/)/.test(endpoint)) {\n throw new Error(`pixel endpoint must be a same-origin path starting with '/'; got: ${endpoint}`)\n }\n const batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE\n const send = options.send\n let queue: PixelEvent[] = []\n let timer: ReturnType<typeof setTimeout> | undefined\n\n const flush = (): void => {\n if (timer !== undefined) clearTimeout(timer)\n timer = undefined\n if (queue.length === 0) return\n const batch = queue\n queue = []\n send(endpoint, JSON.stringify({ events: batch }))\n }\n\n return {\n record(event) {\n queue.push(event)\n if (queue.length >= batchSize) flush()\n else timer ??= setTimeout(flush, options.flushAfterMs ?? 1000)\n },\n flush,\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { F as FormVersionSchema } from './types-CSNXbGFW.js';
1
+ import { F as FormVersionSchema } from './types-BTUTZXxJ.js';
2
2
  import { S as StorefrontHeadersInit } from './http-types-CGh8WGHB.js';
3
3
 
4
4
  type EventRegistrationMode = 'instant' | 'approval_then_payment' | 'waitlist_only';
@@ -1,8 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode } from 'react';
3
3
  import { O as OfferTokenLocation, a as OfferTokenHistory } from './offer-token-C-nk_nj8.js';
4
- import { E as EventsClient, a as EventCheckoutSession, b as EventApprovalOfferResolution, P as PublicEvent, c as EventRegistrationSubmission } from './client-D-M3Y1ul.js';
5
- import './types-CSNXbGFW.js';
4
+ import { E as EventsClient, a as EventCheckoutSession, b as EventApprovalOfferResolution, P as PublicEvent, c as EventRegistrationSubmission } from './client-Bt8EEr-K.js';
5
+ import './types-BTUTZXxJ.js';
6
6
  import './http-types-CGh8WGHB.js';
7
7
 
8
8
  type EventRegistrationState = 'idle' | 'submitting' | 'awaiting_approval' | 'waitlisted' | 'checkout_ready' | 'request_error';
package/dist/events.d.ts CHANGED
@@ -1,10 +1,10 @@
1
1
  import { C as CartHandler } from './createCartHandler-DJEZW4o2.js';
2
- export { C as ClaimEventApprovalOffer, d as CreateEventApprovalRequest, e as CreateEventCheckoutSession, f as CreateEventWaitlistEntry, b as EventApprovalOfferResolution, g as EventApprovalRequestReceipt, a as EventCheckoutSession, h as EventFormAnswer, i as EventFormSubmissionInput, j as EventRegistrationMode, k as EventRegistrationResult, c as EventRegistrationSubmission, l as EventWaitlistReceipt, E as EventsClient, P as PublicEvent, m as PublicEventForm, n as PublicEventOccurrence, o as PublicEventSummary, p as PublicEventTicketType, q as PublicEventVenue, S as StorefrontEventsRequestError, r as createEventsClient } from './client-D-M3Y1ul.js';
2
+ export { C as ClaimEventApprovalOffer, d as CreateEventApprovalRequest, e as CreateEventCheckoutSession, f as CreateEventWaitlistEntry, b as EventApprovalOfferResolution, g as EventApprovalRequestReceipt, a as EventCheckoutSession, h as EventFormAnswer, i as EventFormSubmissionInput, j as EventRegistrationMode, k as EventRegistrationResult, c as EventRegistrationSubmission, l as EventWaitlistReceipt, E as EventsClient, P as PublicEvent, m as PublicEventForm, n as PublicEventOccurrence, o as PublicEventSummary, p as PublicEventTicketType, q as PublicEventVenue, S as StorefrontEventsRequestError, r as createEventsClient } from './client-Bt8EEr-K.js';
3
3
  export { a as OfferTokenHistory, O as OfferTokenLocation, c as consumeOfferTokenFragment, o as offerTokenHrefMarker } from './offer-token-C-nk_nj8.js';
4
4
  import './client-D51WdvYR.js';
5
5
  import './http-types-CGh8WGHB.js';
6
6
  import './types-C4yXcret.js';
7
- import './types-CSNXbGFW.js';
7
+ import './types-BTUTZXxJ.js';
8
8
 
9
9
  declare class EventCartPreparationError extends Error {
10
10
  constructor();
package/dist/forms.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { i as FormVisibilityRule, a as FormAnswers, F as FormVersionSchema, e as FormField, f as FormLocalizedText, g as FormRenderState, P as PublicForm, b as FormFieldErrors, h as FormSubmission } from './types-CSNXbGFW.js';
2
- export { c as FormAnswer, d as FormBlock, j as PublicFormDefinition, k as PublicFormVersion } from './types-CSNXbGFW.js';
1
+ import { i as FormVisibilityRule, b as FormAnswers, F as FormVersionSchema, d as FormField, f as FormLocalizedText, g as FormRenderState, P as PublicForm, e as FormFieldErrors, h as FormSubmission } from './types-BTUTZXxJ.js';
2
+ export { a as FormAnswer, c as FormBlock, j as PublicFormDefinition, k as PublicFormVersion } from './types-BTUTZXxJ.js';
3
3
 
4
4
  declare const FORM_ANSWER_PREFIX = "answers";
5
5
  declare const ADDRESS_PROPERTIES: readonly ["line1", "line2", "city", "postalCode", "countryCode", "provinceCode"];
package/dist/index.d.ts CHANGED
@@ -1,31 +1,30 @@
1
1
  export { c as CacheCustom, d as CacheLong, e as CacheNone, f as CacheShort, C as CacheStrategy, H as HydrogenStorefrontClientOptions, K as KotaoCache, g as StaleIfErrorFallback, h as Storefront, a as StorefrontAuthHeader, i as StorefrontCache, b as StorefrontCacheInput, j as StorefrontCacheQueryOptions, k as StorefrontCacheRequest, S as StorefrontClient, l as StorefrontClientOptions, m as StorefrontClientResult, n as StorefrontDefaultCache, o as StorefrontQueryOptions, p as StorefrontQueryTimeoutError, q as StorefrontUpstreamError, r as createCache, s as createStorefrontClient, t as generateCacheControlHeader } from './client-D51WdvYR.js';
2
2
  import { C as Cart } from './types-C4yXcret.js';
3
3
  export { k as CART_FORM_ACTIONS, b as CartAttribute, l as CartBuyerIdentity, c as CartBuyerIdentityInput, h as CartDeliveryAddress, j as CartFormAction, m as CartLine, a as CartLineInput, e as CartLineUpdateInput, f as CartMetafield, g as CartMetafieldIdentifier, d as CartMutationResult, i as CartSelectedDeliveryOption, n as CartUserError, o as HydrogenCart, p as HydrogenCartCreateInput, q as HydrogenCartMutationResult, H as HydrogenSession, r as HydrogenSessionData } from './types-C4yXcret.js';
4
- import { c as ConsentBucket, C as ConsentState, B as BoundNonceProvider, A as AnalyticsContext } from './shop-4y-4z3oZ.js';
5
- export { d as ANALYTICS_EVENTS, b as AnalyticsBus, e as AnalyticsBusOptions, f as AnalyticsDeviceClass, a as AnalyticsEmitter, h as AnalyticsEventMap, i as AnalyticsEventName, j as AnalyticsGeo, k as CONSENT_BUCKETS, l as CONSENT_COOKIE, m as CartForm, n as CartFormProps, o as CartViewedPayload, p as CollectionViewedPayload, D as DENIED_CONSENT, E as EventHandler, G as GRANTED_CONSENT, q as GetShopAnalyticsOptions, P as PageViewedPayload, r as PixelEvent, s as PixelSend, t as PixelTransport, v as PixelTransportOptions, w as ProductAddedToCartPayload, x as ProductViewedPayload, y as SearchViewedPayload, S as ShopAnalytics, z as buildConsentCookie, F as createAnalyticsBus, H as createAnalyticsEmitter, I as createPixelTransport, J as getShopAnalytics, K as isGranted, L as mergeConsent, M as parseConsent, N as readConsentCookie, O as serializeConsent } from './shop-4y-4z3oZ.js';
4
+ import { C as ConsentBucket, a as ConsentState, A as AnalyticsContext } from './shop-wJdcWcVz.js';
5
+ export { b as ANALYTICS_EVENTS, c as AnalyticsBus, d as AnalyticsBusOptions, e as AnalyticsDeviceClass, f as AnalyticsEmitter, g as AnalyticsEventMap, h as AnalyticsEventName, i as AnalyticsGeo, j as CONSENT_BUCKETS, k as CONSENT_COOKIE, l as CartForm, m as CartFormProps, n as CartViewedPayload, o as CollectionViewedPayload, p as ContentSecurityPolicyResult, q as ContentSecurityPolicyShop, r as CreateContentSecurityPolicyOptions, D as DENIED_CONSENT, E as EventHandler, G as GRANTED_CONSENT, s as GetShopAnalyticsOptions, P as PageViewedPayload, t as PixelEvent, u as PixelSend, v as PixelTransport, w as PixelTransportOptions, x as ProductAddedToCartPayload, y as ProductViewedPayload, S as SearchViewedPayload, z as ShopAnalytics, B as buildConsentCookie, F as createAnalyticsBus, H as createAnalyticsEmitter, I as createContentSecurityPolicy, J as createPixelTransport, K as getShopAnalytics, L as isGranted, M as mergeConsent, N as parseConsent, O as readConsentCookie, Q as serializeConsent } from './shop-wJdcWcVz.js';
6
6
  import { a as CartDispatchAction, C as CartHandler } from './createCartHandler-DJEZW4o2.js';
7
7
  export { b as CartGetId, c as CartSetId, d as CreateCartHandlerOptions, H as HydrogenCartHandlerOptions, R as RequestCartHandlerOptions, e as cartGetIdDefault, f as cartSetIdDefault, g as createCartHandler } from './createCartHandler-DJEZW4o2.js';
8
8
  import { c as ThemeSettingsSnapshot, R as ResolvedSettings } from './store-ZzoBbWir.js';
9
9
  export { b as ResolvedBlock, a as ResolvedSection, d as ResolvedValuesDocument, T as ThemeSettingsStore, e as createThemeSettingsStore } from './store-ZzoBbWir.js';
10
- import { C as CustomerAccountClient } from './routing-D2GFXAa0.js';
11
- export { A as Address, c as AddressConnection, d as CustomerAccount, e as CustomerAccountError, f as CustomerAccountErrorCode, G as GEO_HEADER, g as GEO_SIGNATURE_HEADER, h as Geo, K as KotaoContext, a as KotaoEnv, b as KotaoSession, L as LocalizePathOptions, M as Money, O as Order, i as OrderConnection, j as OrderPageInfo, k as OrdersOptions, R as ROUTING_LOCALE_HEADER, l as ROUTING_ORIGINAL_PATHNAME_HEADER, m as RequestLoginCodeInput, n as RequestLoginCodeResult, S as StorefrontExecutionContext, o as StorefrontMarketContext, p as StrippedLocalePath, V as VerifyLoginCodeInput, W as WithCache, q as createKotaoContext, r as createWithCache, t as isLocalePathSegment, u as localeFromAcceptLanguage, v as localeFromPathname, w as localeFromRequest, x as localizePath, y as marketContextFromHeaders, z as originalPathnameFromRequest, B as signGeo, D as stripLocalePrefixFromPathname, s as stripLocalePrefixFromRequest, E as trustedShopOriginFromHeaders, F as verifyGeo } from './routing-D2GFXAa0.js';
12
- export { AUTO_REDIRECT_LANGUAGE_HEADER, CHECKOUT_BLOCK_POSITIONS, CHECKOUT_BLOCK_TYPES, CHECKOUT_EDITOR_PAGES, CHECKOUT_FIELDS_ATTRIBUTE, CHECKOUT_FIELDS_LIMIT, CHECKOUT_FIELD_TYPES, CHECKOUT_GIFT_NOTE_MAX_LENGTH, CHECKOUT_PAYMENT_METHODS, CHECKOUT_PAYMENT_RULES_ATTRIBUTE, CheckoutBlockPosition, CheckoutBlockType, CheckoutContentBlock, CheckoutContentPosition, CheckoutCustomFieldSettings, CheckoutCustomFieldSettingsSchema, CheckoutCustomization, CheckoutEditorPage, CheckoutFieldSnapshot, CheckoutFieldValue, CheckoutGiftNote, CheckoutGiftNoteSettingsSchema, CheckoutPaymentMethod, CheckoutProductOffer, CheckoutReviewSettingsSchema, CheckoutRule, CheckoutRuleConditions, CheckoutRuleConditionsSchema, CheckoutRuleContext, CheckoutRuleSchema, CheckoutRulesSchema, CheckoutShippingNotice, CheckoutShippingNoticeSettingsSchema, 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, POST_PURCHASE_BLOCK_POSITIONS, applyCheckoutFieldRules, applyCheckoutShippingRules, autoRedirectEnabled, checkoutBlockAllowedAt, checkoutBlockSettingsSchema, checkoutPageBlockAllowedAt, checkoutPagePositions, checkoutRuleMatches, checkoutShippingNoticeVisible, evaluateCheckoutRules, isCheckoutBlockPosition, isCheckoutBlockType, localizeCheckoutField, readCheckoutCustomization, readCheckoutFieldSnapshots, readCheckoutPaymentExclusions, validateCheckoutFields } from '@kotao/storefront-contracts';
10
+ import { C as CustomerAccountClient } from './routing-hrvYWYEV.js';
11
+ export { A as Address, c as AddressConnection, d as CustomerAccount, e as CustomerAccountError, f as CustomerAccountErrorCode, G as GEO_HEADER, g as GEO_SIGNATURE_HEADER, h as Geo, K as KotaoContext, a as KotaoEnv, b as KotaoSession, L as LocalizePathOptions, M as Money, O as Order, i as OrderConnection, j as OrderPageInfo, k as OrdersOptions, R as ROUTING_LOCALE_HEADER, l as ROUTING_ORIGINAL_PATHNAME_HEADER, m as RequestLoginCodeInput, n as RequestLoginCodeResult, S as StorefrontExecutionContext, o as StorefrontMarketContext, p as StrippedLocalePath, V as VerifyLoginCodeInput, W as WithCache, q as createKotaoContext, r as createWithCache, t as isLocalePathSegment, u as localeFromAcceptLanguage, v as localeFromPathname, w as localeFromRequest, x as localizePath, y as marketContextFromHeaders, z as originalPathnameFromRequest, B as signGeo, D as stripLocalePrefixFromPathname, s as stripLocalePrefixFromRequest, E as trustedShopOriginFromHeaders, F as verifyGeo } from './routing-hrvYWYEV.js';
12
+ export { AUTO_REDIRECT_LANGUAGE_HEADER, CHECKOUT_BLOCK_POSITIONS, CHECKOUT_BLOCK_TYPES, CHECKOUT_EDITOR_PAGES, CHECKOUT_FIELDS_ATTRIBUTE, CHECKOUT_FIELDS_LIMIT, CHECKOUT_FIELD_TYPES, CHECKOUT_GIFT_NOTE_MAX_LENGTH, CHECKOUT_PAYMENT_METHODS, CHECKOUT_PAYMENT_RULES_ATTRIBUTE, CONSENT_BANNER_DEFAULT_COPY, CONSENT_BANNER_LOCALES, CheckoutBlockPosition, CheckoutBlockType, CheckoutCartEditing, CheckoutCartEditingSchema, CheckoutContentBlock, CheckoutContentPosition, CheckoutCustomFieldSettings, CheckoutCustomFieldSettingsSchema, CheckoutCustomization, CheckoutEditorPage, CheckoutFieldSnapshot, CheckoutFieldValue, CheckoutGiftNote, CheckoutGiftNoteSettingsSchema, CheckoutLayout, CheckoutLayoutSchema, CheckoutPaymentMethod, CheckoutProductOffer, CheckoutReviewSettingsSchema, CheckoutRule, CheckoutRuleConditions, CheckoutRuleConditionsSchema, CheckoutRuleContext, CheckoutRuleSchema, CheckoutRulesSchema, CheckoutShippingNotice, CheckoutShippingNoticeSettingsSchema, ConsentBannerCopy, ConsentBannerLocale, 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, POST_PURCHASE_BLOCK_POSITIONS, applyCheckoutFieldRules, applyCheckoutShippingRules, autoRedirectEnabled, checkoutBlockAllowedAt, checkoutBlockSettingsSchema, checkoutPageBlockAllowedAt, checkoutPagePositions, checkoutRuleMatches, checkoutShippingNoticeVisible, evaluateCheckoutRules, isCheckoutBlockPosition, isCheckoutBlockType, localizeCheckoutField, readCheckoutCustomization, readCheckoutFieldSnapshots, readCheckoutPaymentExclusions, validateCheckoutFields } from '@kotao/storefront-contracts';
13
13
  export { ImageAttrs, ImageAttrsOptions, ImageCrop, ImageData, ImageFit, ImageFormat, ImageSrcSetOptions, ImageUrlOptions, buildImageAttrs, imageSrcSet, imageUrl } from './image.js';
14
- export { C as Connection, a as ConnectionEdge, F as FlattenableConnection, b as PageInfo, P as PaginationInfo, c as PaginationOptions, d as PaginationVariables, f as flattenConnection, g as getPaginationInfo, e as getPaginationVariables } from './pagination-DCrQk02Q.js';
14
+ export { C as Connection, a as ConnectionEdge, F as FlattenableConnection, P as PageInfo, b as PaginationInfo, c as PaginationOptions, d as PaginationVariables, f as flattenConnection, g as getPaginationInfo, e as getPaginationVariables } from './pagination-CPgH3fAa.js';
15
15
  export { MappedProductOptions, ProductLike, ProductOptionDef, ProductOptionState, ProductOptionValueState, SelectedOption, SelectedOptionsMap, VariantLike, VariantSelectionLike, getAdjacentAndFirstAvailableVariants, getProductOptions, getSelectedProductOptions, getSelectedVariant, mapSelectedProductOptionToObject, useOptimisticVariant, useSelectedOptionInUrlParam } from './product.js';
16
16
  export { ResolveThemeSettingsArgs, mergeSection, mergeSettings, reconcileSyntheticSectionGroup, resolveThemeSettings } from './settings.js';
17
17
  export { F as FetchThemeSettingsOptions, S as StoredThemeSettings, f as fetchThemeSettings } from './fetch-Bq_cc8_G.js';
18
18
  export { AddressInput, BreadcrumbItem, ChangeFreq, GeoInput, LocalBusinessInput, OfferInput, OrganizationInput, ProductJsonLdInput, RedirectLookup, RedirectOptions, RobotsOptions, SitemapEntry, SitemapIndexEntry, StorefrontRedirectOptions, URL_REDIRECT_QUERY, WebSiteInput, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, getSeoMeta, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, serializeJsonLd, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd } from './seo.js';
19
19
  export { A as Alternate, J as JsonLd, O as OpenGraph, a as OpenGraphImage, S as SeoConfig, b as SeoDescriptor, T as TwitterCard } from './types-BkY0yET-.js';
20
- export { c as FormAnswer, a as FormAnswers, d as FormBlock, e as FormField, b as FormFieldErrors, f as FormLocalizedText, g as FormRenderState, h as FormSubmission, F as FormVersionSchema, i as FormVisibilityRule, P as PublicForm, j as PublicFormDefinition, k as PublicFormVersion } from './types-CSNXbGFW.js';
20
+ export { a as FormAnswer, b as FormAnswers, c as FormBlock, d as FormField, e as FormFieldErrors, f as FormLocalizedText, g as FormRenderState, h as FormSubmission, F as FormVersionSchema, i as FormVisibilityRule, P as PublicForm, j as PublicFormDefinition, k as PublicFormVersion } from './types-BTUTZXxJ.js';
21
21
  export { ADDRESS_PROPERTIES, FORM_ANSWER_PREFIX, FormFetchOptions, RenderFormHtmlOptions, ShopifyContactCompatibility, ShopifyContactInput, StorefrontFormRequestError, SubmitFormInput, adaptShopifyContactForm, evaluateFormRule, formAnswerName, formFields, isFormFieldVisible, loadPublishedForm, parseFormAnswers, renderFormHtml, resolveFormText, submitPublishedForm } from './forms.js';
22
22
  export { EventCartPreparationError, eventCartToken, prepareEventCart } from './events.js';
23
- export { C as ClaimEventApprovalOffer, d as CreateEventApprovalRequest, e as CreateEventCheckoutSession, f as CreateEventWaitlistEntry, b as EventApprovalOfferResolution, g as EventApprovalRequestReceipt, a as EventCheckoutSession, h as EventFormAnswer, i as EventFormSubmissionInput, j as EventRegistrationMode, k as EventRegistrationResult, c as EventRegistrationSubmission, l as EventWaitlistReceipt, E as EventsClient, P as PublicEvent, m as PublicEventForm, n as PublicEventOccurrence, o as PublicEventSummary, p as PublicEventTicketType, q as PublicEventVenue, S as StorefrontEventsRequestError, r as createEventsClient } from './client-D-M3Y1ul.js';
23
+ export { C as ClaimEventApprovalOffer, d as CreateEventApprovalRequest, e as CreateEventCheckoutSession, f as CreateEventWaitlistEntry, b as EventApprovalOfferResolution, g as EventApprovalRequestReceipt, a as EventCheckoutSession, h as EventFormAnswer, i as EventFormSubmissionInput, j as EventRegistrationMode, k as EventRegistrationResult, c as EventRegistrationSubmission, l as EventWaitlistReceipt, E as EventsClient, P as PublicEvent, m as PublicEventForm, n as PublicEventOccurrence, o as PublicEventSummary, p as PublicEventTicketType, q as PublicEventVenue, S as StorefrontEventsRequestError, r as createEventsClient } from './client-Bt8EEr-K.js';
24
24
  export { a as OfferTokenHistory, O as OfferTokenLocation, c as consumeOfferTokenFragment, o as offerTokenHrefMarker } from './offer-token-C-nk_nj8.js';
25
25
  export { C as CreateStorefrontEditorBridgeArgs, b as CreateStorefrontEditorHostBridgeArgs, c as StorefrontEditorAppExtensionPreview, d as StorefrontEditorBlockSchema, e as StorefrontEditorBridge, f as StorefrontEditorCanvasAction, g as StorefrontEditorCanvasBlockAction, h as StorefrontEditorCanvasPosition, i as StorefrontEditorCanvasSectionAction, j as StorefrontEditorDocument, k as StorefrontEditorHostBridge, l as StorefrontEditorMessageEvent, S as StorefrontEditorMessageSource, a as StorefrontEditorMessageTarget, m as StorefrontEditorNavigationRequest, n as StorefrontEditorReady, o as StorefrontEditorRect, p as StorefrontEditorSectionPreset, q as StorefrontEditorSectionPresetBlock, r as StorefrontEditorSectionSchema, s as StorefrontEditorSelection, t as StorefrontEditorSelectionScope, u as StorefrontEditorSettingInput, v as StorefrontEditorSettingOption, w as StorefrontEditorThemeStyle, y as createStorefrontEditorBridge, z as createStorefrontEditorHostBridge, A as positionStorefrontEditorCanvasToolbar } from './bridge-CfNBWu0H.js';
26
26
  export { S as STOREFRONT_SECTION_CUSTOM_CSS_SETTING, s as scopeStorefrontSectionCss } from './custom-css-Bl7Ur3-H.js';
27
27
  import './http-types-CGh8WGHB.js';
28
- import 'react';
29
28
  import './storefront-api-types.js';
30
29
  import '@kotao/storefront-contracts/theme';
31
30
 
@@ -120,24 +119,6 @@ declare const CHECKOUT_DESIGN_TOKEN_INPUTS: ({
120
119
  })[];
121
120
  declare function extractCheckoutDesignTokens(snapshot: Pick<ThemeSettingsSnapshot, 'global'>): CheckoutDesignTokens;
122
121
 
123
- interface ContentSecurityPolicyShop {
124
- readonly checkoutDomain?: string;
125
- readonly storeDomain?: string;
126
- }
127
- interface CreateContentSecurityPolicyOptions {
128
- readonly shop?: ContentSecurityPolicyShop;
129
- readonly scriptSrc?: readonly string[];
130
- readonly connectSrc?: readonly string[];
131
- readonly imgSrc?: readonly string[];
132
- readonly styleSrc?: readonly string[];
133
- }
134
- interface ContentSecurityPolicyResult {
135
- readonly nonce: string;
136
- readonly header: string;
137
- readonly NonceProvider: BoundNonceProvider;
138
- }
139
- declare function createContentSecurityPolicy(options?: CreateContentSecurityPolicyOptions): ContentSecurityPolicyResult;
140
-
141
122
  declare const LOCALIZATION_COOKIE = "kotao_localization";
142
123
  declare function readLocalizationCookie(cookieHeader: string | null | undefined): {
143
124
  country: string | null;
@@ -274,4 +255,4 @@ interface HostedLocaleInput {
274
255
  */
275
256
  declare function resolveHostedLocale(input: HostedLocaleInput): string;
276
257
 
277
- export { type AnalyticsAttributionEnvironment, AnalyticsContext, CART_ID_COOKIE, CHECKOUT_CONSENT_CATEGORIES, CHECKOUT_CONSENT_PARAM_PREFIX, CHECKOUT_DESIGN_TOKEN_INPUTS, CUSTOMER_SESSION_COOKIE, Cart, CartDispatchAction, CartHandler, type CheckoutDesignTokens, ConsentBucket, ConsentState, type ContentSecurityPolicyResult, type ContentSecurityPolicyShop, type CreateContentSecurityPolicyOptions, CustomerAccountClient, type CustomerAccountClientOptions, DEFAULT_HOSTED_SESSION_MAX_AGE, DEFAULT_SESSION_MAX_AGE, HOSTED_CUSTOMER_CSRF_COOKIE, HOSTED_CUSTOMER_CSRF_HEADER, HOSTED_CUSTOMER_SESSION_COOKIE, type HostedLocaleInput, type HostedSessionCookieAttrs, LOCALIZATION_COOKIE, type LegacySessionReadOptions, MAX_HOSTED_SESSION_MAX_AGE, MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH, type ResolveCheckoutUrlOptions, ResolvedSettings, type SessionCookieAttrs, ThemeSettingsSnapshot, appendConsentToCheckoutUrl, applyOptimisticCartAction, buildCartIdCookie, buildCustomerSessionCookie, buildHostedCustomerSessionCookie, buildLocalizationCookie, clearCartIdCookie, clearCustomerSessionCookie, clearHostedCustomerSessionCookie, clearLegacyCustomerSessionCookie, collectAnalyticsAttribution, createContentSecurityPolicy, createCustomerAccountClient, decodeCheckoutConsent, decodeConsent, encodeCheckoutConsent, encodeConsent, escapeHostedHtml, extractCheckoutDesignTokens, handleLocalizationPost, readCartIdCookie, readCustomerSessionToken, readHostedCustomerCsrfToken, readHostedCustomerSessionToken, readLegacyCustomerSessionToken, readLocalizationCookie, resolveCheckoutUrl, resolveHostedBranding, resolveHostedLocale, sanitizeHostedCssValue, shopHostname, useOptimisticCart };
258
+ export { type AnalyticsAttributionEnvironment, AnalyticsContext, CART_ID_COOKIE, CHECKOUT_CONSENT_CATEGORIES, CHECKOUT_CONSENT_PARAM_PREFIX, CHECKOUT_DESIGN_TOKEN_INPUTS, CUSTOMER_SESSION_COOKIE, Cart, CartDispatchAction, CartHandler, type CheckoutDesignTokens, ConsentBucket, ConsentState, CustomerAccountClient, type CustomerAccountClientOptions, DEFAULT_HOSTED_SESSION_MAX_AGE, DEFAULT_SESSION_MAX_AGE, HOSTED_CUSTOMER_CSRF_COOKIE, HOSTED_CUSTOMER_CSRF_HEADER, HOSTED_CUSTOMER_SESSION_COOKIE, type HostedLocaleInput, type HostedSessionCookieAttrs, LOCALIZATION_COOKIE, type LegacySessionReadOptions, MAX_HOSTED_SESSION_MAX_AGE, MAX_LEGACY_CUSTOMER_SESSION_TOKEN_LENGTH, type ResolveCheckoutUrlOptions, ResolvedSettings, type SessionCookieAttrs, ThemeSettingsSnapshot, appendConsentToCheckoutUrl, applyOptimisticCartAction, buildCartIdCookie, buildCustomerSessionCookie, buildHostedCustomerSessionCookie, buildLocalizationCookie, clearCartIdCookie, clearCustomerSessionCookie, clearHostedCustomerSessionCookie, clearLegacyCustomerSessionCookie, collectAnalyticsAttribution, createCustomerAccountClient, decodeCheckoutConsent, decodeConsent, encodeCheckoutConsent, encodeConsent, escapeHostedHtml, extractCheckoutDesignTokens, handleLocalizationPost, readCartIdCookie, readCustomerSessionToken, readHostedCustomerCsrfToken, readHostedCustomerSessionToken, readLegacyCustomerSessionToken, readLocalizationCookie, resolveCheckoutUrl, resolveHostedBranding, resolveHostedLocale, sanitizeHostedCssValue, shopHostname, useOptimisticCart };
package/dist/index.js CHANGED
@@ -1,9 +1,8 @@
1
1
  export { getAdjacentAndFirstAvailableVariants, getProductOptions, getSelectedProductOptions, getSelectedVariant, mapSelectedProductOptionToObject, useOptimisticVariant, useSelectedOptionInUrlParam } from './chunk-QOEEUTHQ.js';
2
- import { createNonceProvider } from './chunk-BV4OLXV4.js';
3
- export { CartForm, collectAnalyticsAttribution, createAnalyticsBus, createAnalyticsEmitter, createPixelTransport } from './chunk-BV4OLXV4.js';
2
+ export { CartForm, collectAnalyticsAttribution, createAnalyticsBus, createAnalyticsEmitter, createContentSecurityPolicy, createPixelTransport } from './chunk-NRWS7HJ2.js';
4
3
  export { flattenConnection, getPaginationInfo, getPaginationVariables } from './chunk-5QOFKGKD.js';
5
- import { CHECKOUT_DESIGN_TOKEN_INPUTS, readLocalizationCookie, localizePath, buildLocalizationCookie, extractCheckoutDesignTokens } from './chunk-XZVCUAZU.js';
6
- 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, 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, 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 } from './chunk-XZVCUAZU.js';
4
+ import { CHECKOUT_DESIGN_TOKEN_INPUTS, readLocalizationCookie, localizePath, buildLocalizationCookie, extractCheckoutDesignTokens } from './chunk-4OELOXCN.js';
5
+ 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, 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, 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 } from './chunk-4OELOXCN.js';
7
6
  import { CART_FORM_ACTIONS, CONSENT_BUCKETS } from './chunk-GR4QJ7EC.js';
8
7
  export { CART_FORM_ACTIONS, CONSENT_BUCKETS, CONSENT_COOKIE, DENIED_CONSENT, GRANTED_CONSENT, buildConsentCookie, isGranted, mergeConsent, parseConsent, readConsentCookie, serializeConsent } from './chunk-GR4QJ7EC.js';
9
8
  export { URL_REDIRECT_QUERY, breadcrumbListJsonLd, buildRobotsTxt, buildSitemapIndexXml, buildSitemapXml, localBusinessJsonLd, organizationJsonLd, productJsonLd, resolveRedirect, resolveStorefrontRedirect, restaurantJsonLd, robotsResponse, sitemapIndexResponse, sitemapResponse, storefrontRedirect, websiteJsonLd } from './chunk-W74FGUZH.js';
@@ -18,7 +17,7 @@ export { StorefrontEventsRequestError, createEventsClient } from './chunk-R4N565
18
17
  export { ADDRESS_PROPERTIES, FORM_ANSWER_PREFIX, StorefrontFormRequestError, adaptShopifyContactForm, evaluateFormRule, formAnswerName, formFields, isFormFieldVisible, loadPublishedForm, parseFormAnswers, renderFormHtml, resolveFormText, submitPublishedForm } from './chunk-IIOHENCG.js';
19
18
  export { buildImageAttrs, imageSrcSet, imageUrl } from './chunk-PWVXOMDE.js';
20
19
  import { MARKET_PATH_PREFIX_HEADER } from '@kotao/storefront-contracts';
21
- export { AUTO_REDIRECT_LANGUAGE_HEADER, CHECKOUT_BLOCK_POSITIONS, CHECKOUT_BLOCK_TYPES, CHECKOUT_EDITOR_PAGES, CHECKOUT_FIELDS_ATTRIBUTE, CHECKOUT_FIELDS_LIMIT, CHECKOUT_FIELD_TYPES, CHECKOUT_GIFT_NOTE_MAX_LENGTH, CHECKOUT_PAYMENT_METHODS, CHECKOUT_PAYMENT_RULES_ATTRIBUTE, CheckoutCustomFieldSettingsSchema, CheckoutGiftNoteSettingsSchema, CheckoutReviewSettingsSchema, CheckoutRuleConditionsSchema, CheckoutRuleSchema, CheckoutRulesSchema, CheckoutShippingNoticeSettingsSchema, POST_PURCHASE_BLOCK_POSITIONS, applyCheckoutFieldRules, applyCheckoutShippingRules, autoRedirectEnabled, checkoutBlockAllowedAt, checkoutBlockSettingsSchema, checkoutPageBlockAllowedAt, checkoutPagePositions, checkoutRuleMatches, checkoutShippingNoticeVisible, evaluateCheckoutRules, isCheckoutBlockPosition, isCheckoutBlockType, localizeCheckoutField, readCheckoutCustomization, readCheckoutFieldSnapshots, readCheckoutPaymentExclusions, validateCheckoutFields } from '@kotao/storefront-contracts';
20
+ export { AUTO_REDIRECT_LANGUAGE_HEADER, CHECKOUT_BLOCK_POSITIONS, CHECKOUT_BLOCK_TYPES, CHECKOUT_EDITOR_PAGES, CHECKOUT_FIELDS_ATTRIBUTE, CHECKOUT_FIELDS_LIMIT, CHECKOUT_FIELD_TYPES, CHECKOUT_GIFT_NOTE_MAX_LENGTH, CHECKOUT_PAYMENT_METHODS, CHECKOUT_PAYMENT_RULES_ATTRIBUTE, CONSENT_BANNER_DEFAULT_COPY, CONSENT_BANNER_LOCALES, CheckoutCartEditingSchema, CheckoutCustomFieldSettingsSchema, CheckoutGiftNoteSettingsSchema, CheckoutLayoutSchema, CheckoutReviewSettingsSchema, CheckoutRuleConditionsSchema, CheckoutRuleSchema, CheckoutRulesSchema, CheckoutShippingNoticeSettingsSchema, POST_PURCHASE_BLOCK_POSITIONS, applyCheckoutFieldRules, applyCheckoutShippingRules, autoRedirectEnabled, checkoutBlockAllowedAt, checkoutBlockSettingsSchema, checkoutPageBlockAllowedAt, checkoutPagePositions, checkoutRuleMatches, checkoutShippingNoticeVisible, evaluateCheckoutRules, isCheckoutBlockPosition, isCheckoutBlockType, localizeCheckoutField, readCheckoutCustomization, readCheckoutFieldSnapshots, readCheckoutPaymentExclusions, validateCheckoutFields } from '@kotao/storefront-contracts';
22
21
 
23
22
  // src/cart/useOptimisticCart.ts
24
23
  var recalculate = (cart, lines) => ({
@@ -69,79 +68,6 @@ function applyOptimisticCartAction(cart, action) {
69
68
  function useOptimisticCart(cart, action) {
70
69
  return action ? applyOptimisticCartAction(cart, action) : cart;
71
70
  }
72
-
73
- // src/content-security-policy.ts
74
- var QUOTED_TOKENS = /* @__PURE__ */ new Set([
75
- "self",
76
- "none",
77
- "unsafe-eval",
78
- "unsafe-hashes",
79
- "unsafe-inline",
80
- "strict-dynamic",
81
- "wasm-unsafe-eval"
82
- ]);
83
- function createContentSecurityPolicy(options = {}) {
84
- const nonce = createNonce();
85
- const shopDomains = shopSources(options.shop);
86
- const scriptSrc = uniqueSources([
87
- ...normalizeSources(options.scriptSrc ?? ["self"]),
88
- `'nonce-${nonce}'`
89
- ]);
90
- const connectSrc = uniqueSources([
91
- "self",
92
- ...shopDomains,
93
- ...normalizeSources(options.connectSrc)
94
- ]);
95
- const imgSrc = uniqueSources([
96
- "self",
97
- "data:",
98
- "https:",
99
- ...shopDomains,
100
- ...normalizeSources(options.imgSrc)
101
- ]);
102
- const styleSrc = uniqueSources(["self", "unsafe-inline", ...normalizeSources(options.styleSrc)]);
103
- const directives = [
104
- ["base-uri", ["'self'"]],
105
- ["default-src", ["'self'"]],
106
- ["connect-src", connectSrc],
107
- ["img-src", imgSrc],
108
- ["script-src", scriptSrc],
109
- ["style-src", styleSrc]
110
- ];
111
- return {
112
- nonce,
113
- header: directives.map(([name, values]) => `${name} ${values.join(" ")}`).join("; "),
114
- NonceProvider: createNonceProvider(nonce)
115
- };
116
- }
117
- function createNonce() {
118
- const bytes = new Uint8Array(18);
119
- const runtimeCrypto = globalThis.crypto;
120
- if (runtimeCrypto?.getRandomValues !== void 0) {
121
- runtimeCrypto.getRandomValues(bytes);
122
- } else {
123
- for (let i = 0; i < bytes.length; i += 1) {
124
- bytes[i] = Math.floor(Math.random() * 256);
125
- }
126
- }
127
- return Array.from(bytes, (byte) => byte.toString(16).padStart(2, "0")).join("");
128
- }
129
- function shopSources(shop) {
130
- if (shop === void 0) return [];
131
- return [shop.storeDomain, shop.checkoutDomain].filter((domain) => domain !== void 0 && domain.trim() !== "").map((domain) => {
132
- const trimmed = domain.trim();
133
- return /^https?:\/\//i.test(trimmed) ? new URL(trimmed).origin : `https://${trimmed}`;
134
- });
135
- }
136
- function normalizeSources(sources) {
137
- return (sources ?? []).map((source) => {
138
- const trimmed = source.trim();
139
- return QUOTED_TOKENS.has(trimmed) ? `'${trimmed}'` : trimmed;
140
- });
141
- }
142
- function uniqueSources(sources) {
143
- return Array.from(new Set(sources.filter((source) => source.length > 0)));
144
- }
145
71
  function safeReturnTo(raw) {
146
72
  if (raw === null || raw === "") return { path: "/", safe: true };
147
73
  return /^\/(?![/\\])/.test(raw) ? { path: raw, safe: true } : { path: "/", safe: false };
@@ -271,6 +197,6 @@ function safelyReadCookieLocale(cookieHeader) {
271
197
  }
272
198
  }
273
199
 
274
- export { ANALYTICS_EVENTS, appendConsentToCheckoutUrl, applyOptimisticCartAction, createContentSecurityPolicy, decodeConsent, encodeConsent, escapeHostedHtml, getShopAnalytics, handleLocalizationPost, resolveHostedBranding, resolveHostedLocale, sanitizeHostedCssValue, useOptimisticCart };
200
+ export { ANALYTICS_EVENTS, appendConsentToCheckoutUrl, applyOptimisticCartAction, decodeConsent, encodeConsent, escapeHostedHtml, getShopAnalytics, handleLocalizationPost, resolveHostedBranding, resolveHostedLocale, sanitizeHostedCssValue, useOptimisticCart };
275
201
  //# sourceMappingURL=index.js.map
276
202
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cart/useOptimisticCart.ts","../src/content-security-policy.ts","../src/localization/handler.ts","../src/analytics/events.ts","../src/analytics/shop.ts","../src/analytics/consent-encoding.ts","../src/hosted-surface/branding.ts","../src/hosted-surface/localization.ts"],"names":["MARKET_PATH_PREFIX_HEADER"],"mappings":"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","file":"index.js","sourcesContent":["import { CART_FORM_ACTIONS } from './actions'\nimport type { CartDispatchAction } from './createCartHandler'\nimport type { Cart, CartLine } from './types'\n\nconst recalculate = (cart: Cart, lines: readonly CartLine[]): Cart => ({\n ...cart,\n lines,\n totalQuantity: lines.reduce((sum, line) => sum + line.quantity, 0),\n})\n\nexport function applyOptimisticCartAction(cart: Cart, action: CartDispatchAction): Cart {\n switch (action.action) {\n case CART_FORM_ACTIONS.LinesAdd: {\n const inputLines = (action.inputs.lines ?? []) as Array<{\n merchandiseId: string\n quantity?: number | null\n }>\n const additions = inputLines.map<CartLine>((line) => ({\n id: `optimistic:${line.merchandiseId}`,\n quantity: line.quantity ?? 1,\n merchandise: { id: line.merchandiseId },\n attributes: [],\n }))\n return recalculate(cart, [...cart.lines, ...additions])\n }\n case CART_FORM_ACTIONS.LinesUpdate: {\n const updates = new Map(\n ((action.inputs.lines ?? []) as Array<{ id: string; quantity?: number | null }>).map(\n (line) => [line.id, line],\n ),\n )\n const lines = cart.lines\n .map((line) => {\n const update = updates.get(line.id)\n if (!update) return line\n if (update.quantity === 0) return null\n return {\n ...line,\n quantity: update.quantity ?? line.quantity,\n }\n })\n .filter((line): line is CartLine => line !== null)\n return recalculate(cart, lines)\n }\n case CART_FORM_ACTIONS.LinesRemove: {\n const remove = new Set((action.inputs.lineIds ?? []) as string[])\n return recalculate(\n cart,\n cart.lines.filter((line) => !remove.has(line.id)),\n )\n }\n default:\n return cart\n }\n}\n\n/**\n * Pure optimistic helper for React integrations. A React wrapper can call this from `useOptimistic`;\n * keeping the reducer pure lets non-React tests exercise the exact overlay behavior.\n */\nexport function useOptimisticCart(cart: Cart, action: CartDispatchAction | null): Cart {\n return action ? applyOptimisticCartAction(cart, action) : cart\n}\n","import { createNonceProvider, type BoundNonceProvider } from './react/nonce'\n\nexport interface ContentSecurityPolicyShop {\n readonly checkoutDomain?: string\n readonly storeDomain?: string\n}\n\nexport interface CreateContentSecurityPolicyOptions {\n readonly shop?: ContentSecurityPolicyShop\n readonly scriptSrc?: readonly string[]\n readonly connectSrc?: readonly string[]\n readonly imgSrc?: readonly string[]\n readonly styleSrc?: readonly string[]\n}\n\nexport interface ContentSecurityPolicyResult {\n readonly nonce: string\n readonly header: string\n readonly NonceProvider: BoundNonceProvider\n}\n\nconst QUOTED_TOKENS = new Set([\n 'self',\n 'none',\n 'unsafe-eval',\n 'unsafe-hashes',\n 'unsafe-inline',\n 'strict-dynamic',\n 'wasm-unsafe-eval',\n])\n\nexport function createContentSecurityPolicy(\n options: CreateContentSecurityPolicyOptions = {},\n): ContentSecurityPolicyResult {\n const nonce = createNonce()\n const shopDomains = shopSources(options.shop)\n const scriptSrc = uniqueSources([\n ...normalizeSources(options.scriptSrc ?? ['self']),\n `'nonce-${nonce}'`,\n ])\n const connectSrc = uniqueSources([\n 'self',\n ...shopDomains,\n ...normalizeSources(options.connectSrc),\n ])\n const imgSrc = uniqueSources([\n 'self',\n 'data:',\n 'https:',\n ...shopDomains,\n ...normalizeSources(options.imgSrc),\n ])\n const styleSrc = uniqueSources(['self', 'unsafe-inline', ...normalizeSources(options.styleSrc)])\n const directives = [\n ['base-uri', [\"'self'\"]],\n ['default-src', [\"'self'\"]],\n ['connect-src', connectSrc],\n ['img-src', imgSrc],\n ['script-src', scriptSrc],\n ['style-src', styleSrc],\n ]\n return {\n nonce,\n header: directives\n .map(([name, values]) => `${name} ${(values as readonly string[]).join(' ')}`)\n .join('; '),\n NonceProvider: createNonceProvider(nonce),\n }\n}\n\nfunction createNonce(): string {\n const bytes = new Uint8Array(18)\n const runtimeCrypto = (globalThis as typeof globalThis & { crypto?: Crypto }).crypto\n if (runtimeCrypto?.getRandomValues !== undefined) {\n runtimeCrypto.getRandomValues(bytes)\n } else {\n for (let i = 0; i < bytes.length; i += 1) {\n bytes[i] = Math.floor(Math.random() * 256)\n }\n }\n return Array.from(bytes, (byte) => byte.toString(16).padStart(2, '0')).join('')\n}\n\nfunction shopSources(shop: ContentSecurityPolicyShop | undefined): readonly string[] {\n if (shop === undefined) return []\n return [shop.storeDomain, shop.checkoutDomain]\n .filter((domain): domain is string => domain !== undefined && domain.trim() !== '')\n .map((domain) => {\n const trimmed = domain.trim()\n return /^https?:\\/\\//i.test(trimmed) ? new URL(trimmed).origin : `https://${trimmed}`\n })\n}\n\nfunction normalizeSources(sources: readonly string[] | undefined): readonly string[] {\n return (sources ?? []).map((source) => {\n const trimmed = source.trim()\n return QUOTED_TOKENS.has(trimmed) ? `'${trimmed}'` : trimmed\n })\n}\n\nfunction uniqueSources(sources: readonly string[]): readonly string[] {\n return Array.from(new Set(sources.filter((source) => source.length > 0)))\n}\n","import { MARKET_PATH_PREFIX_HEADER } from '@kotao/storefront-contracts'\nimport type { CartHandler } from '../cart/createCartHandler'\nimport { buildLocalizationCookie, readLocalizationCookie } from './cookie'\nimport { localizePath } from './routing'\n\n/** Same-origin path only: must start with a single '/', not '//' or '/\\'. */\nfunction safeReturnTo(raw: string | null): { path: string; safe: boolean } {\n if (raw === null || raw === '') return { path: '/', safe: true }\n return /^\\/(?![/\\\\])/.test(raw) ? { path: raw, safe: true } : { path: '/', safe: false }\n}\n\nexport async function handleLocalizationPost(\n request: Request,\n context?: { readonly cart?: Pick<CartHandler, 'get' | 'updateBuyerIdentity'> },\n): Promise<Response> {\n const form = await request.formData()\n // Shopify localization forms may include the current value as a hidden input before the clicked\n // submit button with the same name. FormData preserves DOM order, so the successful submitter is\n // the final value and must win over the stale hidden default.\n const previous = readLocalizationCookie(request.headers.get('cookie'))\n const country = form.has('country_code')\n ? (form.getAll('country_code').at(-1) ?? '').toString().trim().toUpperCase() || null\n : previous.country\n const locale = form.has('locale_code')\n ? (form.getAll('locale_code').at(-1) ?? '').toString().trim() || null\n : previous.locale\n if ((form.has('country_code') && country === null) || (country !== null && !/^[A-Z]{2}$/.test(country))) {\n return new Response('Invalid country', { status: 400 })\n }\n const primaryLocale = (form.get('primary_locale') ?? '').toString().trim() || null\n const returnTo = safeReturnTo((form.get('return_to') ?? '').toString())\n const location =\n returnTo.safe && primaryLocale !== null\n ? localizePath(returnTo.path, locale, {\n primaryLocale,\n marketPathPrefix: request.headers.get(MARKET_PATH_PREFIX_HEADER),\n })\n : returnTo.path\n const headers = new Headers({ location })\n // Do not create a cart just to change language/country. When one exists, update it before\n // committing the browsing preference so the following checkout uses the same destination.\n if (country !== null && form.has('country_code') && context?.cart !== undefined) {\n const cart = await context.cart.get()\n if (cart !== null && cart.buyerIdentity.countryCode !== country) {\n const result = await context.cart.updateBuyerIdentity({ countryCode: country })\n if (result.cart === null || result.userErrors.length > 0) {\n return new Response('Unable to update cart country', { status: 409 })\n }\n const cartCookie = result.headers.get('set-cookie')\n if (cartCookie !== null) headers.append('set-cookie', cartCookie)\n }\n }\n headers.append('set-cookie', buildLocalizationCookie({ country, locale }))\n return new Response(null, {\n status: 302,\n headers,\n })\n}\n","/**\n * Coarse visitor geo attached to pixel events — structurally the SDK's `context.geo` (a `Geo` value is\n * assignable here). Declared locally so the analytics surface (and its DOM/React preset) need not pull\n * in the geo crypto module.\n */\nexport interface AnalyticsGeo {\n readonly country: string | null\n readonly city: string | null\n readonly colo: string | null\n readonly botScore: number | null\n readonly clientIp: string | null\n}\n\n/** The standard storefront analytics events (Hydrogen-shaped names). */\nexport const ANALYTICS_EVENTS = {\n pageViewed: 'page_viewed',\n productViewed: 'product_viewed',\n collectionViewed: 'collection_viewed',\n cartViewed: 'cart_viewed',\n searchViewed: 'search_viewed',\n productAddedToCart: 'product_added_to_cart',\n} as const\n\nexport type AnalyticsEventName = (typeof ANALYTICS_EVENTS)[keyof typeof ANALYTICS_EVENTS]\n\nexport type AnalyticsDeviceClass = 'mobile' | 'tablet' | 'desktop'\n\n/** Ambient context the provider attaches to every event before it reaches the pixel. */\nexport interface AnalyticsContext {\n readonly shopId?: string\n readonly url?: string\n readonly geo?: AnalyticsGeo\n readonly referrer?: string\n readonly utmSource?: string\n readonly utmMedium?: string\n readonly utmCampaign?: string\n readonly deviceClass?: AnalyticsDeviceClass\n}\n\nexport interface PageViewedPayload {\n readonly title?: string\n}\nexport interface ProductViewedPayload {\n readonly productId: string\n /** Stable offer id; Google Merchant Center and Google ecommerce events use this as item_id. */\n readonly variantId?: string\n readonly handle?: string\n readonly title?: string\n readonly variantTitle?: string\n readonly vendor?: string\n readonly sku?: string\n /** Major-unit price, e.g. 24.95. */\n readonly price?: number\n readonly currency?: string\n readonly quantity?: number\n}\nexport interface CollectionViewedPayload {\n readonly collectionId: string\n readonly handle?: string\n}\nexport interface CartViewedPayload {\n readonly cartId?: string\n}\nexport interface SearchViewedPayload {\n readonly query: string\n readonly resultCount?: number\n}\nexport interface ProductAddedToCartPayload {\n readonly productId: string\n readonly variantId: string\n readonly quantity: number\n readonly title?: string\n readonly variantTitle?: string\n readonly vendor?: string\n readonly sku?: string\n /** Major-unit price, e.g. 24.95. */\n readonly price?: number\n readonly currency?: string\n}\n\n/** Event name → payload (the typed pub/sub surface). */\nexport interface AnalyticsEventMap {\n page_viewed: PageViewedPayload\n product_viewed: ProductViewedPayload\n collection_viewed: CollectionViewedPayload\n cart_viewed: CartViewedPayload\n search_viewed: SearchViewedPayload\n product_added_to_cart: ProductAddedToCartPayload\n}\n\n/** A pixel-bound event: the name, its payload, the ambient context, a timestamp, and consent state. */\nexport interface PixelEvent<E extends AnalyticsEventName = AnalyticsEventName> {\n readonly event: E\n readonly payload: AnalyticsEventMap[E]\n readonly context: AnalyticsContext\n readonly timestamp: string\n /** Whether the analytics-consent bucket was granted when this event was recorded. */\n readonly consent: boolean\n}\n","export interface ShopAnalytics {\n readonly acceptedLanguage?: string\n readonly currency?: string\n readonly shopId?: string\n readonly storefrontId?: string\n}\n\nexport interface GetShopAnalyticsOptions {\n readonly publicStorefrontId?: string\n readonly storefront?: {\n readonly i18n?: {\n readonly country?: string | null\n readonly currency?: string | null\n readonly language?: string | null\n readonly pathPrefix?: string | null\n } | null\n } | null\n}\n\nexport function getShopAnalytics(options: GetShopAnalyticsOptions): ShopAnalytics {\n const language = options.storefront?.i18n?.language ?? null\n const country = options.storefront?.i18n?.country ?? null\n const currency = options.storefront?.i18n?.currency ?? null\n const acceptedLanguage =\n language != null && country != null ? `${language}-${country}` : (language ?? country)\n\n return {\n ...(acceptedLanguage != null ? { acceptedLanguage } : {}),\n ...(currency != null ? { currency } : {}),\n ...(options.publicStorefrontId != null ? { shopId: options.publicStorefrontId } : {}),\n ...(options.publicStorefrontId != null ? { storefrontId: options.publicStorefrontId } : {}),\n }\n}\n","import { CONSENT_BUCKETS, type ConsentBucket, type ConsentState } from './consent'\n\n/**\n * Encode/decode consent into the `cart.checkoutUrl` handoff (query params), mirroring Shopify's\n * server-set-consent direction (design §Checkout handoff). The handoff target is the Gateway-owned\n * same-origin `/checkout/*` path — `appendConsentToCheckoutUrl` preserves a relative URL as relative\n * so it never points at a separate subdomain.\n */\nconst PARAM_PREFIX = 'consent_'\nconst RELATIVE_BASE = 'https://kotao.invalid'\n\nexport function encodeConsent(state: ConsentState): URLSearchParams {\n const params = new URLSearchParams()\n for (const bucket of CONSENT_BUCKETS)\n params.set(`${PARAM_PREFIX}${bucket}`, state[bucket] ? '1' : '0')\n return params\n}\n\nexport function decodeConsent(params: URLSearchParams): ConsentState {\n const read = (bucket: ConsentBucket): boolean => params.get(`${PARAM_PREFIX}${bucket}`) === '1'\n return {\n analytics: read('analytics'),\n marketing: read('marketing'),\n preferences: read('preferences'),\n }\n}\n\nexport function appendConsentToCheckoutUrl(checkoutUrl: string, state: ConsentState): string {\n // The checkout handoff is the same-origin `/checkout/*` path (cart.checkoutUrl is relative). Reject\n // absolute or protocol-relative URLs so consent params never ride to another origin.\n if (!/^\\/(?!\\/)/.test(checkoutUrl)) {\n throw new Error(`checkoutUrl must be a same-origin path starting with '/'; got: ${checkoutUrl}`)\n }\n const url = new URL(checkoutUrl, RELATIVE_BASE)\n for (const [key, value] of encodeConsent(state)) url.searchParams.set(key, value)\n return `${url.pathname}${url.search}${url.hash}`\n}\n","import {\n CHECKOUT_DESIGN_TOKEN_INPUTS,\n extractCheckoutDesignTokens,\n type CheckoutDesignTokens,\n} from '../checkout/design-tokens'\nimport type { ResolvedSettings } from '../settings/types'\n\nconst CHECKOUT_TOKEN_DEFAULTS: Readonly<Record<string, string>> = Object.fromEntries(\n CHECKOUT_DESIGN_TOKEN_INPUTS.flatMap((input) =>\n 'defaultValue' in input && typeof input.defaultValue === 'string' && input.defaultValue !== ''\n ? [[input.name, input.defaultValue]]\n : [],\n ),\n)\n\n/** Resolve the token contract shared by trusted checkout and customer-account surfaces. */\nexport function resolveHostedBranding(global: ResolvedSettings): CheckoutDesignTokens {\n return extractCheckoutDesignTokens({ global: { ...CHECKOUT_TOKEN_DEFAULTS, ...global } })\n}\n\n/** Escape merchant-controlled text for an HTML text node or double-quoted attribute. */\nexport function escapeHostedHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/**\n * Strip characters that can terminate an inline CSS declaration, block, quote, or style element.\n * Trusted renderers must apply this at the CSS-value sink; the resolved token values themselves\n * remain byte-for-byte compatible with checkout's existing contract.\n */\nexport function sanitizeHostedCssValue(value: string): string {\n return value\n .replace(/[<>\"'`;{}\\\\]/g, '')\n .replace(/[\\r\\n\\t]+/g, ' ')\n .trim()\n}\n","import { readLocalizationCookie } from '../localization/cookie'\n\nexport interface HostedLocaleInput {\n readonly configuredLocales: readonly string[]\n readonly localizationCookie: string | null\n readonly customerLocale: string | null\n readonly primaryLocale: string\n}\n\n/**\n * Resolve display language within the verified shop's configured locale allowlist. Payment\n * jurisdiction and legal-copy decisions deliberately stay outside this display-only resolver.\n */\nexport function resolveHostedLocale(input: HostedLocaleInput): string {\n const configured = input.configuredLocales.map((locale) => locale.trim()).filter(Boolean)\n if (configured.length === 0) throw new Error('hosted surfaces require a configured locale')\n\n const configuredByKey = new Map(configured.map((locale) => [localeKey(locale), locale] as const))\n const cookieLocale = safelyReadCookieLocale(input.localizationCookie)\n\n for (const candidate of [cookieLocale, input.customerLocale, input.primaryLocale]) {\n if (candidate === null || candidate.trim() === '') continue\n const match = configuredByKey.get(localeKey(candidate))\n if (match !== undefined) return match\n }\n\n return configured[0]!\n}\n\nfunction localeKey(locale: string): string {\n return locale.trim().replace(/_/g, '-').toLowerCase()\n}\n\nfunction safelyReadCookieLocale(cookieHeader: string | null): string | null {\n if (cookieHeader === null) return null\n if (!cookieHeader.includes('=')) return cookieHeader.trim() || null\n try {\n return readLocalizationCookie(cookieHeader).locale\n } catch {\n return null\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/cart/useOptimisticCart.ts","../src/localization/handler.ts","../src/analytics/events.ts","../src/analytics/shop.ts","../src/analytics/consent-encoding.ts","../src/hosted-surface/branding.ts","../src/hosted-surface/localization.ts"],"names":["MARKET_PATH_PREFIX_HEADER"],"mappings":"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","file":"index.js","sourcesContent":["import { CART_FORM_ACTIONS } from './actions'\nimport type { CartDispatchAction } from './createCartHandler'\nimport type { Cart, CartLine } from './types'\n\nconst recalculate = (cart: Cart, lines: readonly CartLine[]): Cart => ({\n ...cart,\n lines,\n totalQuantity: lines.reduce((sum, line) => sum + line.quantity, 0),\n})\n\nexport function applyOptimisticCartAction(cart: Cart, action: CartDispatchAction): Cart {\n switch (action.action) {\n case CART_FORM_ACTIONS.LinesAdd: {\n const inputLines = (action.inputs.lines ?? []) as Array<{\n merchandiseId: string\n quantity?: number | null\n }>\n const additions = inputLines.map<CartLine>((line) => ({\n id: `optimistic:${line.merchandiseId}`,\n quantity: line.quantity ?? 1,\n merchandise: { id: line.merchandiseId },\n attributes: [],\n }))\n return recalculate(cart, [...cart.lines, ...additions])\n }\n case CART_FORM_ACTIONS.LinesUpdate: {\n const updates = new Map(\n ((action.inputs.lines ?? []) as Array<{ id: string; quantity?: number | null }>).map(\n (line) => [line.id, line],\n ),\n )\n const lines = cart.lines\n .map((line) => {\n const update = updates.get(line.id)\n if (!update) return line\n if (update.quantity === 0) return null\n return {\n ...line,\n quantity: update.quantity ?? line.quantity,\n }\n })\n .filter((line): line is CartLine => line !== null)\n return recalculate(cart, lines)\n }\n case CART_FORM_ACTIONS.LinesRemove: {\n const remove = new Set((action.inputs.lineIds ?? []) as string[])\n return recalculate(\n cart,\n cart.lines.filter((line) => !remove.has(line.id)),\n )\n }\n default:\n return cart\n }\n}\n\n/**\n * Pure optimistic helper for React integrations. A React wrapper can call this from `useOptimistic`;\n * keeping the reducer pure lets non-React tests exercise the exact overlay behavior.\n */\nexport function useOptimisticCart(cart: Cart, action: CartDispatchAction | null): Cart {\n return action ? applyOptimisticCartAction(cart, action) : cart\n}\n","import { MARKET_PATH_PREFIX_HEADER } from '@kotao/storefront-contracts'\nimport type { CartHandler } from '../cart/createCartHandler'\nimport { buildLocalizationCookie, readLocalizationCookie } from './cookie'\nimport { localizePath } from './routing'\n\n/** Same-origin path only: must start with a single '/', not '//' or '/\\'. */\nfunction safeReturnTo(raw: string | null): { path: string; safe: boolean } {\n if (raw === null || raw === '') return { path: '/', safe: true }\n return /^\\/(?![/\\\\])/.test(raw) ? { path: raw, safe: true } : { path: '/', safe: false }\n}\n\nexport async function handleLocalizationPost(\n request: Request,\n context?: { readonly cart?: Pick<CartHandler, 'get' | 'updateBuyerIdentity'> },\n): Promise<Response> {\n const form = await request.formData()\n // Shopify localization forms may include the current value as a hidden input before the clicked\n // submit button with the same name. FormData preserves DOM order, so the successful submitter is\n // the final value and must win over the stale hidden default.\n const previous = readLocalizationCookie(request.headers.get('cookie'))\n const country = form.has('country_code')\n ? (form.getAll('country_code').at(-1) ?? '').toString().trim().toUpperCase() || null\n : previous.country\n const locale = form.has('locale_code')\n ? (form.getAll('locale_code').at(-1) ?? '').toString().trim() || null\n : previous.locale\n if ((form.has('country_code') && country === null) || (country !== null && !/^[A-Z]{2}$/.test(country))) {\n return new Response('Invalid country', { status: 400 })\n }\n const primaryLocale = (form.get('primary_locale') ?? '').toString().trim() || null\n const returnTo = safeReturnTo((form.get('return_to') ?? '').toString())\n const location =\n returnTo.safe && primaryLocale !== null\n ? localizePath(returnTo.path, locale, {\n primaryLocale,\n marketPathPrefix: request.headers.get(MARKET_PATH_PREFIX_HEADER),\n })\n : returnTo.path\n const headers = new Headers({ location })\n // Do not create a cart just to change language/country. When one exists, update it before\n // committing the browsing preference so the following checkout uses the same destination.\n if (country !== null && form.has('country_code') && context?.cart !== undefined) {\n const cart = await context.cart.get()\n if (cart !== null && cart.buyerIdentity.countryCode !== country) {\n const result = await context.cart.updateBuyerIdentity({ countryCode: country })\n if (result.cart === null || result.userErrors.length > 0) {\n return new Response('Unable to update cart country', { status: 409 })\n }\n const cartCookie = result.headers.get('set-cookie')\n if (cartCookie !== null) headers.append('set-cookie', cartCookie)\n }\n }\n headers.append('set-cookie', buildLocalizationCookie({ country, locale }))\n return new Response(null, {\n status: 302,\n headers,\n })\n}\n","/**\n * Coarse visitor geo attached to pixel events — structurally the SDK's `context.geo` (a `Geo` value is\n * assignable here). Declared locally so the analytics surface (and its DOM/React preset) need not pull\n * in the geo crypto module.\n */\nexport interface AnalyticsGeo {\n readonly country: string | null\n readonly city: string | null\n readonly colo: string | null\n readonly botScore: number | null\n readonly clientIp: string | null\n}\n\n/** The standard storefront analytics events (Hydrogen-shaped names). */\nexport const ANALYTICS_EVENTS = {\n pageViewed: 'page_viewed',\n productViewed: 'product_viewed',\n collectionViewed: 'collection_viewed',\n cartViewed: 'cart_viewed',\n searchViewed: 'search_viewed',\n productAddedToCart: 'product_added_to_cart',\n} as const\n\nexport type AnalyticsEventName = (typeof ANALYTICS_EVENTS)[keyof typeof ANALYTICS_EVENTS]\n\nexport type AnalyticsDeviceClass = 'mobile' | 'tablet' | 'desktop'\n\n/** Ambient context the provider attaches to every event before it reaches the pixel. */\nexport interface AnalyticsContext {\n readonly shopId?: string\n readonly url?: string\n readonly geo?: AnalyticsGeo\n readonly referrer?: string\n readonly utmSource?: string\n readonly utmMedium?: string\n readonly utmCampaign?: string\n readonly deviceClass?: AnalyticsDeviceClass\n}\n\nexport interface PageViewedPayload {\n readonly title?: string\n}\nexport interface ProductViewedPayload {\n readonly productId: string\n /** Stable offer id; Google Merchant Center and Google ecommerce events use this as item_id. */\n readonly variantId?: string\n readonly handle?: string\n readonly title?: string\n readonly variantTitle?: string\n readonly vendor?: string\n readonly sku?: string\n /** Major-unit price, e.g. 24.95. */\n readonly price?: number\n readonly currency?: string\n readonly quantity?: number\n}\nexport interface CollectionViewedPayload {\n readonly collectionId: string\n readonly handle?: string\n}\nexport interface CartViewedPayload {\n readonly cartId?: string\n}\nexport interface SearchViewedPayload {\n readonly query: string\n readonly resultCount?: number\n}\nexport interface ProductAddedToCartPayload {\n readonly productId: string\n readonly variantId: string\n readonly quantity: number\n readonly title?: string\n readonly variantTitle?: string\n readonly vendor?: string\n readonly sku?: string\n /** Major-unit price, e.g. 24.95. */\n readonly price?: number\n readonly currency?: string\n}\n\n/** Event name → payload (the typed pub/sub surface). */\nexport interface AnalyticsEventMap {\n page_viewed: PageViewedPayload\n product_viewed: ProductViewedPayload\n collection_viewed: CollectionViewedPayload\n cart_viewed: CartViewedPayload\n search_viewed: SearchViewedPayload\n product_added_to_cart: ProductAddedToCartPayload\n}\n\n/** A pixel-bound event: the name, its payload, the ambient context, a timestamp, and consent state. */\nexport interface PixelEvent<E extends AnalyticsEventName = AnalyticsEventName> {\n readonly event: E\n readonly payload: AnalyticsEventMap[E]\n readonly context: AnalyticsContext\n readonly timestamp: string\n /** Whether the analytics-consent bucket was granted when this event was recorded. */\n readonly consent: boolean\n}\n","export interface ShopAnalytics {\n readonly acceptedLanguage?: string\n readonly currency?: string\n readonly shopId?: string\n readonly storefrontId?: string\n}\n\nexport interface GetShopAnalyticsOptions {\n readonly publicStorefrontId?: string\n readonly storefront?: {\n readonly i18n?: {\n readonly country?: string | null\n readonly currency?: string | null\n readonly language?: string | null\n readonly pathPrefix?: string | null\n } | null\n } | null\n}\n\nexport function getShopAnalytics(options: GetShopAnalyticsOptions): ShopAnalytics {\n const language = options.storefront?.i18n?.language ?? null\n const country = options.storefront?.i18n?.country ?? null\n const currency = options.storefront?.i18n?.currency ?? null\n const acceptedLanguage =\n language != null && country != null ? `${language}-${country}` : (language ?? country)\n\n return {\n ...(acceptedLanguage != null ? { acceptedLanguage } : {}),\n ...(currency != null ? { currency } : {}),\n ...(options.publicStorefrontId != null ? { shopId: options.publicStorefrontId } : {}),\n ...(options.publicStorefrontId != null ? { storefrontId: options.publicStorefrontId } : {}),\n }\n}\n","import { CONSENT_BUCKETS, type ConsentBucket, type ConsentState } from './consent'\n\n/**\n * Encode/decode consent into the `cart.checkoutUrl` handoff (query params), mirroring Shopify's\n * server-set-consent direction (design §Checkout handoff). The handoff target is the Gateway-owned\n * same-origin `/checkout/*` path — `appendConsentToCheckoutUrl` preserves a relative URL as relative\n * so it never points at a separate subdomain.\n */\nconst PARAM_PREFIX = 'consent_'\nconst RELATIVE_BASE = 'https://kotao.invalid'\n\nexport function encodeConsent(state: ConsentState): URLSearchParams {\n const params = new URLSearchParams()\n for (const bucket of CONSENT_BUCKETS)\n params.set(`${PARAM_PREFIX}${bucket}`, state[bucket] ? '1' : '0')\n return params\n}\n\nexport function decodeConsent(params: URLSearchParams): ConsentState {\n const read = (bucket: ConsentBucket): boolean => params.get(`${PARAM_PREFIX}${bucket}`) === '1'\n return {\n analytics: read('analytics'),\n marketing: read('marketing'),\n preferences: read('preferences'),\n }\n}\n\nexport function appendConsentToCheckoutUrl(checkoutUrl: string, state: ConsentState): string {\n // The checkout handoff is the same-origin `/checkout/*` path (cart.checkoutUrl is relative). Reject\n // absolute or protocol-relative URLs so consent params never ride to another origin.\n if (!/^\\/(?!\\/)/.test(checkoutUrl)) {\n throw new Error(`checkoutUrl must be a same-origin path starting with '/'; got: ${checkoutUrl}`)\n }\n const url = new URL(checkoutUrl, RELATIVE_BASE)\n for (const [key, value] of encodeConsent(state)) url.searchParams.set(key, value)\n return `${url.pathname}${url.search}${url.hash}`\n}\n","import {\n CHECKOUT_DESIGN_TOKEN_INPUTS,\n extractCheckoutDesignTokens,\n type CheckoutDesignTokens,\n} from '../checkout/design-tokens'\nimport type { ResolvedSettings } from '../settings/types'\n\nconst CHECKOUT_TOKEN_DEFAULTS: Readonly<Record<string, string>> = Object.fromEntries(\n CHECKOUT_DESIGN_TOKEN_INPUTS.flatMap((input) =>\n 'defaultValue' in input && typeof input.defaultValue === 'string' && input.defaultValue !== ''\n ? [[input.name, input.defaultValue]]\n : [],\n ),\n)\n\n/** Resolve the token contract shared by trusted checkout and customer-account surfaces. */\nexport function resolveHostedBranding(global: ResolvedSettings): CheckoutDesignTokens {\n return extractCheckoutDesignTokens({ global: { ...CHECKOUT_TOKEN_DEFAULTS, ...global } })\n}\n\n/** Escape merchant-controlled text for an HTML text node or double-quoted attribute. */\nexport function escapeHostedHtml(value: string): string {\n return value\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n .replace(/'/g, '&#39;')\n}\n\n/**\n * Strip characters that can terminate an inline CSS declaration, block, quote, or style element.\n * Trusted renderers must apply this at the CSS-value sink; the resolved token values themselves\n * remain byte-for-byte compatible with checkout's existing contract.\n */\nexport function sanitizeHostedCssValue(value: string): string {\n return value\n .replace(/[<>\"'`;{}\\\\]/g, '')\n .replace(/[\\r\\n\\t]+/g, ' ')\n .trim()\n}\n","import { readLocalizationCookie } from '../localization/cookie'\n\nexport interface HostedLocaleInput {\n readonly configuredLocales: readonly string[]\n readonly localizationCookie: string | null\n readonly customerLocale: string | null\n readonly primaryLocale: string\n}\n\n/**\n * Resolve display language within the verified shop's configured locale allowlist. Payment\n * jurisdiction and legal-copy decisions deliberately stay outside this display-only resolver.\n */\nexport function resolveHostedLocale(input: HostedLocaleInput): string {\n const configured = input.configuredLocales.map((locale) => locale.trim()).filter(Boolean)\n if (configured.length === 0) throw new Error('hosted surfaces require a configured locale')\n\n const configuredByKey = new Map(configured.map((locale) => [localeKey(locale), locale] as const))\n const cookieLocale = safelyReadCookieLocale(input.localizationCookie)\n\n for (const candidate of [cookieLocale, input.customerLocale, input.primaryLocale]) {\n if (candidate === null || candidate.trim() === '') continue\n const match = configuredByKey.get(localeKey(candidate))\n if (match !== undefined) return match\n }\n\n return configured[0]!\n}\n\nfunction localeKey(locale: string): string {\n return locale.trim().replace(/_/g, '-').toLowerCase()\n}\n\nfunction safelyReadCookieLocale(cookieHeader: string | null): string | null {\n if (cookieHeader === null) return null\n if (!cookieHeader.includes('=')) return cookieHeader.trim() || null\n try {\n return readLocalizationCookie(cookieHeader).locale\n } catch {\n return null\n }\n}\n"]}
@@ -74,4 +74,4 @@ declare function getPaginationInfo<T>(connection: Connection<T>, currentUrl: URL
74
74
  namespace?: string;
75
75
  }): PaginationInfo<T>;
76
76
 
77
- export { type Connection as C, type FlattenableConnection as F, type PaginationInfo as P, type ConnectionEdge as a, type PageInfo as b, type PaginationOptions as c, type PaginationVariables as d, getPaginationVariables as e, flattenConnection as f, getPaginationInfo as g };
77
+ export { type Connection as C, type FlattenableConnection as F, type PageInfo as P, type ConnectionEdge as a, type PaginationInfo as b, type PaginationOptions as c, type PaginationVariables as d, getPaginationVariables as e, flattenConnection as f, getPaginationInfo as g };
package/dist/product.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { F as FlattenableConnection } from './pagination-DCrQk02Q.js';
1
+ import { F as FlattenableConnection } from './pagination-CPgH3fAa.js';
2
2
  import { ProductOptionValueSwatch, Image } from './storefront-api-types.js';
3
3
 
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { K as KotaoContext, a as KotaoEnv, S as StorefrontExecutionContext } from './routing-D2GFXAa0.js';
2
- export { b as KotaoSession, s as stripLocalePrefixFromRequest } from './routing-D2GFXAa0.js';
1
+ import { K as KotaoContext, a as KotaoEnv, S as StorefrontExecutionContext } from './routing-hrvYWYEV.js';
2
+ export { b as KotaoSession, s as stripLocalePrefixFromRequest } from './routing-hrvYWYEV.js';
3
3
  import * as react_router from 'react-router';
4
4
  import { EntryContext, RouterContextProvider } from 'react-router';
5
5
  import { H as HydrogenSession } from './types-C4yXcret.js';
@@ -7,8 +7,8 @@ import { b as StorefrontCacheInput } from './client-D51WdvYR.js';
7
7
  import './fetch-Bq_cc8_G.js';
8
8
  import '@kotao/storefront-contracts/theme';
9
9
  import './createCartHandler-DJEZW4o2.js';
10
- import './client-D-M3Y1ul.js';
11
- import './types-CSNXbGFW.js';
10
+ import './client-Bt8EEr-K.js';
11
+ import './types-BTUTZXxJ.js';
12
12
  import './http-types-CGh8WGHB.js';
13
13
 
14
14
  /** Static assets and SSR must use the same content-addressed tree, including dynamic Liquid URLs. */
@@ -1,5 +1,5 @@
1
- import { createKotaoContext } from './chunk-XZVCUAZU.js';
2
- export { stripLocalePrefixFromRequest } from './chunk-XZVCUAZU.js';
1
+ import { createKotaoContext } from './chunk-4OELOXCN.js';
2
+ export { stripLocalePrefixFromRequest } from './chunk-4OELOXCN.js';
3
3
  import './chunk-GR4QJ7EC.js';
4
4
  import './chunk-2MRB6SMP.js';
5
5
  import './chunk-CKGI3Y7L.js';