@viu/emporix-sdk-react 2.11.0 → 2.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @viu/emporix-sdk-react
2
2
 
3
+ ## 2.12.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [#116](https://github.com/viuteam/emporix-sdk/pull/116) [`5411502`](https://github.com/viuteam/emporix-sdk/commit/5411502fdde0737ad457812e28a86c505f938282) Thanks [@amnael1](https://github.com/amnael1)! - Add a runtime language switch. `client.setStorefrontContext({ language })` now sets an `Accept-Language` header on every read. React's `useSiteContext()` exposes `language` + `setLanguage(lang)` (modeled on `setCurrency`), persists the choice via `EmporixStorage` (`emporix.language`), mirrors it into the server session context, and keys localized reads (products, categories, segments, cart, shopping lists, orders) by language so the cache never serves stale-language text. A new `initialLanguage` provider prop seeds the active language.
8
+
3
9
  ## 2.11.0
4
10
 
5
11
  ### Minor Changes
@@ -1,4 +1,4 @@
1
- import { createMemoryStorage } from './chunk-FBQY2N7S.js';
1
+ import { createMemoryStorage } from './chunk-VMDBYVWG.js';
2
2
  import { createContext, useContext, useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
3
  import { useQueryClient, QueryClient, QueryClientProvider } from '@tanstack/react-query';
4
4
  import { auth } from '@viu/emporix-sdk';
@@ -166,6 +166,7 @@ function EmporixProvider({
166
166
  storage,
167
167
  initialCustomerToken,
168
168
  initialSiteCode,
169
+ initialLanguage,
169
170
  initialActiveLegalEntityId,
170
171
  onTelemetry,
171
172
  autoRefreshCustomerToken,
@@ -319,6 +320,7 @@ function EmporixProvider({
319
320
  client,
320
321
  storage: value.storage,
321
322
  ...initialSiteCode !== void 0 ? { initialSiteCode } : {},
323
+ ...initialLanguage !== void 0 ? { initialLanguage } : {},
322
324
  children: /* @__PURE__ */ jsx(
323
325
  CompanyContextProvider,
324
326
  {
@@ -335,6 +337,7 @@ function SiteContextProvider({
335
337
  client,
336
338
  storage,
337
339
  initialSiteCode,
340
+ initialLanguage,
338
341
  children
339
342
  }) {
340
343
  const qc = useQueryClient();
@@ -347,11 +350,17 @@ function SiteContextProvider({
347
350
  const [currency, setCurrencyState] = useState(
348
351
  () => client.config?.credentials?.storefront?.context?.currency ?? null
349
352
  );
353
+ const [language, setLanguageState] = useState(() => {
354
+ if (initialLanguage !== void 0) return initialLanguage;
355
+ const fromStorage = storage.getLanguage();
356
+ if (fromStorage !== null) return fromStorage;
357
+ return client.config?.credentials?.storefront?.context?.language ?? null;
358
+ });
350
359
  const [targetLocation, setTargetLocation] = useState(null);
351
360
  const [isSwitching, setIsSwitching] = useState(false);
352
361
  const [switchError, setSwitchError] = useState(null);
353
362
  useEffect(() => {
354
- if (!siteCode || currency !== null && targetLocation !== null) return;
363
+ if (!siteCode || currency !== null && targetLocation !== null && language !== null) return;
355
364
  let cancelled = false;
356
365
  const token = storage.getCustomerToken();
357
366
  const authCtx = token ? auth.customer(token) : auth.anonymous();
@@ -368,12 +377,19 @@ function SiteContextProvider({
368
377
  if (cancelled) return;
369
378
  if (currency === null) setCurrencyState(site.currency);
370
379
  setTargetLocation(site.homeBase?.address?.country ?? null);
380
+ if (language === null && site.defaultLanguage) {
381
+ setLanguageState(site.defaultLanguage);
382
+ client.setStorefrontContext({ language: site.defaultLanguage });
383
+ }
371
384
  }).catch(() => {
372
385
  });
373
386
  return () => {
374
387
  cancelled = true;
375
388
  };
376
389
  }, [siteCode]);
390
+ useEffect(() => {
391
+ if (language) client.setStorefrontContext({ language });
392
+ }, []);
377
393
  const setSite = useCallback(
378
394
  async (code) => {
379
395
  storage.setSiteCode(code);
@@ -404,6 +420,10 @@ function SiteContextProvider({
404
420
  const nextTarget = site.homeBase?.address?.country ?? null;
405
421
  setCurrencyState(nextCurrency);
406
422
  setTargetLocation(nextTarget);
423
+ if (site.languages && !site.languages.includes(language ?? "") && site.defaultLanguage) {
424
+ setLanguageState(site.defaultLanguage);
425
+ client.setStorefrontContext({ language: site.defaultLanguage });
426
+ }
407
427
  await client.sessionContext.patch(
408
428
  {
409
429
  siteCode: code,
@@ -418,7 +438,7 @@ function SiteContextProvider({
418
438
  setIsSwitching(false);
419
439
  }
420
440
  },
421
- [client, storage, qc]
441
+ [client, storage, qc, language]
422
442
  );
423
443
  const setCurrency = useCallback(
424
444
  async (next) => {
@@ -443,17 +463,42 @@ function SiteContextProvider({
443
463
  },
444
464
  [client, storage, qc, siteCode]
445
465
  );
466
+ const setLanguage = useCallback(
467
+ async (next) => {
468
+ storage.setLanguage(next);
469
+ setLanguageState(next);
470
+ setSwitchError(null);
471
+ client.setStorefrontContext({ language: next });
472
+ void qc.invalidateQueries({ queryKey: ["emporix"] });
473
+ setIsSwitching(true);
474
+ try {
475
+ const token = storage.getCustomerToken();
476
+ const authCtx = token ? auth.customer(token) : auth.anonymous();
477
+ await client.sessionContext.patch(
478
+ { language: next, ...siteCode ? { siteCode } : {} },
479
+ authCtx
480
+ );
481
+ } catch (e) {
482
+ setSwitchError(e instanceof Error ? e : new Error(String(e)));
483
+ } finally {
484
+ setIsSwitching(false);
485
+ }
486
+ },
487
+ [client, storage, qc, siteCode]
488
+ );
446
489
  const value = useMemo(
447
490
  () => ({
448
491
  siteCode,
449
492
  currency,
450
493
  targetLocation,
494
+ language,
451
495
  setSite,
452
496
  setCurrency,
497
+ setLanguage,
453
498
  isSwitching,
454
499
  switchError
455
500
  }),
456
- [siteCode, currency, targetLocation, setSite, setCurrency, isSwitching, switchError]
501
+ [siteCode, currency, targetLocation, language, setSite, setCurrency, setLanguage, isSwitching, switchError]
457
502
  );
458
503
  return /* @__PURE__ */ jsx(EmporixSiteContext.Provider, { value, children });
459
504
  }
@@ -464,5 +509,5 @@ function useEmporix() {
464
509
  }
465
510
 
466
511
  export { CompanyContextProvider, EmporixCompanyContext, EmporixProvider, EmporixSiteContext, useActiveCompany, useEmporix, useEmporixTelemetry };
467
- //# sourceMappingURL=chunk-SMJ5IQZJ.js.map
468
- //# sourceMappingURL=chunk-SMJ5IQZJ.js.map
512
+ //# sourceMappingURL=chunk-4YDWCA7A.js.map
513
+ //# sourceMappingURL=chunk-4YDWCA7A.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/telemetry.ts","../src/company-context.tsx","../src/provider.tsx"],"names":["createContext","useContext","useMemo","useState","useCallback","useEffect","storage","jsx","useQueryClient","auth"],"mappings":"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","file":"chunk-4YDWCA7A.js","sourcesContent":["import { createContext, useContext } from \"react\";\n\n/**\n * All telemetry events emitted through the EmporixProvider's `onTelemetry`\n * callback. Discriminated by `type` — exhaustive switch is type-safe.\n *\n * Consumers can emit their own `{ type: \"custom\" }` events via\n * {@link useEmporixTelemetry}. Namespace `name` with an app-specific\n * prefix (e.g. `\"app.checkout-cta-click\"`) to avoid collisions with\n * future SDK event types.\n */\nexport type EmporixTelemetryEvent =\n // Cache lifecycle (React-Query QueryCache)\n | { type: \"cache.hit\"; queryKey: readonly unknown[]; tenant: string }\n | {\n type: \"cache.miss\";\n queryKey: readonly unknown[];\n tenant: string;\n durationMs: number;\n }\n | {\n type: \"query.refetch\";\n queryKey: readonly unknown[];\n tenant: string;\n reason: \"invalidate\" | \"focus\" | \"stale\";\n }\n | {\n type: \"query.error\";\n queryKey: readonly unknown[];\n tenant: string;\n error: unknown;\n }\n // Mutation lifecycle\n | {\n type: \"mutation.success\";\n mutationKey?: readonly unknown[];\n tenant: string;\n durationMs: number;\n }\n | {\n type: \"mutation.error\";\n mutationKey?: readonly unknown[];\n tenant: string;\n error: unknown;\n durationMs: number;\n }\n // Auth refresh (SDK-side)\n | {\n type: \"auth.refresh\";\n kind: \"anonymous\" | \"customer\";\n tenant: string;\n success: boolean;\n }\n // Storage writes\n | {\n type: \"storage.write\";\n key: \"customerToken\" | \"cartId\" | \"siteCode\" | \"language\" | \"anonymousSession\" | \"activeLegalEntityId\" | \"refreshToken\";\n }\n // Active-company switch (B2B)\n | {\n type: \"company:switched\";\n from: string | null;\n to: string | null;\n durationMs: number;\n }\n // Consumer-emitted\n | { type: \"custom\"; name: string; props?: Record<string, unknown> };\n\n/** Internal: the React context carrying the emit function down the tree. */\nexport const EmporixTelemetryContext = createContext<{\n emit: (event: EmporixTelemetryEvent) => void;\n} | null>(null);\n\n/**\n * Hook to emit custom telemetry events through the same channel as SDK\n * events. Throws when used outside an {@link EmporixProvider}.\n *\n * When the provider has no `onTelemetry` callback configured, `emit` is a\n * no-op — calling it is safe and incurs no overhead.\n */\nexport function useEmporixTelemetry(): {\n emit: (event: EmporixTelemetryEvent) => void;\n} {\n const ctx = useContext(EmporixTelemetryContext);\n if (!ctx) {\n throw new Error(\"useEmporixTelemetry must be used within an EmporixProvider\");\n }\n return ctx;\n}\n","import {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useRef,\n useState,\n type ReactNode,\n} from \"react\";\nimport { useQueryClient } from \"@tanstack/react-query\";\nimport { auth, type EmporixClient, type LegalEntity } from \"@viu/emporix-sdk\";\nimport type { EmporixStorage } from \"./storage\";\nimport { useEmporixTelemetry } from \"./telemetry\";\n\nexport type CompanyMode = \"b2c\" | \"b2b\" | \"unresolved\";\n\nexport interface CompanyContextValue {\n /** Active legal entity. `null` = B2C mode. */\n activeCompany: LegalEntity | null;\n /** All legal entities the customer is assigned to. */\n myCompanies: LegalEntity[];\n /**\n * `b2b` = a company is active; `b2c` = none active (and ≤1 available);\n * `unresolved` = multiple companies available, none picked yet — the\n * storefront must render a picker.\n */\n mode: CompanyMode;\n status: \"idle\" | \"loading\" | \"switching\" | \"error\";\n error: unknown;\n /**\n * Switch the active company. Eagerly calls\n * `client.customers.refresh({ legalEntityId })` so the customer token is\n * rescoped server-side, drops the cart id, then invalidates company-scoped\n * queries. Falls back to a local-state-only update when no refresh token\n * is in storage (e.g. fresh page load with memory storage).\n */\n setActiveCompany: (legalEntityId: string | null) => Promise<void>;\n refetchMyCompanies: () => Promise<void>;\n}\n\nconst NULL_CTX: CompanyContextValue = {\n activeCompany: null,\n myCompanies: [],\n mode: \"b2c\",\n status: \"idle\",\n error: null,\n setActiveCompany: async () => {\n throw new Error(\"CompanyContextProvider not mounted\");\n },\n refetchMyCompanies: async () => {},\n};\n\nexport const EmporixCompanyContext = createContext<CompanyContextValue>(NULL_CTX);\n\n/** Returns the active-company context. Safe outside the provider — returns idle B2C defaults. */\nexport function useActiveCompany(): CompanyContextValue {\n return useContext(EmporixCompanyContext);\n}\n\nexport interface CompanyContextProviderProps {\n client: EmporixClient;\n storage: EmporixStorage;\n initialActiveLegalEntityId?: string | null;\n children: ReactNode;\n}\n\nexport function CompanyContextProvider({\n client,\n storage,\n initialActiveLegalEntityId,\n children,\n}: CompanyContextProviderProps): React.JSX.Element {\n const qc = useQueryClient();\n const { emit } = useEmporixTelemetry();\n const [myCompanies, setMyCompanies] = useState<LegalEntity[]>([]);\n const [activeCompany, setActive] = useState<LegalEntity | null>(null);\n const [status, setStatus] = useState<CompanyContextValue[\"status\"]>(\"idle\");\n const [error, setError] = useState<unknown>(null);\n // Ref so switchTo can capture the latest `activeCompany` for telemetry `from`.\n const activeRef = useRef<LegalEntity | null>(null);\n activeRef.current = activeCompany;\n\n /** Internal: eager refresh + storage write + state update. */\n const switchTo = useCallback(\n async (target: LegalEntity | null) => {\n const start = Date.now();\n const from = activeRef.current?.id ?? null;\n const refreshToken = storage.getRefreshToken();\n const token = storage.getCustomerToken();\n if (!refreshToken || !token) {\n // Local-state-only fallback — no rescope possible.\n setActive(target);\n storage.setActiveLegalEntityId(target?.id ?? null);\n } else {\n const next = await client.customers.refresh({\n refreshToken,\n ...(target ? { legalEntityId: target.id } : {}),\n });\n storage.setCustomerToken(next.customerToken);\n if (next.refreshToken) storage.setRefreshToken(next.refreshToken);\n storage.setCartId(null);\n storage.setActiveLegalEntityId(target?.id ?? null);\n setActive(target);\n qc.invalidateQueries({\n predicate: (q) =>\n Array.isArray(q.queryKey) &&\n q.queryKey.some(\n (k) =>\n k === \"cart\" ||\n k === \"companies\" ||\n k === \"customer\" ||\n k === from ||\n (target !== null && k === target.id),\n ),\n });\n }\n emit({\n type: \"company:switched\",\n from,\n to: target?.id ?? null,\n durationMs: Date.now() - start,\n });\n },\n [client, storage, qc, emit],\n );\n\n const load = useCallback(async () => {\n const token = storage.getCustomerToken();\n if (!token) {\n setMyCompanies([]);\n setActive(null);\n setStatus(\"idle\");\n return;\n }\n setStatus(\"loading\");\n try {\n const companies = await client.companies.listMine(auth.customer(token));\n setMyCompanies(companies);\n const persisted = initialActiveLegalEntityId ?? storage.getActiveLegalEntityId();\n const matched = persisted ? companies.find((c) => c.id === persisted) ?? null : null;\n if (matched) {\n setActive(matched);\n if (storage.getActiveLegalEntityId() !== matched.id) {\n storage.setActiveLegalEntityId(matched.id ?? null);\n }\n } else if (companies.length === 1) {\n await switchTo(companies[0] ?? null);\n } else {\n setActive(null);\n if (persisted && !matched) storage.setActiveLegalEntityId(null);\n }\n setStatus(\"idle\");\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n }\n }, [client, storage, initialActiveLegalEntityId, switchTo]);\n\n useEffect(() => {\n void load();\n }, [load]);\n\n // Re-run bootstrap only on token-presence transitions (login/logout). A\n // mid-session token swap (e.g. switch-driven refresh) keeps prev/next both\n // truthy and is ignored — otherwise the auto-pick branch would clobber an\n // explicit B2C choice as soon as the new token is written.\n useEffect(() => {\n let prev = storage.getCustomerToken();\n return storage.subscribe?.((next) => {\n const becameAuth = !prev && next;\n const becameUnauth = prev && !next;\n prev = next;\n if (becameAuth || becameUnauth) void load();\n });\n }, [storage, load]);\n\n const setActiveCompany = useCallback(\n async (legalEntityId: string | null) => {\n setStatus(\"switching\");\n try {\n if (legalEntityId === null) {\n await switchTo(null);\n } else {\n const target = myCompanies.find((c) => c.id === legalEntityId) ?? null;\n if (!target) throw new Error(`setActiveCompany: unknown legalEntityId ${legalEntityId}`);\n await switchTo(target);\n }\n setStatus(\"idle\");\n } catch (e) {\n setError(e);\n setStatus(\"error\");\n throw e;\n }\n },\n [myCompanies, switchTo],\n );\n\n const value = useMemo<CompanyContextValue>(() => {\n const mode: CompanyMode = activeCompany\n ? \"b2b\"\n : myCompanies.length > 1\n ? \"unresolved\"\n : \"b2c\";\n return {\n activeCompany,\n myCompanies,\n mode,\n status,\n error,\n setActiveCompany,\n refetchMyCompanies: load,\n };\n }, [activeCompany, myCompanies, status, error, setActiveCompany, load]);\n\n return (\n <EmporixCompanyContext.Provider value={value}>{children}</EmporixCompanyContext.Provider>\n );\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState, type ReactNode } from \"react\";\nimport { QueryClient, QueryClientProvider, useQueryClient } from \"@tanstack/react-query\";\nimport { auth, type EmporixClient } from \"@viu/emporix-sdk\";\nimport type { EmporixStorage } from \"./storage/index\";\nimport { createMemoryStorage } from \"./storage/memory\";\nimport { EmporixTelemetryContext, type EmporixTelemetryEvent } from \"./telemetry\";\nimport { CompanyContextProvider } from \"./company-context\";\n\ninterface EmporixContextValue {\n client: EmporixClient;\n storage: EmporixStorage;\n}\n\nexport interface SiteContextValue {\n siteCode: string | null;\n /** MS-4 populates this from the active site's DTO. */\n currency: string | null;\n /** MS-4 populates this from the active site's DTO. */\n targetLocation: string | null;\n /** Active language for localized reads (Accept-Language). `null` = site/tenant default. */\n language: string | null;\n /**\n * Asynchronous site switch. Updates local state + storage immediately\n * (optimistic), then PATCHes `/session-context/{tenant}/me/context` so\n * the server sees the same site on the next request. When no session\n * context exists yet (first visit, before any cart), the PATCH is\n * skipped — local state still flips.\n *\n * `isSwitching` is `true` while the PATCH is in flight. `switchError`\n * surfaces a PATCH failure; the optimistic state is NOT rolled back\n * (the cache was already invalidated, the UI already moved on).\n */\n setSite: (code: string | null) => Promise<void>;\n /**\n * Switch the active currency at runtime. Re-binds the anonymous price context\n * (so guest pricing changes even before a cart exists), clears the\n * currency-bound guest cart, and PATCHes an existing server session context.\n * The chosen currency must be in the active site's `availableCurrencies`.\n */\n setCurrency: (currency: string) => Promise<void>;\n /**\n * Switch the active language at runtime. Sets the `Accept-Language` request\n * header (via `setStorefrontContext`), invalidates the React-Query cache so\n * localized reads refetch, and PATCHes an existing server session context.\n * Does NOT clear the cart (language does not affect pricing).\n */\n setLanguage: (language: string) => Promise<void>;\n isSwitching: boolean;\n switchError: Error | null;\n}\n\nconst EmporixContext = createContext<EmporixContextValue | null>(null);\nexport const EmporixSiteContext = createContext<SiteContextValue | null>(null);\n\n/**\n * Balanced React-Query defaults applied to the provider's fallback QueryClient\n * (only when no `queryClient` prop is passed). Keeps the Emporix API-quota in\n * check by suppressing window-focus refetches and capping retries.\n */\nconst DEFAULT_QUERY_OPTIONS = {\n staleTime: 30_000,\n refetchOnWindowFocus: false,\n retry: 1,\n} as const;\n\n/** Props for {@link EmporixProvider}. */\nexport interface EmporixProviderProps {\n client: EmporixClient;\n queryClient?: QueryClient;\n storage?: EmporixStorage;\n initialCustomerToken?: string;\n /**\n * Initial site code. Resolution order: this prop → `storage.getSiteCode()` →\n * `client.config.credentials.storefront.context.siteCode` → `null`.\n */\n initialSiteCode?: string;\n /**\n * Initial active language. Resolution order: this prop → `storage.getLanguage()`\n * → `client.config.credentials.storefront.context.language` → `null` (then\n * seeded from the active site's `defaultLanguage` on mount).\n */\n initialLanguage?: string;\n /**\n * Initial active legal-entity id (B2B). When set, the CompanyContext\n * provider tries to match it against `companies.listMine()` once the\n * customer is loaded; mismatches are dropped silently.\n */\n initialActiveLegalEntityId?: string | null;\n /**\n * Opt-in telemetry callback. Receives a typed event stream covering cache\n * hit/miss, refetches, errors, mutations, auth refreshes, storage writes,\n * and consumer-emitted custom events. Wire this to Datadog/Sentry/custom\n * analytics. The handler is wrapped in try/catch — a throwing handler\n * never breaks the provider.\n */\n onTelemetry?: (event: EmporixTelemetryEvent) => void;\n /**\n * Opt in to reactive customer-token auto-refresh: on a `customer`-kind 401,\n * the SDK refreshes once (via the stored refresh token + anonymous auth) and\n * retries. Default: false (the customer token stays caller-owned).\n */\n autoRefreshCustomerToken?: boolean;\n /**\n * Called when a customer-token refresh is needed but fails (refresh token\n * expired/revoked) or no refresh token is stored. Use to drive logout /\n * redirect to login.\n */\n onCustomerSessionExpired?: () => void;\n children: ReactNode;\n}\n\n/** Provides the SDK client, token storage, react-query client, and site context to the tree. */\nexport function EmporixProvider({\n client,\n queryClient,\n storage,\n initialCustomerToken,\n initialSiteCode,\n initialLanguage,\n initialActiveLegalEntityId,\n onTelemetry,\n autoRefreshCustomerToken,\n onCustomerSessionExpired,\n children,\n}: EmporixProviderProps): React.JSX.Element {\n const value = useMemo<EmporixContextValue>(() => {\n const s =\n storage ??\n createMemoryStorage(\n initialCustomerToken !== undefined ? { initial: initialCustomerToken } : {},\n );\n if (initialCustomerToken && storage && storage.getCustomerToken() === null) {\n storage.setCustomerToken(initialCustomerToken);\n }\n return { client, storage: s };\n \n }, [client, storage, initialCustomerToken]);\n const qc = useMemo(\n () =>\n queryClient ??\n new QueryClient({ defaultOptions: { queries: DEFAULT_QUERY_OPTIONS } }),\n [queryClient],\n );\n\n // Idempotent one-time wiring: attaches a storage-backed adapter to the SDK's\n // token provider so anonymous sessions survive reloads. Runs once per\n // (client, storage) pair via useState's lazy initializer.\n useState(() => {\n client.tokenProvider.attachAnonymousStore?.({\n read: () => value.storage.getAnonymousSession(),\n write: (s) => value.storage.setAnonymousSession(s),\n });\n return null;\n });\n\n // Telemetry: stable safeEmit + context value. emit is no-op when no\n // onTelemetry callback was provided (no overhead).\n const safeEmit = useCallback(\n (event: EmporixTelemetryEvent) => {\n if (!onTelemetry) return;\n try {\n onTelemetry(event);\n } catch (err) {\n // eslint-disable-next-line no-console\n console.error(\"[emporix] telemetry handler threw:\", err);\n }\n },\n [onTelemetry],\n );\n const telemetryValue = useMemo(() => ({ emit: safeEmit }), [safeEmit]);\n\n // Source subscriptions: cache + mutation cache + token-provider + storage.\n // All only active when onTelemetry is provided.\n useEffect(() => {\n if (!onTelemetry) return;\n const startedAt = new Map<string, number>();\n\n const unsubQuery = qc.getQueryCache().subscribe((event) => {\n const key = event.query.queryKey;\n if (!Array.isArray(key) || key[0] !== \"emporix\") return;\n if (event.type === \"updated\") {\n const action = event.action as { type: string };\n if (action.type === \"fetch\") {\n const isRefetch = event.query.state.dataUpdateCount > 0;\n if (isRefetch) {\n safeEmit({\n type: \"query.refetch\",\n queryKey: key,\n tenant: client.tenant,\n reason: \"invalidate\",\n });\n }\n startedAt.set(event.query.queryHash, Date.now());\n } else if (action.type === \"success\") {\n const start = startedAt.get(event.query.queryHash);\n startedAt.delete(event.query.queryHash);\n safeEmit({\n type: \"cache.miss\",\n queryKey: key,\n tenant: client.tenant,\n durationMs: start ? Date.now() - start : 0,\n });\n } else if (action.type === \"error\") {\n startedAt.delete(event.query.queryHash);\n safeEmit({\n type: \"query.error\",\n queryKey: key,\n tenant: client.tenant,\n error: event.query.state.error,\n });\n }\n } else if (event.type === \"observerResultsUpdated\") {\n const s = event.query.state;\n if (s.status === \"success\" && s.fetchStatus === \"idle\" && s.dataUpdateCount > 0) {\n safeEmit({ type: \"cache.hit\", queryKey: key, tenant: client.tenant });\n }\n }\n });\n\n const unsubMut = qc.getMutationCache().subscribe((event) => {\n if (event.type !== \"updated\") return;\n const m = event.mutation;\n const dur = Date.now() - (m.state.submittedAt ?? Date.now());\n const mk = m.options.mutationKey;\n if (m.state.status === \"success\") {\n safeEmit({\n type: \"mutation.success\",\n ...(mk ? { mutationKey: mk as readonly unknown[] } : {}),\n tenant: client.tenant,\n durationMs: dur,\n });\n } else if (m.state.status === \"error\") {\n safeEmit({\n type: \"mutation.error\",\n ...(mk ? { mutationKey: mk as readonly unknown[] } : {}),\n tenant: client.tenant,\n error: m.state.error,\n durationMs: dur,\n });\n }\n });\n\n const unsubAuth = client.tokenProvider.onRefresh?.((evt) =>\n safeEmit({ type: \"auth.refresh\", ...evt, tenant: client.tenant }),\n );\n\n const unsubStorage = value.storage.subscribeAll?.((key) =>\n safeEmit({ type: \"storage.write\", key }),\n );\n\n return () => {\n unsubQuery();\n unsubMut();\n unsubAuth?.();\n unsubStorage?.();\n };\n }, [qc, onTelemetry, client, value.storage, safeEmit]);\n\n // Opt-in reactive customer-token auto-refresh. Registered on the client so\n // the core HttpClient can refresh-and-retry a customer 401. Single-flight is\n // handled in the core registry. Off unless `autoRefreshCustomerToken`.\n useEffect(() => {\n if (!autoRefreshCustomerToken) return;\n const storage = value.storage;\n client.setCustomerTokenRefresher({\n refresh: async () => {\n const refreshToken = storage.getRefreshToken();\n if (!refreshToken) {\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: false, tenant: client.tenant });\n onCustomerSessionExpired?.();\n return null;\n }\n try {\n const legalEntityId = storage.getActiveLegalEntityId() ?? undefined;\n const s = await client.customers.refresh({\n refreshToken,\n ...(legalEntityId ? { legalEntityId } : {}),\n });\n storage.setCustomerToken(s.customerToken);\n if (s.refreshToken) storage.setRefreshToken(s.refreshToken);\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: true, tenant: client.tenant });\n return s.customerToken;\n } catch {\n safeEmit({ type: \"auth.refresh\", kind: \"customer\", success: false, tenant: client.tenant });\n onCustomerSessionExpired?.();\n return null;\n }\n },\n });\n return () => client.setCustomerTokenRefresher(null);\n }, [autoRefreshCustomerToken, client, value.storage, safeEmit, onCustomerSessionExpired]);\n\n return (\n <EmporixContext.Provider value={value}>\n <EmporixTelemetryContext.Provider value={telemetryValue}>\n <QueryClientProvider client={qc}>\n <SiteContextProvider\n client={client}\n storage={value.storage}\n {...(initialSiteCode !== undefined ? { initialSiteCode } : {})}\n {...(initialLanguage !== undefined ? { initialLanguage } : {})}\n >\n <CompanyContextProvider\n client={client}\n storage={value.storage}\n {...(initialActiveLegalEntityId !== undefined\n ? { initialActiveLegalEntityId }\n : {})}\n >\n {children}\n </CompanyContextProvider>\n </SiteContextProvider>\n </QueryClientProvider>\n </EmporixTelemetryContext.Provider>\n </EmporixContext.Provider>\n );\n}\n\n/**\n * Manages the active-site state. Sits inside `QueryClientProvider` so\n * `setSite` can invalidate the React-Query cache on switch.\n */\nfunction SiteContextProvider({\n client,\n storage,\n initialSiteCode,\n initialLanguage,\n children,\n}: {\n client: EmporixClient;\n storage: EmporixStorage;\n initialSiteCode?: string;\n initialLanguage?: string;\n children: ReactNode;\n}): React.JSX.Element {\n const qc = useQueryClient();\n const [siteCode, setSiteCodeState] = useState<string | null>(() => {\n if (initialSiteCode !== undefined) return initialSiteCode;\n const fromStorage = storage.getSiteCode();\n if (fromStorage !== null) return fromStorage;\n return client.config?.credentials?.storefront?.context?.siteCode ?? null;\n });\n const [currency, setCurrencyState] = useState<string | null>(\n () => client.config?.credentials?.storefront?.context?.currency ?? null,\n );\n const [language, setLanguageState] = useState<string | null>(() => {\n if (initialLanguage !== undefined) return initialLanguage;\n const fromStorage = storage.getLanguage();\n if (fromStorage !== null) return fromStorage;\n return client.config?.credentials?.storefront?.context?.language ?? null;\n });\n const [targetLocation, setTargetLocation] = useState<string | null>(null);\n const [isSwitching, setIsSwitching] = useState(false);\n const [switchError, setSwitchError] = useState<Error | null>(null);\n\n // Mount-time derivation: if a siteCode is already resolved, fetch its DTO\n // once so currency + targetLocation populate without a user-driven switch.\n // A currency seeded from the client config is NOT overridden (the user's /\n // persisted choice wins); only fields still `null` are filled in.\n useEffect(() => {\n if (!siteCode || (currency !== null && targetLocation !== null && language !== null)) return;\n let cancelled = false;\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n qc.fetchQuery({\n queryKey: [\n \"emporix\",\n \"site-by-code\",\n siteCode,\n { tenant: client.tenant, authKind: authCtx.kind },\n ],\n queryFn: () => client.sites.get(siteCode, authCtx),\n staleTime: 5 * 60_000,\n })\n .then((site) => {\n if (cancelled) return;\n if (currency === null) setCurrencyState(site.currency);\n setTargetLocation(site.homeBase?.address?.country ?? null);\n if (language === null && site.defaultLanguage) {\n setLanguageState(site.defaultLanguage);\n client.setStorefrontContext({ language: site.defaultLanguage });\n }\n })\n .catch(() => {\n // Best-effort — silent. setSite-driven derivation surfaces real errors.\n });\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [siteCode]);\n\n // Push the initially-resolved language (prop / storage / config) to the SDK so\n // the very first reads carry `Accept-Language` — React state alone does not\n // reach the client. Mount-only; later changes go through setLanguage / setSite.\n useEffect(() => {\n if (language) client.setStorefrontContext({ language });\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n const setSite = useCallback(\n async (code: string | null) => {\n // 1) Optimistic flip — UI moves immediately.\n storage.setSiteCode(code);\n storage.setCartId(null);\n setSiteCodeState(code);\n setSwitchError(null);\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n\n if (code === null) {\n setCurrencyState(null);\n setTargetLocation(null);\n return;\n }\n\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // 2) Derive currency + targetLocation from the site DTO (cached 5min).\n const site = await qc.fetchQuery({\n queryKey: [\n \"emporix\",\n \"site-by-code\",\n code,\n { tenant: client.tenant, authKind: authCtx.kind },\n ],\n queryFn: () => client.sites.get(code, authCtx),\n staleTime: 5 * 60_000,\n });\n const nextCurrency = site.currency;\n const nextTarget = site.homeBase?.address?.country ?? null;\n setCurrencyState(nextCurrency);\n setTargetLocation(nextTarget);\n // Reset the language if the new site doesn't support the active one.\n if (site.languages && !site.languages.includes(language ?? \"\") && site.defaultLanguage) {\n setLanguageState(site.defaultLanguage);\n client.setStorefrontContext({ language: site.defaultLanguage });\n }\n // 3) Push everything into the session-context PATCH.\n await client.sessionContext.patch(\n {\n siteCode: code,\n ...(nextCurrency ? { currency: nextCurrency } : {}),\n ...(nextTarget ? { targetLocation: nextTarget } : {}),\n },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, language],\n );\n\n const setCurrency = useCallback(\n async (next: string) => {\n // Carts are currency-bound — drop the guest cart so a fresh one is created.\n storage.setCartId(null);\n setCurrencyState(next);\n setSwitchError(null);\n // Re-bind the anonymous price context so guest pricing uses the new\n // currency even before a session/cart exists (sessionContext.patch can't).\n client.setStorefrontContext({ currency: next });\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // Update an existing server session context (no-op / returns false pre-cart).\n await client.sessionContext.patch(\n { currency: next, ...(siteCode ? { siteCode } : {}) },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, siteCode],\n );\n\n const setLanguage = useCallback(\n async (next: string) => {\n storage.setLanguage(next);\n setLanguageState(next);\n setSwitchError(null);\n // Header source — applies to anonymous + pre-session reads too.\n client.setStorefrontContext({ language: next });\n void qc.invalidateQueries({ queryKey: [\"emporix\"] });\n setIsSwitching(true);\n try {\n const token = storage.getCustomerToken();\n const authCtx = token ? auth.customer(token) : auth.anonymous();\n // Update an existing server session context (no-op / returns false pre-cart).\n await client.sessionContext.patch(\n { language: next, ...(siteCode ? { siteCode } : {}) },\n authCtx,\n );\n } catch (e) {\n setSwitchError(e instanceof Error ? e : new Error(String(e)));\n } finally {\n setIsSwitching(false);\n }\n },\n [client, storage, qc, siteCode],\n );\n\n const value = useMemo<SiteContextValue>(\n () => ({\n siteCode,\n currency,\n targetLocation,\n language,\n setSite,\n setCurrency,\n setLanguage,\n isSwitching,\n switchError,\n }),\n [siteCode, currency, targetLocation, language, setSite, setCurrency, setLanguage, isSwitching, switchError],\n );\n\n return <EmporixSiteContext.Provider value={value}>{children}</EmporixSiteContext.Provider>;\n}\n\n/** Returns the SDK client and token storage. Throws outside an {@link EmporixProvider}. */\nexport function useEmporix(): EmporixContextValue {\n const ctx = useContext(EmporixContext);\n if (!ctx) throw new Error(\"useEmporix must be used within an EmporixProvider\");\n return ctx;\n}\n"]}