@weaverse/hydrogen 6.1.3 → 6.2.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.
Files changed (142) hide show
  1. package/dist/index.js +5 -6
  2. package/dist/index.mjs +1 -2
  3. package/dist/internal.js +18 -29
  4. package/dist/internal.mjs +3 -14
  5. package/dist/next-client-boundary.js +1088 -0
  6. package/dist/next-client-boundary.js.map +1 -0
  7. package/dist/next-client-boundary.mjs +1038 -0
  8. package/dist/next-client-boundary.mjs.map +1 -0
  9. package/dist/next-server.js +669 -13
  10. package/dist/next-server.js.map +1 -0
  11. package/dist/next-server.mjs +666 -2
  12. package/dist/next-server.mjs.map +1 -0
  13. package/dist/next.js +29 -43
  14. package/dist/next.mjs +5 -3
  15. package/dist/react-router.js +6 -7
  16. package/dist/react-router.mjs +2 -3
  17. package/dist/seo-B8u2r3rX.mjs +205 -0
  18. package/dist/seo-B8u2r3rX.mjs.map +1 -0
  19. package/dist/seo-D9A9uRQ4.js +264 -0
  20. package/dist/seo-D9A9uRQ4.js.map +1 -0
  21. package/dist/translate-Celryv8j.mjs +26 -0
  22. package/dist/translate-Celryv8j.mjs.map +1 -0
  23. package/dist/translate-Kt1BYL1n.js +37 -0
  24. package/dist/translate-Kt1BYL1n.js.map +1 -0
  25. package/dist/{nested-key-CR3-YMFi.js → translation-store-BmGxBALf.js} +46 -137
  26. package/dist/translation-store-BmGxBALf.js.map +1 -0
  27. package/dist/{nested-key-_k9aW_Wd.mjs → translation-store-JFs-4lvf.mjs} +35 -138
  28. package/dist/translation-store-JFs-4lvf.mjs.map +1 -0
  29. package/dist/types/hooks/translation-context.d.ts +2 -36
  30. package/dist/types/hooks/translation-context.d.ts.map +1 -1
  31. package/dist/types/next/client-boundary.d.ts +25 -0
  32. package/dist/types/next/client-boundary.d.ts.map +1 -0
  33. package/dist/types/next/client.d.ts +16 -0
  34. package/dist/types/next/client.d.ts.map +1 -0
  35. package/dist/types/next/hooks.d.ts +20 -0
  36. package/dist/types/next/hooks.d.ts.map +1 -0
  37. package/dist/types/next/index.d.ts +34 -0
  38. package/dist/types/next/index.d.ts.map +1 -0
  39. package/dist/types/next/item.d.ts +60 -0
  40. package/dist/types/next/item.d.ts.map +1 -0
  41. package/dist/types/next/loader.d.ts +25 -0
  42. package/dist/types/next/loader.d.ts.map +1 -0
  43. package/dist/types/next/main.d.ts +11 -0
  44. package/dist/types/next/main.d.ts.map +1 -0
  45. package/dist/types/next/provider.d.ts +85 -0
  46. package/dist/types/next/provider.d.ts.map +1 -0
  47. package/dist/types/next/registry.d.ts +15 -0
  48. package/dist/types/next/registry.d.ts.map +1 -0
  49. package/dist/types/next/renderer.d.ts +21 -0
  50. package/dist/types/next/renderer.d.ts.map +1 -0
  51. package/dist/types/next/request-info.d.ts +19 -0
  52. package/dist/types/next/request-info.d.ts.map +1 -0
  53. package/dist/types/next/revalidate-item.d.ts +82 -0
  54. package/dist/types/next/revalidate-item.d.ts.map +1 -0
  55. package/dist/types/next/root-provider.d.ts +65 -0
  56. package/dist/types/next/root-provider.d.ts.map +1 -0
  57. package/dist/types/next/runtime.d.ts +113 -0
  58. package/dist/types/next/runtime.d.ts.map +1 -0
  59. package/dist/types/next/seo.d.ts +55 -0
  60. package/dist/types/next/seo.d.ts.map +1 -0
  61. package/dist/types/next/server/configs.d.ts +27 -0
  62. package/dist/types/next/server/configs.d.ts.map +1 -0
  63. package/dist/types/next/server/normalize-page-url.d.ts +19 -0
  64. package/dist/types/next/server/normalize-page-url.d.ts.map +1 -0
  65. package/dist/types/next/server/revalidate-handler.d.ts +55 -0
  66. package/dist/types/next/server/revalidate-handler.d.ts.map +1 -0
  67. package/dist/types/next/server/server-client.d.ts +21 -0
  68. package/dist/types/next/server/server-client.d.ts.map +1 -0
  69. package/dist/types/next/server.d.ts +19 -0
  70. package/dist/types/next/server.d.ts.map +1 -0
  71. package/dist/types/next/studio-bridge.d.ts +16 -0
  72. package/dist/types/next/studio-bridge.d.ts.map +1 -0
  73. package/dist/types/next/studio-connect.d.ts +27 -0
  74. package/dist/types/next/studio-connect.d.ts.map +1 -0
  75. package/dist/types/next/studio-router.d.ts +50 -0
  76. package/dist/types/next/studio-router.d.ts.map +1 -0
  77. package/dist/types/next/studio-script-src.d.ts +12 -0
  78. package/dist/types/next/studio-script-src.d.ts.map +1 -0
  79. package/dist/types/next/theme-settings-store.d.ts +18 -0
  80. package/dist/types/next/theme-settings-store.d.ts.map +1 -0
  81. package/dist/types/next/translation-context.d.ts +109 -0
  82. package/dist/types/next/translation-context.d.ts.map +1 -0
  83. package/dist/types/next/types.d.ts +674 -0
  84. package/dist/types/next/types.d.ts.map +1 -0
  85. package/dist/types/next/use-weaverse-next-studio.d.ts +34 -0
  86. package/dist/types/next/use-weaverse-next-studio.d.ts.map +1 -0
  87. package/dist/types/next/utils.d.ts +21 -0
  88. package/dist/types/next/utils.d.ts.map +1 -0
  89. package/dist/types/next-server.d.ts +3 -1
  90. package/dist/types/next-server.d.ts.map +1 -1
  91. package/dist/types/next.d.ts +4 -2
  92. package/dist/types/next.d.ts.map +1 -1
  93. package/dist/types/utils/translate.d.ts +51 -0
  94. package/dist/types/utils/translate.d.ts.map +1 -0
  95. package/dist/{weaverse-client-C9IgIH7O.js → weaverse-client-BmceZc5q.js} +49 -771
  96. package/dist/weaverse-client-BmceZc5q.js.map +1 -0
  97. package/dist/{weaverse-client-D59mBW0j.mjs → weaverse-client-CXnM9ayH.mjs} +4 -720
  98. package/dist/weaverse-client-CXnM9ayH.mjs.map +1 -0
  99. package/package.json +13 -7
  100. package/src/hooks/translation-context.tsx +7 -84
  101. package/src/next/client-boundary.ts +51 -0
  102. package/src/next/client.ts +102 -0
  103. package/src/next/hooks.ts +52 -0
  104. package/src/next/index.ts +145 -0
  105. package/src/next/item.ts +167 -0
  106. package/src/next/loader.ts +135 -0
  107. package/src/next/main.tsx +45 -0
  108. package/src/next/provider.tsx +241 -0
  109. package/src/next/registry.ts +63 -0
  110. package/src/next/renderer.tsx +102 -0
  111. package/src/next/request-info.ts +124 -0
  112. package/src/next/revalidate-item.ts +211 -0
  113. package/src/next/root-provider.tsx +201 -0
  114. package/src/next/runtime.ts +559 -0
  115. package/src/next/seo.ts +157 -0
  116. package/src/next/server/configs.ts +178 -0
  117. package/src/next/server/normalize-page-url.ts +73 -0
  118. package/src/next/server/revalidate-handler.ts +357 -0
  119. package/src/next/server/server-client.ts +728 -0
  120. package/src/next/server.ts +67 -0
  121. package/src/next/studio-bridge.tsx +82 -0
  122. package/src/next/studio-connect.tsx +88 -0
  123. package/src/next/studio-router.ts +85 -0
  124. package/src/next/studio-script-src.ts +128 -0
  125. package/src/next/theme-settings-store.ts +47 -0
  126. package/src/next/translation-context.tsx +182 -0
  127. package/src/next/types.ts +764 -0
  128. package/src/next/use-weaverse-next-studio.tsx +106 -0
  129. package/src/next/utils.ts +48 -0
  130. package/src/next-server.ts +41 -1
  131. package/src/next.ts +48 -12
  132. package/src/utils/translate.ts +101 -0
  133. package/dist/internal.js.map +0 -1
  134. package/dist/internal.mjs.map +0 -1
  135. package/dist/nested-key-CR3-YMFi.js.map +0 -1
  136. package/dist/nested-key-_k9aW_Wd.mjs.map +0 -1
  137. package/dist/translation-store-4fAV771j.js +0 -69
  138. package/dist/translation-store-4fAV771j.js.map +0 -1
  139. package/dist/translation-store-BBrw0FOk.mjs +0 -58
  140. package/dist/translation-store-BBrw0FOk.mjs.map +0 -1
  141. package/dist/weaverse-client-C9IgIH7O.js.map +0 -1
  142. package/dist/weaverse-client-D59mBW0j.mjs.map +0 -1
@@ -1,5 +1,5 @@
1
- const require_nested_key = require("./nested-key-CR3-YMFi.js");
2
- const require_translation_store = require("./translation-store-4fAV771j.js");
1
+ const require_translation_store = require("./translation-store-BmGxBALf.js");
2
+ const require_translate = require("./translate-Kt1BYL1n.js");
3
3
  let _weaverse_react = require("@weaverse/react");
4
4
  let _weaverse_schema = require("@weaverse/schema");
5
5
  let react = require("react");
@@ -8,67 +8,16 @@ let _shopify_hydrogen = require("@shopify/hydrogen");
8
8
  let react_error_boundary = require("react-error-boundary");
9
9
  let react_router = require("react-router");
10
10
  //#region src/hooks/translation-context.tsx
11
- /**
12
- * Replace `{{variable}}` patterns in a string with provided values.
13
- *
14
- * @example
15
- * interpolate('Hello {{name}}!', { name: 'World' }) // => 'Hello World!'
16
- * interpolate('-{{percentage}}% Off', { percentage: 15 }) // => '-15% Off'
17
- */
18
- function interpolate(template, variables) {
19
- if (!variables) return template;
20
- return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
21
- const value = variables[key];
22
- return value === void 0 ? match : String(value);
23
- });
24
- }
25
11
  const TranslationContext = (0, react.createContext)(null);
26
12
  TranslationContext.displayName = "WeaverseTranslationContext";
27
- /**
28
- * Build the `t()` translation function over a fixed set of sources.
29
- *
30
- * Resolution order, highest priority first:
31
- * 1. `externalT` – host i18n (e.g. Shopify), unless it echoes the key
32
- * 2. `designOverrides` – live design-mode edits, flat dot-path keys
33
- * 3. `merchantOverrides` – locale overrides from the API, nested
34
- * 4. `staticContent` – the theme's default locale JSON
35
- * 5. the key itself
36
- *
37
- * Design overrides are looked up per-key (own properties only) rather than
38
- * merged into `merchantOverrides`: a flat key like `cart.title` must override
39
- * exactly that leaf without wiping sibling keys (`cart.subtitle`), and a
40
- * per-key own-property lookup never builds nested objects from
41
- * merchant-controlled keys, so it cannot pollute `Object.prototype`.
42
- */
43
- function createTranslate(sources) {
44
- const { staticContent, merchantOverrides, designOverrides, externalT } = sources;
45
- return (key, variables) => {
46
- if (externalT) {
47
- const external = externalT(key, variables);
48
- if (external && external !== key) return external;
49
- }
50
- const design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
51
- const override = merchantOverrides ? require_nested_key.getNestedKey(merchantOverrides, key) : void 0;
52
- const staticValue = require_nested_key.getNestedKey(staticContent, key);
53
- return interpolate(design ?? override ?? staticValue ?? key, variables);
54
- };
55
- }
56
13
  const EMPTY = {};
57
14
  const NOOP_SUBSCRIBE = () => () => {};
58
15
  const NOOP_SNAPSHOT = () => EMPTY;
59
- /**
60
- * Provider that wraps the app to expose the `t()` function.
61
- *
62
- * - `staticContent` – the theme's default locale JSON (from themeSchema.i18n)
63
- * - `merchantOverrides` – locale-specific overrides fetched from the API
64
- * - `translationStore` – optional store for live design-mode text overrides
65
- * (the deprecated `themeTextStore` prop is accepted as a fallback)
66
- */
67
16
  function TranslationProvider({ staticContent, merchantOverrides, t: externalT, translationStore, themeTextStore, children }) {
68
17
  const store = translationStore ?? themeTextStore ?? null;
69
18
  const designOverrides = (0, _weaverse_react.useSafeExternalStore)(store?.subscribe ?? NOOP_SUBSCRIBE, store?.getSnapshot ?? NOOP_SNAPSHOT, store?.getServerSnapshot ?? NOOP_SNAPSHOT);
70
19
  const value = (0, react.useMemo)(() => ({
71
- t: createTranslate({
20
+ t: require_translate.createTranslate({
72
21
  staticContent,
73
22
  merchantOverrides,
74
23
  designOverrides,
@@ -89,55 +38,15 @@ function TranslationProvider({ staticContent, merchantOverrides, t: externalT, t
89
38
  children
90
39
  });
91
40
  }
92
- /**
93
- * Hook to access the translation `t()` function.
94
- *
95
- * Must be used inside a component wrapped by `withWeaverse` or `TranslationProvider`.
96
- *
97
- * @example
98
- * ```tsx
99
- * function CartTitle() {
100
- * const { t } = useTranslation()
101
- * return <h2>{t('cart.title')}</h2>
102
- * }
103
- * ```
104
- */
105
41
  function useTranslation() {
106
42
  const ctx = (0, react.useContext)(TranslationContext);
107
43
  if (!ctx) throw new Error("useTranslation must be used within <TranslationProvider>. Wrap your app with withWeaverse().");
108
44
  return ctx;
109
45
  }
110
- /**
111
- * Legacy name for {@link TranslationProvider}.
112
- * @deprecated Use {@link TranslationProvider} instead.
113
- */
114
46
  const ThemeTextProvider = TranslationProvider;
115
- /**
116
- * Legacy name for {@link useTranslation}.
117
- * @deprecated Use {@link useTranslation} instead.
118
- */
119
47
  const useThemeText = useTranslation;
120
48
  //#endregion
121
49
  //#region src/seo.ts
122
- /**
123
- * Convert a Weaverse page-level SEO payload into React Router
124
- * `MetaDescriptor[]`. Pure, synchronous, tree-shakeable — does not fetch.
125
- *
126
- * Behavior:
127
- * - `title` → top-level `{ title }` descriptor.
128
- * - `description` / `keywords` → `<meta name="...">`.
129
- * - `canonicalUrl` → `<link rel="canonical">`.
130
- * - `openGraph.*` → `<meta property="og:*">`. `og:type` defaults to
131
- * `'website'` when any other OG field is present.
132
- * - `twitter.*` → `<meta name="twitter:*">`. `twitter:card` defaults to
133
- * `'summary'` when any other Twitter field is present.
134
- * - `robots` is always emitted (defaults to `'index,follow'`) so themes
135
- * stacking multiple SEO sources have a deterministic last word on
136
- * indexing for Weaverse-managed pages.
137
- * - Empty strings / missing fields are filtered before return so empty
138
- * descriptors don't override earlier sources (e.g. Hydrogen
139
- * `getSeoMeta`).
140
- */
141
50
  function formatMetaDescriptors(seo) {
142
51
  if (!seo) return [{
143
52
  name: "robots",
@@ -204,38 +113,12 @@ function formatMetaDescriptors(seo) {
204
113
  });
205
114
  return descriptors;
206
115
  }
207
- /**
208
- * Convenience accessor: pull `page.seo` out of a `WeaverseLoaderData`
209
- * (or `WeaversePageData`) and emit `MetaDescriptor[]`. Null-safe.
210
- *
211
- * @example
212
- * ```ts
213
- * export const meta: MetaFunction<typeof loader> = ({ data }) => {
214
- * return getWeaverseSeoMeta(data?.weaverseData)
215
- * }
216
- * ```
217
- */
218
116
  function getWeaverseSeoMeta(data) {
219
117
  if (!data) return formatMetaDescriptors(null);
220
118
  return formatMetaDescriptors(("items" in data && "id" in data ? data : data.page ?? null)?.seo ?? null);
221
119
  }
222
120
  //#endregion
223
121
  //#region src/utils/product-options.ts
224
- /**
225
- * Filter out Weaverse-specific query parameters from product options.
226
- * Removes `isDesignMode` and any parameters starting with `weaverse` prefix.
227
- *
228
- * @param request - The incoming HTTP request
229
- * @returns Filtered product options for Shopify Hydrogen
230
- *
231
- * @example
232
- * ```typescript
233
- * export async function loader({ request }: LoaderFunctionArgs) {
234
- * const selectedOptions = getSelectedProductOptions(request)
235
- * // Use selectedOptions for product queries without Weaverse params
236
- * }
237
- * ```
238
- */
239
122
  function getSelectedProductOptions(request) {
240
123
  return (0, _shopify_hydrogen.getSelectedProductOptions)({ searchParams: new URL(request.url).searchParams }).filter(({ name }) => name !== "isDesignMode" && !name.startsWith("weaverse"));
241
124
  }
@@ -251,7 +134,6 @@ function Main(props) {
251
134
  }
252
135
  //#endregion
253
136
  //#region src/components/index.ts
254
- /** Built-in components required to render the root of every Weaverse page. */
255
137
  let defaultComponents = [{
256
138
  default: Main,
257
139
  schema: (0, _weaverse_schema.createSchema)({
@@ -261,68 +143,19 @@ let defaultComponents = [{
261
143
  }];
262
144
  //#endregion
263
145
  //#region src/hooks/use-weaverse-data-context.ts
264
- /**
265
- * Creates flat route-keyed structure from matches
266
- * Target: {root: {...rootData}, "routes/product": {...productData}}
267
- * Eliminates all duplication by using route IDs as keys
268
- */
269
146
  function createFlatDataContext(matches) {
270
147
  const context = {};
271
148
  for (const match of matches) if (match.data && typeof match.data === "object") context[match.id] = match.data;
272
149
  return context;
273
150
  }
274
- /**
275
- * Hook to get flat route-keyed data context from matches
276
- * Returns: {root: {...}, "routes/xxx": {...}}
277
- * No more useLoaderData dependency - everything comes from matches
278
- */
279
151
  function useWeaverseDataContext() {
280
152
  return createFlatDataContext((0, react_router.useMatches)());
281
153
  }
282
- /**
283
- * Helper function to create flat route-keyed data context from useMatches() result
284
- * Returns: {root: {...}, "routes/xxx": {...}}
285
- */
286
154
  function createWeaverseDataContext(matches) {
287
155
  return createFlatDataContext(matches);
288
156
  }
289
157
  //#endregion
290
158
  //#region src/utils/pick-weaverse-data.ts
291
- /**
292
- * Resolve the `weaverseData` payload for a `<WeaverseHydrogenRoot>` instance.
293
- *
294
- * Resolution order (first match wins):
295
- *
296
- * 1. **Explicit prop** — the caller passed `data` directly. Used as-is,
297
- * including when it is a `Promise` (handled upstream via `<Await>`) or
298
- * an explicit `null` (suppresses rendering).
299
- * 2. **Own route's loader data** — the loader data for the route that
300
- * rendered this component, obtained via `useLoaderData()`. This is
301
- * React Router's route-scoped primitive and is what makes nested
302
- * layout + child Weaverse pages work: each `<WeaverseContent />`
303
- * resolves to *its own* route's `weaverseData` regardless of siblings.
304
- * 3. **Ancestor match fallback** — walk `useMatches()` from leaf to root
305
- * and return the first ancestor whose `loaderData` exposes a
306
- * `weaverseData` key. This preserves the long-standing behaviour where
307
- * a child route with no loader (e.g. an `index.tsx` that omits
308
- * `weaverseData`) still renders its layout's Weaverse page.
309
- *
310
- * The helper is intentionally pure (no hook calls) so it can be unit-tested
311
- * without a React Router context. Hook calls happen in the component.
312
- *
313
- * ## Back-compat contract
314
- *
315
- * Themes that pre-date the `data` prop addition pass `dataProp === undefined`,
316
- * so resolution starts at Tier 2. For the canonical single-instance pattern
317
- * (one `<WeaverseContent />` inside a route whose loader returns
318
- * `{ weaverseData }`), Tier 2 returns the same value the old `useMatches()`
319
- * walk did. For the index-without-loader pattern (leaf route exposes no
320
- * `weaverseData`, layout does), Tier 3's leaf→root walk produces an
321
- * identical result to the pre-fix code. The only intentional behaviour
322
- * change is the issue #451 case: two `<WeaverseContent />` instances on the
323
- * same URL (layout + child, both with their own `weaverseData`) now each
324
- * render their own page instead of both rendering the deepest one.
325
- */
326
159
  function pickWeaverseData(dataProp, ownLoaderData, matches) {
327
160
  if (dataProp !== void 0) return dataProp;
328
161
  if (hasWeaverseData(ownLoaderData)) return ownLoaderData.weaverseData;
@@ -350,15 +183,6 @@ function getQueriesFromSearch(search) {
350
183
  else queries[key] = value;
351
184
  return queries;
352
185
  }
353
- /**
354
- * React Router v7 single-fetch revalidation can render client data returned
355
- * from a `*.data` request while the browser is still on the canonical URL.
356
- * Instance identity must follow the browser URL, not the transient data
357
- * endpoint, otherwise the SDK creates a fresh Weaverse instance mid-session:
358
- * in design mode that drops the existing Studio bridge/interactions, and in
359
- * the live theme it resets every section's runtime state after any
360
- * revalidation (cart mutations, locale switches, `revalidate()`). See #451.
361
- */
362
186
  function normalizeRequestInfo(params, browserLocation = getBrowserLocation()) {
363
187
  if (!browserLocation) return params;
364
188
  let { pathname, search } = browserLocation;
@@ -375,50 +199,12 @@ function normalizeRequestInfo(params, browserLocation = getBrowserLocation()) {
375
199
  }
376
200
  //#endregion
377
201
  //#region src/utils/is-same-loader-payload.ts
378
- /**
379
- * Structural comparison used to detect whether a reused Weaverse instance
380
- * must adopt a fresh loader payload.
381
- *
382
- * `JSON.stringify` cannot do this job on the client:
383
- *
384
- * - Route loader data reaches `dataContext` unserialized, so deferred values
385
- * are still `Promise`s. React 19 development builds hang an enumerable,
386
- * self-referencing `_debugInfo` off those promises, and stringifying one
387
- * throws `TypeError: Converting circular structure to JSON` during render
388
- * (issue #511).
389
- * - In production every promise stringifies to `{}`, so a *fresh* deferred
390
- * value looks unchanged and the reused instance keeps serving the previous
391
- * render's promise. Tokenizing promises to a constant (`'[[promise]]'`) has
392
- * the same defect — it is stable by construction, therefore blind to
393
- * identity.
394
- *
395
- * Semantics, chosen deliberately:
396
- *
397
- * - **Promises/thenables are atomic**: compared by identity, never traversed.
398
- * A fresh promise is a change; the same promise is not. Debug metadata is
399
- * invisible to the comparison.
400
- * - **Opaque objects are atomic**: anything that is not a plain object, an
401
- * array, or `toJSON`-serializable (`Map`, `Set`, `URL`, `RegExp`, streams,
402
- * async iterators, cross-realm promises, class instances) is compared by
403
- * identity. `JSON.stringify` flattens all of them to `{}`, which would
404
- * silently collapse two distinct async values into "unchanged".
405
- * - **Cyclic graphs are compared coinductively**: a pair already being
406
- * compared is assumed equal, so equal self/mutual cycles are equal while a
407
- * differing leaf anywhere still reports a change. Nothing throws.
408
- * - **JSON-visible fields only**: `undefined`/function/symbol properties are
409
- * omitted from objects and read as `null` in arrays, and NaN/±Infinity read
410
- * as `null` — matching the previous `JSON.stringify` behavior for plain wire
411
- * payloads. Key order is irrelevant, which removes the old "false mismatch
412
- * costs a re-render" caveat.
413
- */
414
- /** `JSON.stringify` drops these from objects and nulls them inside arrays. */
415
202
  function isJsonOmitted(value) {
416
203
  return value === void 0 || typeof value === "function" || typeof value === "symbol";
417
204
  }
418
205
  function isObjectLike(value) {
419
206
  return value !== null && typeof value === "object";
420
207
  }
421
- /** Duck-typed so cross-realm promises and hand-rolled thenables also match. */
422
208
  function isThenable(value) {
423
209
  return typeof value.then === "function";
424
210
  }
@@ -426,15 +212,12 @@ function isPlainObject$1(value) {
426
212
  const proto = Object.getPrototypeOf(value);
427
213
  return proto === Object.prototype || proto === null;
428
214
  }
429
- /** Returns the `toJSON()` projection, or the value itself when there is none. */
430
215
  function toJsonValue(value) {
431
216
  return typeof value.toJSON === "function" ? value.toJSON() : value;
432
217
  }
433
- /** Maps NaN/±Infinity to `null`, matching how `JSON.stringify` renders them. */
434
218
  function toFiniteOrNull(value) {
435
219
  return typeof value === "number" && !Number.isFinite(value) ? null : value;
436
220
  }
437
- /** Compares two loader payloads for JSON-visible structural equality. */
438
221
  function isSameLoaderPayload(left, right) {
439
222
  const activePairs = [];
440
223
  function isSame(rawA, rawB) {
@@ -481,25 +264,6 @@ function isSameLoaderPayload(left, right) {
481
264
  }
482
265
  //#endregion
483
266
  //#region src/utils/sync-reused-instance.ts
484
- /**
485
- * Apply a fresh loader payload to a reused Weaverse instance.
486
- *
487
- * With requestInfo normalized to the browser URL, same-URL revalidations
488
- * (cart mutations, `useRevalidator()`, locale-neutral re-fetches) reuse the
489
- * cached `window.__weaverses[pageId]` instance instead of constructing a new
490
- * one — which preserves section state, but would silently drop the fresh
491
- * `data`/`dataContext` the loaders just returned. Sync them here.
492
- *
493
- * Design mode is excluded by the caller: Studio owns the instance data there
494
- * (unsaved drafts must not be clobbered) and applies updates via
495
- * `refreshStudio` instead.
496
- *
497
- * Change detection uses {@link isSameLoaderPayload}: a structural comparison
498
- * that treats promises/thenables and other opaque objects as atomic values
499
- * compared by identity, and tolerates cyclic graphs. `dataContext` carries
500
- * live route loader data — including unresolved deferred promises whose React
501
- * development metadata is cyclic — so it cannot be JSON-serialized here.
502
- */
503
267
  function syncReusedInstance(weaverse, params) {
504
268
  weaverse.requestInfo = params.requestInfo;
505
269
  weaverse.internal = params.internal;
@@ -512,18 +276,13 @@ function syncReusedInstance(weaverse, params) {
512
276
  }
513
277
  //#endregion
514
278
  //#region src/utils/use-theme-settings-store.ts
515
- /** Mutable, subscribable store for theme settings received from the root loader. */
516
279
  var ThemeSettingsStore = class {
517
- /** Current merged theme setting values. */
518
280
  settings = {};
519
- /** Theme schema exposed to Studio, when available. */
520
281
  schema;
521
- /** Storefront-safe environment values, when available. */
522
282
  publicEnv;
523
283
  listeners = /* @__PURE__ */ new Set();
524
284
  hasWarnedListenerCount = false;
525
285
  isDestroyed = false;
526
- /** Creates a theme settings store from root-loader theme data. */
527
286
  constructor(data) {
528
287
  const { theme, schema, publicEnv } = data || {};
529
288
  this.settings = { ...theme };
@@ -531,7 +290,6 @@ var ThemeSettingsStore = class {
531
290
  this.publicEnv = publicEnv;
532
291
  if (_weaverse_react.isBrowser) window.__weaverseThemeSettingsStore = this;
533
292
  }
534
- /** Merges setting changes into the current snapshot and notifies subscribers. */
535
293
  updateThemeSettings = (newSettings) => {
536
294
  if (this.isDestroyed) {
537
295
  console.warn("ThemeSettingsStore: Cannot update destroyed store");
@@ -543,11 +301,8 @@ var ThemeSettingsStore = class {
543
301
  };
544
302
  this.emit();
545
303
  };
546
- /** Returns the current client snapshot for `useSyncExternalStore`. */
547
304
  getSnapshot = () => this.settings;
548
- /** Returns the current server snapshot for `useSyncExternalStore`. */
549
305
  getServerSnapshot = () => this.settings;
550
- /** Subscribes to setting changes and returns an unsubscribe callback. */
551
306
  subscribe = (callback) => {
552
307
  if (this.isDestroyed) {
553
308
  console.warn("ThemeSettingsStore: Cannot subscribe to destroyed store");
@@ -571,7 +326,6 @@ var ThemeSettingsStore = class {
571
326
  console.error("ThemeSettingsStore: Listener error", error);
572
327
  }
573
328
  };
574
- /** Clears subscribers and detaches the browser-global store reference. */
575
329
  destroy = () => {
576
330
  if (this.isDestroyed) return;
577
331
  this.listeners.clear();
@@ -611,17 +365,11 @@ function useThemeSettingsStore() {
611
365
  //#region src/utils/use-studio.ts
612
366
  const STUDIO_READY_POLL_MS = 50;
613
367
  const STUDIO_READY_TIMEOUT_MS = 5e3;
614
- /**
615
- * Resolve once `window.weaverseStudio` is available, or `null` on timeout.
616
- * The studio script sets the global when it *executes*; `loadScript` can
617
- * resolve earlier for tags it did not create (e.g. SSR-injected markup),
618
- * so never assume readiness right after the script promise settles.
619
- */
620
368
  function waitForStudio() {
621
369
  return new Promise((resolve) => {
622
370
  let startedAt = Date.now();
623
371
  function check() {
624
- if (require_nested_key.hasWeaverseStudio(window)) return resolve(window.weaverseStudio);
372
+ if (require_translation_store.hasWeaverseStudio(window)) return resolve(window.weaverseStudio);
625
373
  if (Date.now() - startedAt >= STUDIO_READY_TIMEOUT_MS) {
626
374
  console.warn("[Weaverse] Studio script did not initialize in time");
627
375
  return resolve(null);
@@ -631,38 +379,10 @@ function waitForStudio() {
631
379
  check();
632
380
  });
633
381
  }
634
- /**
635
- * Load the Studio bridge script on every design/preview render so Studio's
636
- * `checkWeaversePage()` handshake is answered instead of timing out — crucially
637
- * on routes where the page-scoped {@link useStudio} never mounts: 404s, error
638
- * boundaries, and non-Weaverse routes. The bridge registers its RPC endpoint
639
- * and `window.weaverseStudio` the moment the script executes, independent of any
640
- * page binding. Without this, a content-less route never loads the script and
641
- * Studio reports a false "Connection lost" instead of "this page has no Weaverse
642
- * content set up".
643
- *
644
- * `loadScript` is idempotent, so on content routes this coexists with the
645
- * page-scoped {@link useStudio} (same src) — that hook still binds the page via
646
- * `init`. Gating this on whether a route "has Weaverse data" is deliberately
647
- * avoided: route matches can't tell whether the page-scoped bridge actually
648
- * mounts (an `ErrorBoundary` replacing a data route, or data passed via the
649
- * `data` prop), and suppressing the script there would reintroduce the timeout
650
- * this fixes. Loading the script is harmless; it only registers the responder.
651
- *
652
- * Known limitation: on a route whose `weaverseData` is a deferred Promise, the
653
- * script can load before the page streams in, so `checkWeaversePage()` may
654
- * briefly observe `NOT_WEAVERSE_PAGE`. The complete fix is a "loading" state in
655
- * `checkWeaversePage` so the handshake retries rather than latching — that lives
656
- * in the Studio script, not here. Tracked in Weaverse/builder#2515.
657
- *
658
- * Mounted via {@link withWeaverse}, which must be the root route's `Layout`
659
- * export so the bridge renders even when a route's `ErrorBoundary` replaces the
660
- * page. Outside Studio (no design/preview params) it is a no-op.
661
- */
662
382
  function useStudioConnect() {
663
383
  let { search } = (0, react_router.useLocation)();
664
384
  (0, react.useEffect)(() => {
665
- let src = require_nested_key.resolveStudioScriptSrc(search, typeof window === "undefined" ? "" : window.location.hostname);
385
+ let src = require_translation_store.resolveStudioScriptSrc(search, typeof window === "undefined" ? "" : window.location.hostname);
666
386
  if (src) (0, _weaverse_react.loadScript)(src).catch(console.error);
667
387
  }, [search]);
668
388
  }
@@ -683,7 +403,7 @@ function useStudio(weaverse) {
683
403
  let { isDesignMode, weaverseHost, weaverseVersion, isPreviewMode, isRevisionPreview } = weaverse;
684
404
  (0, react.useEffect)(() => {
685
405
  if (navigation.state !== "idle") return;
686
- let src = require_nested_key.getStudioScriptSrc({
406
+ let src = require_translation_store.getStudioScriptSrc({
687
407
  isDesignMode,
688
408
  isPreviewMode,
689
409
  isRevisionPreview,
@@ -714,16 +434,10 @@ function useStudio(weaverse) {
714
434
  }
715
435
  //#endregion
716
436
  //#region src/WeaverseHydrogenRoot.tsx
717
- /** Runtime store for one rendered Hydrogen component instance. */
718
437
  var WeaverseHydrogenItem = class extends _weaverse_react.WeaverseItemStore {
719
- /**
720
- * Cached merged snapshot (base + translations).
721
- * Reset to `null` whenever `_store` or the item's translation entry changes.
722
- */
723
438
  _cachedSnapshot = null;
724
439
  _snapshotStoreRef = null;
725
440
  _snapshotTranslationRef = null;
726
- /** Creates an item store from serialized component data and its owner. */
727
441
  constructor(initialData, weaverse) {
728
442
  super(initialData, weaverse);
729
443
  const { data, ...rest } = initialData;
@@ -731,29 +445,12 @@ var WeaverseHydrogenItem = class extends _weaverse_react.WeaverseItemStore {
731
445
  console.error("Element is missing schema or not found!");
732
446
  return;
733
447
  }
734
- const schemaData = require_nested_key.generateDataFromSchema(this.Element.schema);
448
+ const schemaData = require_translation_store.generateDataFromSchema(this.Element.schema);
735
449
  Object.assign(this._store, schemaData, data, rest);
736
450
  }
737
- /** Registered component definition for this item's type. */
738
451
  get Element() {
739
452
  return super.Element;
740
453
  }
741
- /**
742
- * Override setData to flatten serialized `data` the same way the constructor
743
- * does. Core's `initProject()` reuses item stores keyed by item id (identical
744
- * ids across locales), and the inherited setData only shallow-merges the raw
745
- * item — fresh settings would land under `_store.data` while the stale
746
- * flattened values keep rendering.
747
- *
748
- * Schema defaults are re-applied ahead of incoming settings because a
749
- * serialized payload can omit fields — or the optional `data` object itself —
750
- * when values equal schema defaults. The stored nested `data` is also replaced
751
- * so the public serialized state does not retain the previous locale payload.
752
- *
753
- * An empty update is the context-only refresh from `syncReusedInstance`: swap
754
- * the store reference so memoized subscribers re-render, and leave the
755
- * settings untouched.
756
- */
757
454
  setData = (update) => {
758
455
  let source = update ?? {};
759
456
  let { data, ...rest } = source;
@@ -764,7 +461,7 @@ var WeaverseHydrogenItem = class extends _weaverse_react.WeaverseItemStore {
764
461
  let isSerializedItem = "id" in source && "type" in source;
765
462
  if (schema && (data !== void 0 || isSerializedItem)) {
766
463
  let { data: _previousData, ...store } = this._store;
767
- let schemaData = require_nested_key.generateDataFromSchema(schema);
464
+ let schemaData = require_translation_store.generateDataFromSchema(schema);
768
465
  this._store = {
769
466
  ...store,
770
467
  ...data === void 0 ? {} : { data },
@@ -780,12 +477,6 @@ var WeaverseHydrogenItem = class extends _weaverse_react.WeaverseItemStore {
780
477
  this.triggerUpdate();
781
478
  return this.data;
782
479
  };
783
- /**
784
- * Override getSnapShot to merge translation data when in translation mode.
785
- * Memoizes the result: returns the same object reference as long as
786
- * both `_store` and the translation entry haven't changed.
787
- * This is critical for `useSyncExternalStore` stability.
788
- */
789
480
  getSnapShot = () => {
790
481
  const base = this._store;
791
482
  const translations = this.weaverse.translationMap?.[this._id];
@@ -800,50 +491,22 @@ var WeaverseHydrogenItem = class extends _weaverse_react.WeaverseItemStore {
800
491
  };
801
492
  };
802
493
  _weaverse_react.Weaverse.ItemConstructor = WeaverseHydrogenItem;
803
- /**
804
- * Hydrogen-specific Weaverse runtime that owns page data, component stores,
805
- * Studio state, and translation sidecars for one rendered page.
806
- */
807
494
  var WeaverseHydrogen = class extends _weaverse_react.Weaverse {
808
- /** Identifier of the rendered page. */
809
495
  pageId;
810
- /** Runtime services and project metadata exposed to integrations. */
811
496
  internal;
812
- /** Normalized URL and locale information for the current request. */
813
497
  requestInfo;
814
- /** Identifier of the project supplying the page. */
815
498
  projectId;
816
- /** Origin used for Studio assets and editor communication. */
817
499
  weaverseHost;
818
- /** Base URL used for public content API requests. */
819
500
  weaverseApiBase;
820
- /**
821
- * API key read from environment/configuration for storefront requests or
822
- * supplied by Studio requests while editing and previewing.
823
- */
824
501
  weaverseApiKey;
825
- /** Studio asset version supplied by the preview request. */
826
502
  weaverseVersion;
827
- /** Whether the page is running inside the visual editor. */
828
503
  isDesignMode;
829
- /** Whether a single component preview is being rendered. */
830
504
  isPreviewMode;
831
- /** Whether a saved page revision is being previewed. */
832
505
  isRevisionPreview;
833
- /** Component type requested by section preview mode. */
834
506
  sectionType;
835
- /**
836
- * Translation map received from the builder in design mode.
837
- * Keyed by item ID, each entry maps field names to translated values.
838
- * `WeaverseHydrogenItem.getSnapShot()` merges these into the data
839
- * returned to components, so translations render without monkey-patching.
840
- */
841
507
  translationMap = {};
842
- /** Locale code for the active translation sidecar. */
843
508
  translationLocale = "";
844
- /** Builder language identifier for the active translation sidecar. */
845
509
  translationLanguageId = "";
846
- /** Creates a page runtime from resolved loader data and request settings. */
847
510
  constructor(params) {
848
511
  const { internal, pageId, requestInfo, ...coreParams } = params;
849
512
  super({ ...coreParams });
@@ -861,11 +524,6 @@ var WeaverseHydrogen = class extends _weaverse_react.Weaverse {
861
524
  this.sectionType = params.sectionType || "";
862
525
  this.extractTranslationSidecar();
863
526
  }
864
- /**
865
- * Extract translation sidecar data from `this.data` (the page data).
866
- * The builder attaches `translationMap`, `translationLocale`, and
867
- * `translationLanguageId` to the page data in design mode.
868
- */
869
527
  extractTranslationSidecar = () => {
870
528
  const pageData = this.data;
871
529
  if (pageData?.translationMap) {
@@ -874,21 +532,12 @@ var WeaverseHydrogen = class extends _weaverse_react.Weaverse {
874
532
  this.translationLanguageId = pageData.translationLanguageId || "";
875
533
  }
876
534
  };
877
- /**
878
- * Set the translation sidecar data.
879
- * Called by the studio bridge when translation data arrives or changes.
880
- * Triggers a re-render of all items so translated snapshots are recalculated.
881
- */
882
535
  setTranslationSidecar = (translationMap, locale, languageId) => {
883
536
  this.translationMap = translationMap;
884
537
  this.translationLocale = locale;
885
538
  this.translationLanguageId = languageId;
886
539
  this.refreshAllItems();
887
540
  };
888
- /**
889
- * Update a single translation entry for a specific item field.
890
- * Used by the studio bridge when the user edits a translatable field.
891
- */
892
541
  updateTranslation = (itemId, key, originalValue, translatedValue) => {
893
542
  if (!this.translationMap[itemId]) this.translationMap[itemId] = {};
894
543
  this.translationMap[itemId] = {
@@ -901,10 +550,6 @@ var WeaverseHydrogen = class extends _weaverse_react.Weaverse {
901
550
  const instance = this.itemInstances.get(itemId);
902
551
  if (instance) instance.triggerUpdate();
903
552
  };
904
- /**
905
- * Collect all translation changes across all weaverse instances.
906
- * Used by the save flow to persist translation edits.
907
- */
908
553
  getTranslationChanges = () => {
909
554
  const entries = [];
910
555
  const languageId = this.translationLanguageId;
@@ -921,9 +566,6 @@ var WeaverseHydrogen = class extends _weaverse_react.Weaverse {
921
566
  entries
922
567
  };
923
568
  };
924
- /**
925
- * Override setProjectData to re-extract translation sidecar from new page data.
926
- */
927
569
  setProjectData = (data) => {
928
570
  this.data = data;
929
571
  this.extractTranslationSidecar();
@@ -941,7 +583,7 @@ function createWeaverseInstance(params) {
941
583
  runtimeWindow.__weaverses[normalizedParams.pageId] = weaverse;
942
584
  if (weaverse.isDesignMode) {
943
585
  weaverse.requestInfo = normalizedParams.requestInfo;
944
- if (require_nested_key.hasWeaverseStudio(window)) window.weaverseStudio.refreshStudio(normalizedParams);
586
+ if (require_translation_store.hasWeaverseStudio(window)) window.weaverseStudio.refreshStudio(normalizedParams);
945
587
  } else if (isReused) syncReusedInstance(weaverse, normalizedParams);
946
588
  return weaverse;
947
589
  }
@@ -955,12 +597,6 @@ const StudioConnect = (0, react.memo)(() => {
955
597
  useStudioConnect();
956
598
  return null;
957
599
  });
958
- /**
959
- * Component lists already pushed into the element registry. Registration is
960
- * idempotent (the registry checks `has(type)`), but walking the full list
961
- * allocates and loops on every render — theme component arrays are
962
- * module-level constants, so register each list identity once.
963
- */
964
600
  const registeredComponentLists = /* @__PURE__ */ new WeakSet();
965
601
  function RenderRoot(props) {
966
602
  const { data, components, dataContext } = props;
@@ -986,36 +622,9 @@ function RenderRoot(props) {
986
622
  });
987
623
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_weaverse_react.WeaverseRoot, { context: weaverse }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StudioBridge, { context: weaverse })] });
988
624
  }
989
- /**
990
- * Register a Weaverse component with the global element registry.
991
- * Must be called before rendering components in WeaverseHydrogenRoot.
992
- *
993
- * @param element - Component configuration with schema, Component, and optional loader
994
- *
995
- * @example
996
- * ```typescript
997
- * import Hero from './sections/Hero'
998
- * import { schema } from './sections/Hero'
999
- *
1000
- * registerComponent({
1001
- * type: 'hero',
1002
- * Component: Hero,
1003
- * schema,
1004
- * loader: async ({ data, weaverse }) => {
1005
- * return { someData: 'value' }
1006
- * }
1007
- * })
1008
- * ```
1009
- */
1010
625
  function registerComponent(element) {
1011
626
  WeaverseHydrogen.registerElement(element);
1012
627
  }
1013
- /**
1014
- * Renders the Weaverse page for the current React Router route.
1015
- *
1016
- * Pass `data` to override automatic route-loader resolution. A promise is
1017
- * handled with React Router's `Await`, while explicit `null` suppresses output.
1018
- */
1019
628
  const WeaverseHydrogenRoot = (0, react.memo)(({ components, data: dataProp, errorComponent: ErrorComponent = ({ error }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: error instanceof Error ? error.message : "An unexpected error occurred" }) }) => {
1020
629
  const matches = (0, react_router.useMatches)();
1021
630
  const enhancedDataContext = (0, react.useMemo)(() => createWeaverseDataContext(matches), [matches]);
@@ -1046,33 +655,6 @@ const WeaverseHydrogenRoot = (0, react.memo)(({ components, data: dataProp, erro
1046
655
  }
1047
656
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ErrorComponent, { error: { message: "No Weaverse data found in route matches!" } });
1048
657
  });
1049
- /**
1050
- * Higher-order component that wraps your app with Weaverse theme settings and
1051
- * translation context, and mounts the Studio connect bridge.
1052
- *
1053
- * Export the result as your root route's **`Layout`** (not the default route
1054
- * `Component`). In React Router the root `Layout` wraps both the matched route
1055
- * and its `ErrorBoundary`, so the Studio bridge keeps rendering on 404s and
1056
- * loader/render errors — exactly the pages where Studio must still answer its
1057
- * handshake instead of reporting a false "Connection lost". A default-component
1058
- * wrapper (`export default withWeaverse(App)`) is replaced by the error
1059
- * boundary on those routes and would drop the bridge.
1060
- *
1061
- * @param Component - The root layout component to wrap
1062
- * @param options - Optional configuration (e.g. an external `t` function)
1063
- * @returns Wrapped component with theme settings + translation providers
1064
- *
1065
- * @example
1066
- * ```typescript
1067
- * import { withWeaverse } from '@weaverse/hydrogen'
1068
- *
1069
- * // Basic usage — export as the root route Layout
1070
- * export const Layout = withWeaverse(RootLayout)
1071
- *
1072
- * // With an external translation function
1073
- * export const Layout = withWeaverse(RootLayout, { t: myI18nFunction })
1074
- * ```
1075
- */
1076
658
  function withWeaverse(Component, options) {
1077
659
  return (props) => {
1078
660
  const themeSettingsStore = useCreateThemeSettingsStore();
@@ -1095,10 +677,6 @@ function withWeaverse(Component, options) {
1095
677
  });
1096
678
  };
1097
679
  }
1098
- /**
1099
- * Internal hook to read staticContent and merchantOverrides from root loader data.
1100
- * Similar pattern to useThemeSettingsStore – reads from the 'root' route loader.
1101
- */
1102
680
  function useTranslationData() {
1103
681
  const data = (0, react_router.useRouteLoaderData)("root");
1104
682
  return {
@@ -1106,22 +684,6 @@ function useTranslationData() {
1106
684
  merchantOverrides: data?.weaverseTheme?.merchantOverrides
1107
685
  };
1108
686
  }
1109
- /**
1110
- * React hook to access Weaverse theme settings from anywhere in your component tree.
1111
- * Must be used within a component wrapped by `withWeaverse` or inside `WeaverseHydrogenRoot`.
1112
- *
1113
- * @returns Current theme settings object
1114
- *
1115
- * @example
1116
- * ```typescript
1117
- * function MyComponent() {
1118
- * const theme = useThemeSettings()
1119
- * const primaryColor = theme.colors?.primary
1120
- *
1121
- * return <div style={{ color: primaryColor }}>Styled content</div>
1122
- * }
1123
- * ```
1124
- */
1125
687
  function useThemeSettings() {
1126
688
  const themeSettingsStore = useThemeSettingsStore();
1127
689
  return (0, _weaverse_react.useSafeExternalStore)(themeSettingsStore.subscribe, themeSettingsStore.getSnapshot, themeSettingsStore.getServerSnapshot);
@@ -1129,20 +691,6 @@ function useThemeSettings() {
1129
691
  //#endregion
1130
692
  //#region src/utils/normalize-page-url.ts
1131
693
  const KEPT_PARAM_RE = /^(?:__revisionId|isDesignMode|weaverse)/;
1132
- /**
1133
- * Normalize the storefront URL sent in the Builder page API request body.
1134
- *
1135
- * The POST body participates in Hydrogen's cached fetch key, so a raw
1136
- * `request.url` fragments the cache by every marketing/tracking param:
1137
- * each distinct `?utm_…`/`fbclid` URL is a guaranteed Builder round-trip
1138
- * even when the resolved page is identical — precisely the paid/social
1139
- * traffic that needs the cache most (builder#2450).
1140
- *
1141
- * The Builder reads only the pathname (locale/type/handle fallback) and
1142
- * the params matched above from this URL, so keep exactly those. Params
1143
- * are sorted for a stable cache key regardless of their order in the
1144
- * incoming URL.
1145
- */
1146
694
  function normalizePageUrl(url) {
1147
695
  let parsed;
1148
696
  try {
@@ -1159,41 +707,18 @@ function normalizePageUrl(url) {
1159
707
  }
1160
708
  //#endregion
1161
709
  //#region src/weaverse-client.ts
1162
- /**
1163
- * Cache duration constants (in seconds).
1164
- * These values optimize CDN hit rates while maintaining fresh content.
1165
- */
1166
710
  const CACHE_DURATIONS = {
1167
- /** Freshness for content that can change in Builder */
1168
711
  SHORT: 60,
1169
- /** Long stale window so slow Builder responses do not block storefront rendering */
1170
712
  LONG: 86400
1171
713
  };
1172
- /**
1173
- * Network timeout for fetch requests (in milliseconds).
1174
- * Default is 10 seconds to balance reliability and user experience.
1175
- */
1176
714
  const DEFAULT_FETCH_TIMEOUT_MS = 1e4;
1177
- /**
1178
- * Bounded retry for the public API fetch. A single slow/cold origin response,
1179
- * a transient 5xx, or a network blip would otherwise make loadPage return null
1180
- * — rendering the "Please add new section" placeholder or throwing a 404 in
1181
- * the route. Two attempts (one retry) is enough: by the time the first attempt
1182
- * times out, the edge proxy's single-flight leader has usually populated its
1183
- * versioned cache, so the retry lands on a warm HIT.
1184
- */
1185
715
  const MAX_FETCH_ATTEMPTS = 2;
1186
716
  const FETCH_RETRY_BACKOFF_MS = 300;
1187
- /**
1188
- * Retry only transient failures: request timeouts, network errors, and origin
1189
- * 5xx. A 4xx is deterministic (e.g. a genuine 404) — retrying just wastes time.
1190
- */
1191
717
  function isRetryableFetchError(error) {
1192
- if (!(error instanceof require_nested_key.WeaverseError)) return false;
718
+ if (!(error instanceof require_translation_store.WeaverseError)) return false;
1193
719
  if (error.code === "TIMEOUT_ERROR" || error.code === "NETWORK_ERROR" || error.code === "INVALID_RESPONSE") return true;
1194
720
  return error.code === "FETCH_ERROR" && (error.statusCode ?? 0) >= 500;
1195
721
  }
1196
- /** Parses a JSON body, or returns the raw text when it is not JSON. */
1197
722
  function parseResponseText(text) {
1198
723
  if (!text) return text;
1199
724
  try {
@@ -1205,34 +730,17 @@ function parseResponseText(text) {
1205
730
  function isPlainObject(value) {
1206
731
  return typeof value === "object" && value !== null && !Array.isArray(value);
1207
732
  }
1208
- /**
1209
- * Whether a successful `/project` body is a page envelope.
1210
- *
1211
- * `page: null` is Builder's authoritative "nothing assigned at this URL" and
1212
- * stays valid; anything without a `page` field, with an `error` field, or with
1213
- * a page that has no item list is not an answer about this URL at all.
1214
- */
1215
733
  function isProjectEnvelope(payload) {
1216
- if (!isPlainObject(payload) || require_nested_key.hasError(payload) || !("page" in payload)) return false;
734
+ if (!isPlainObject(payload) || require_translation_store.hasError(payload) || !("page" in payload)) return false;
1217
735
  const { page, project } = payload;
1218
736
  return (page === null || isPlainObject(page) && Array.isArray(page.items)) && (project == null || isPlainObject(project));
1219
737
  }
1220
- /**
1221
- * Whether a successful `/project_configs` body carries theme settings.
1222
- *
1223
- * Builder always sends the `theme` field; `null` means the merchant never
1224
- * saved settings, so schema defaults are the real configuration.
1225
- */
1226
738
  function isThemeConfigsEnvelope(payload) {
1227
- return isPlainObject(payload) && !require_nested_key.hasError(payload) && "theme" in payload && (payload.theme === null || isPlainObject(payload.theme));
739
+ return isPlainObject(payload) && !require_translation_store.hasError(payload) && "theme" in payload && (payload.theme === null || isPlainObject(payload.theme));
1228
740
  }
1229
- /**
1230
- * Classifies a page-load failure. `'absent'` is Builder's 404 for a project
1231
- * that does not exist, which keeps resolving to `null` like before.
1232
- */
1233
741
  function classifyPageLoadFailure(error) {
1234
- if (error instanceof require_nested_key.WeaverseLoadError) return error.kind;
1235
- if (!(error instanceof require_nested_key.WeaverseError)) return "invalid-response";
742
+ if (error instanceof require_translation_store.WeaverseLoadError) return error.kind;
743
+ if (!(error instanceof require_translation_store.WeaverseError)) return "invalid-response";
1236
744
  if (error.code === "TIMEOUT_ERROR" || error.code === "NETWORK_ERROR") return "unavailable";
1237
745
  if (error.code === "INVALID_RESPONSE") return "invalid-response";
1238
746
  if (error.code === "FETCH_ERROR") {
@@ -1242,116 +750,43 @@ function classifyPageLoadFailure(error) {
1242
750
  }
1243
751
  return "configuration";
1244
752
  }
1245
- /**
1246
- * Validators for Builder requests made by this client itself, keyed on the
1247
- * exact options object (same reasoning as `bodyFreeCacheRequests`). On the
1248
- * cached path such a request rejects a non-2xx status instead of resolving
1249
- * to `null`, and only stores a body its validator accepts. Every other
1250
- * `fetchWithCache` caller keeps the existing behavior.
1251
- */
1252
753
  const builderPayloadValidators = /* @__PURE__ */ new WeakMap();
1253
- /**
1254
- * Gives a rejection from Hydrogen's cached fetch the code `fetchOnce` gives
1255
- * the same failure on the direct path.
1256
- *
1257
- * Hydrogen calls the platform `fetch` itself, so a request that never got a
1258
- * response rejects with the platform's error instead of a `WeaverseError`.
1259
- * The Fetch standard rejects a network failure with a `TypeError` and an
1260
- * aborted request with the signal's `AbortError`/`TimeoutError`; those are
1261
- * outages. Anything else is returned unchanged, so it is not reported as one.
1262
- */
1263
754
  function cachedTransportError(error, url) {
1264
- if (error instanceof require_nested_key.WeaverseError || !(error instanceof Error)) return error;
1265
- if (error.name === "AbortError" || error.name === "TimeoutError") return new require_nested_key.WeaverseError("Request timed out", "TIMEOUT_ERROR", void 0, { url });
1266
- if (error instanceof TypeError) return new require_nested_key.WeaverseError("Network error during fetch", "NETWORK_ERROR", void 0, {
755
+ if (error instanceof require_translation_store.WeaverseError || !(error instanceof Error)) return error;
756
+ if (error.name === "AbortError" || error.name === "TimeoutError") return new require_translation_store.WeaverseError("Request timed out", "TIMEOUT_ERROR", void 0, { url });
757
+ if (error instanceof TypeError) return new require_translation_store.WeaverseError("Network error during fetch", "NETWORK_ERROR", void 0, {
1267
758
  url,
1268
759
  cause: error.message
1269
760
  });
1270
761
  return error;
1271
762
  }
1272
- /**
1273
- * Weaverse API version path
1274
- */
1275
763
  const API_PATH = "v1";
1276
- /**
1277
- * Cache strategy for Weaverse API requests: fresh for a minute, then served
1278
- * stale for a day while it refreshes or while Builder errors.
1279
- *
1280
- * Every Builder resource uses it. Hydrogen 2026.4's subrequest cache only read
1281
- * `max-age` for freshness, so the old per-resource `sMaxAge` values never
1282
- * changed how long an entry stayed fresh.
1283
- */
1284
764
  const DEFAULT_CACHE_STRATEGY = (0, _shopify_hydrogen.Cache)({
1285
765
  maxAge: CACHE_DURATIONS.SHORT,
1286
766
  staleWhileRevalidate: CACHE_DURATIONS.LONG,
1287
767
  staleIfError: CACHE_DURATIONS.LONG
1288
768
  });
1289
- /**
1290
- * Options objects created by the internal `project_configs` request whose
1291
- * subrequest cache identity deliberately excludes the body. Theme settings
1292
- * carry the storefront origin so Builder can attribute hostnames; hashing the
1293
- * body would give every domain of one project its own entry.
1294
- *
1295
- * The SUCCESSFUL theme payload is the same for every storefront of a project,
1296
- * which is what makes one shared entry correct. This is not a claim that
1297
- * Builder can never answer differently per host: a hostname-blocked request
1298
- * returns a 403 `{ error }` body, and `shouldCacheResponse` rejects anything
1299
- * `hasError()` matches, so a refusal is never stored under (or served from)
1300
- * the shared entry. If a future response shape ever varies by host WITHOUT an
1301
- * `error` field, this exclusion has to be revisited.
1302
- *
1303
- * Keyed on the exact options object, NOT on `cacheTarget`: `fetchWithCache`
1304
- * is public API, so gating on the target would silently collapse the cache of
1305
- * any consumer who selects `theme-settings` with varying bodies. An outside
1306
- * caller's options object is never in this set and keeps a body-derived key.
1307
- *
1308
- * The WeakSet-membership slot in the cache key (`has(options)`) is the actual
1309
- * discriminator — no caller-supplied value can reach it. The sentinel is not
1310
- * load-bearing for that; it only keeps the omitted body legible in cache
1311
- * debugging instead of a bare `undefined`.
1312
- */
1313
769
  const bodyFreeCacheRequests = /* @__PURE__ */ new WeakSet();
1314
770
  const BODY_FREE_CACHE_SENTINEL = "\0weaverse:body-free";
1315
- /**
1316
- * Request-scoped client for loading Weaverse pages and theme settings in Hydrogen.
1317
- *
1318
- * Create one client from the Hydrogen app context, then call
1319
- * {@link WeaverseClient.loadPage} from route loaders and
1320
- * {@link WeaverseClient.loadThemeSettings} from the root loader.
1321
- */
1322
771
  var WeaverseClient = class {
1323
- /** Builder API version used by this client. */
1324
772
  API = API_PATH;
1325
- /** Stable project configuration shared by page requests. */
1326
773
  basePageConfigs;
1327
- /** Stable request body fields shared by page requests. */
1328
774
  basePageRequestBody;
1329
- /** Resolved project and rendering-mode configuration. */
1330
775
  configs;
1331
- /** Hydrogen cached fetch used for Builder API requests. */
1332
776
  cachedFetch;
1333
- /** Incoming request associated with this client instance. */
1334
777
  request;
1335
- /** Customer Account API client, when the storefront passes one. */
1336
778
  customerAccount;
1337
- /** Hydrogen Storefront API client and locale context. */
1338
779
  storefront;
1339
- /** Components registered for page rendering and component loaders. */
1340
780
  components;
1341
- /** Theme schema used for defaults and Studio editing. */
1342
781
  themeSchema;
1343
- /** Runtime environment variables. */
1344
782
  env;
1345
- /** Cache storage supplied by the Hydrogen runtime. */
1346
783
  cache;
1347
- /** Background execution hook supplied by the runtime. */
1348
784
  waitUntil;
1349
785
  parsedUrl;
1350
786
  componentsByType;
1351
787
  locale;
1352
788
  fetchTimeoutMs;
1353
789
  throwPageLoadFailures;
1354
- /** Creates a request-scoped client from the storefront's request context. */
1355
790
  constructor(args) {
1356
791
  this.request = args.request;
1357
792
  this.storefront = args.storefront;
@@ -1369,10 +804,6 @@ var WeaverseClient = class {
1369
804
  this.initializeCache(args);
1370
805
  this.initializeConfigs(args);
1371
806
  }
1372
- /**
1373
- * Initialize Hydrogen cache with proper configuration.
1374
- * Logs warning if waitUntil is missing.
1375
- */
1376
807
  initializeCache(args) {
1377
808
  if (!args.waitUntil) console.warn("⚠️ WeaverseClient: waitUntil not provided, background operations may not complete");
1378
809
  this.cachedFetch = (0, _shopify_hydrogen.createFetchWithCache)({
@@ -1380,14 +811,10 @@ var WeaverseClient = class {
1380
811
  waitUntil: args.waitUntil
1381
812
  });
1382
813
  }
1383
- /**
1384
- * Initialize configs with projectId resolution and fail-fast validation.
1385
- * Throws WeaverseError if projectId cannot be resolved.
1386
- */
1387
814
  initializeConfigs(args) {
1388
- const baseConfigs = require_nested_key.getWeaverseConfigs(args.request, args.env);
815
+ const baseConfigs = require_translation_store.getWeaverseConfigs(args.request, args.env);
1389
816
  const resolvedProjectId = this.resolveProjectIdSync(args.projectId, args.request, args.env, baseConfigs);
1390
- if (!resolvedProjectId || resolvedProjectId.trim() === "") throw new require_nested_key.WeaverseError("Failed to initialize WeaverseClient: No valid projectId found. Set WEAVERSE_PROJECT_ID environment variable or provide projectId parameter.", "MISSING_PROJECT_ID");
817
+ if (!resolvedProjectId || resolvedProjectId.trim() === "") throw new require_translation_store.WeaverseError("Failed to initialize WeaverseClient: No valid projectId found. Set WEAVERSE_PROJECT_ID environment variable or provide projectId parameter.", "MISSING_PROJECT_ID");
1391
818
  this.configs = {
1392
819
  ...baseConfigs,
1393
820
  projectId: resolvedProjectId
@@ -1411,32 +838,11 @@ var WeaverseClient = class {
1411
838
  Object.freeze(this.basePageConfigs);
1412
839
  Object.freeze(this.basePageRequestBody);
1413
840
  }
1414
- /**
1415
- * Build component lookup map for O(1) access by type.
1416
- * Significantly improves performance for large component lists.
1417
- */
1418
841
  buildComponentLookupMap(components) {
1419
842
  return new Map(components.map((comp) => [comp.schema?.type, comp]));
1420
843
  }
1421
- /**
1422
- * Extract comprehensive error information from unknown error type.
1423
- * Preserves error context, codes, and stack traces for debugging.
1424
- *
1425
- * @param error - Unknown error to extract information from
1426
- * @returns Structured error information with message, code, stack, and context
1427
- *
1428
- * @example
1429
- * ```typescript
1430
- * try {
1431
- * // ... operation
1432
- * } catch (error) {
1433
- * const errorInfo = this.extractErrorInfo(error)
1434
- * console.error('Operation failed:', errorInfo.message, errorInfo.context)
1435
- * }
1436
- * ```
1437
- */
1438
844
  extractErrorInfo(error) {
1439
- if (error instanceof require_nested_key.WeaverseError) return {
845
+ if (error instanceof require_translation_store.WeaverseError) return {
1440
846
  message: error.message,
1441
847
  code: error.code,
1442
848
  context: error.context,
@@ -1448,22 +854,9 @@ var WeaverseClient = class {
1448
854
  };
1449
855
  return { message: String(error) };
1450
856
  }
1451
- /**
1452
- * Extract error message only (for backward compatibility).
1453
- * Use extractErrorInfo() for more detailed error information.
1454
- *
1455
- * @deprecated Use extractErrorInfo() instead to preserve error context
1456
- */
1457
857
  extractErrorMessage(error) {
1458
858
  return this.extractErrorInfo(error).message;
1459
859
  }
1460
- /**
1461
- * Validates projectId format (alphanumeric, hyphens, underscores only).
1462
- * Returns detailed validation result with error message.
1463
- *
1464
- * @param projectId - Project identifier to validate
1465
- * @returns Validation result with error message if invalid
1466
- */
1467
860
  validateProjectId(projectId) {
1468
861
  if (!projectId || projectId.trim() === "") return {
1469
862
  valid: false,
@@ -1475,71 +868,43 @@ var WeaverseClient = class {
1475
868
  };
1476
869
  return { valid: true };
1477
870
  }
1478
- /**
1479
- * Resolves projectId with multi-project architecture support.
1480
- * Uses priority chain to determine the correct project ID.
1481
- *
1482
- * @param projectId - Project identifier (string, function, or undefined)
1483
- * @param request - HTTP request for context access
1484
- * @param env - Hydrogen environment with variables
1485
- * @param baseConfigs - Pre-fetched base configs to avoid duplicate calls
1486
- * @returns Resolved project ID string (empty string if none found)
1487
- */
1488
871
  resolveProjectIdSync(projectId, request, env, baseConfigs) {
1489
872
  return this.resolveFromQueryParams(request) || this.resolveFromFunction(projectId) || this.resolveFromString(projectId) || this.resolveFromEnvironment(baseConfigs, request, env) || "";
1490
873
  }
1491
- /**
1492
- * Priority 1: Resolve projectId from URL query parameters.
1493
- * Used for design mode and preview mode overrides.
1494
- */
1495
874
  resolveFromQueryParams(request) {
1496
- return require_nested_key.getRequestQueries(request).weaverseProjectId || null;
875
+ return require_translation_store.getRequestQueries(request).weaverseProjectId || null;
1497
876
  }
1498
- /**
1499
- * Priority 2: Resolve projectId from function parameter.
1500
- * Detects and rejects async functions with helpful error.
1501
- */
1502
877
  resolveFromFunction(projectId) {
1503
- if (!require_nested_key.isProjectIdFunction(projectId)) return null;
1504
- if (projectId.constructor.name === "AsyncFunction") throw new require_nested_key.WeaverseError("Async projectId functions must be awaited before passing to WeaverseClient. Use: projectId: await getProjectAsync() instead of: projectId: getProjectAsync", "ASYNC_PROJECT_ID");
878
+ if (!require_translation_store.isProjectIdFunction(projectId)) return null;
879
+ if (projectId.constructor.name === "AsyncFunction") throw new require_translation_store.WeaverseError("Async projectId functions must be awaited before passing to WeaverseClient. Use: projectId: await getProjectAsync() instead of: projectId: getProjectAsync", "ASYNC_PROJECT_ID");
1505
880
  try {
1506
881
  const result = projectId();
1507
- if (result instanceof Promise) throw new require_nested_key.WeaverseError("Async projectId functions must be awaited before passing to WeaverseClient. Use: projectId: await getProjectAsync() instead of: projectId: getProjectAsync", "ASYNC_PROJECT_ID");
882
+ if (result instanceof Promise) throw new require_translation_store.WeaverseError("Async projectId functions must be awaited before passing to WeaverseClient. Use: projectId: await getProjectAsync() instead of: projectId: getProjectAsync", "ASYNC_PROJECT_ID");
1508
883
  if (result && result.trim() !== "") {
1509
884
  const trimmed = result.trim();
1510
885
  const validation = this.validateProjectId(trimmed);
1511
886
  if (validation.valid) return trimmed;
1512
- throw new require_nested_key.WeaverseError(validation.error || "Invalid projectId format", "INVALID_PROJECT_ID");
887
+ throw new require_translation_store.WeaverseError(validation.error || "Invalid projectId format", "INVALID_PROJECT_ID");
1513
888
  }
1514
889
  } catch (err) {
1515
- if (err instanceof require_nested_key.WeaverseError) throw err;
1516
- throw new require_nested_key.WeaverseError(`Failed to evaluate projectId function: ${err instanceof Error ? err.message : String(err)}`, "PROJECT_ID_FUNCTION_ERROR", void 0, { cause: err instanceof Error ? err.stack : String(err) });
890
+ if (err instanceof require_translation_store.WeaverseError) throw err;
891
+ throw new require_translation_store.WeaverseError(`Failed to evaluate projectId function: ${err instanceof Error ? err.message : String(err)}`, "PROJECT_ID_FUNCTION_ERROR", void 0, { cause: err instanceof Error ? err.stack : String(err) });
1517
892
  }
1518
893
  return null;
1519
894
  }
1520
- /**
1521
- * Priority 3: Resolve projectId from explicit string parameter.
1522
- */
1523
895
  resolveFromString(projectId) {
1524
896
  if (typeof projectId !== "string") return null;
1525
897
  const trimmed = projectId.trim();
1526
898
  if (trimmed === "") return null;
1527
899
  const validation = this.validateProjectId(trimmed);
1528
900
  if (validation.valid) return trimmed;
1529
- throw new require_nested_key.WeaverseError(validation.error || "Invalid projectId format", "INVALID_PROJECT_ID");
901
+ throw new require_translation_store.WeaverseError(validation.error || "Invalid projectId format", "INVALID_PROJECT_ID");
1530
902
  }
1531
- /**
1532
- * Priority 4: Resolve projectId from environment variables.
1533
- */
1534
903
  resolveFromEnvironment(baseConfigs, request, env) {
1535
- const configs = baseConfigs || require_nested_key.getWeaverseConfigs(request, env);
904
+ const configs = baseConfigs || require_translation_store.getWeaverseConfigs(request, env);
1536
905
  if (configs.projectId && configs.projectId.trim() !== "") return configs.projectId.trim();
1537
906
  return null;
1538
907
  }
1539
- /**
1540
- * Helper method for direct fetching in design mode.
1541
- * Includes 10-second timeout to prevent hanging requests.
1542
- */
1543
908
  fetchOnce = async (url, options, timeoutMs) => {
1544
909
  const controller = new AbortController();
1545
910
  const timeoutId = setTimeout(() => controller.abort(), timeoutMs);
@@ -1550,7 +915,7 @@ var WeaverseClient = class {
1550
915
  });
1551
916
  if (!response.ok) {
1552
917
  const errorText = await response.text();
1553
- throw new require_nested_key.WeaverseError(`HTTP ${response.status}: ${response.statusText}`, "FETCH_ERROR", response.status, {
918
+ throw new require_translation_store.WeaverseError(`HTTP ${response.status}: ${response.statusText}`, "FETCH_ERROR", response.status, {
1554
919
  url,
1555
920
  errorText
1556
921
  });
@@ -1560,19 +925,19 @@ var WeaverseClient = class {
1560
925
  data = await response.json();
1561
926
  } catch (parseError) {
1562
927
  if (parseError?.name === "AbortError") throw parseError;
1563
- throw new require_nested_key.WeaverseError("Response body is not valid JSON", "INVALID_RESPONSE", response.status, { url });
928
+ throw new require_translation_store.WeaverseError("Response body is not valid JSON", "INVALID_RESPONSE", response.status, { url });
1564
929
  }
1565
930
  return {
1566
931
  data,
1567
932
  response
1568
933
  };
1569
934
  } catch (err) {
1570
- if (err instanceof require_nested_key.WeaverseError) throw err;
1571
- if (err.name === "AbortError") throw new require_nested_key.WeaverseError(`Request timeout after ${timeoutMs}ms`, "TIMEOUT_ERROR", void 0, {
935
+ if (err instanceof require_translation_store.WeaverseError) throw err;
936
+ if (err.name === "AbortError") throw new require_translation_store.WeaverseError(`Request timeout after ${timeoutMs}ms`, "TIMEOUT_ERROR", void 0, {
1572
937
  url,
1573
938
  timeoutMs
1574
939
  });
1575
- throw new require_nested_key.WeaverseError("Network error during fetch", "NETWORK_ERROR", void 0, {
940
+ throw new require_translation_store.WeaverseError("Network error during fetch", "NETWORK_ERROR", void 0, {
1576
941
  url,
1577
942
  cause: err instanceof Error ? err.message : String(err)
1578
943
  });
@@ -1599,23 +964,6 @@ var WeaverseClient = class {
1599
964
  const { weaverseApiBase, weaverseHost } = this.configs;
1600
965
  return weaverseApiBase !== weaverseHost && url.startsWith(`${weaverseApiBase}/api/public/`);
1601
966
  }
1602
- /**
1603
- * Fetch data with caching support for both design mode and production.
1604
- * Uses direct fetch in design mode, Hydrogen's cached fetch in production.
1605
- * Automatically includes projectId in cache key for multi-project isolation.
1606
- *
1607
- * @param url - The URL to fetch from
1608
- * @param options - Fetch options including optional cache strategy
1609
- * @returns Promise resolving to the fetched data
1610
- *
1611
- * @example
1612
- * ```typescript
1613
- * const data = await weaverse.fetchWithCache<MyData>(
1614
- * 'https://api.example.com/data',
1615
- * { method: 'POST', body: JSON.stringify({ key: 'value' }) }
1616
- * )
1617
- * ```
1618
- */
1619
967
  fetchWithCache = async (url, options = {}) => {
1620
968
  const { cacheTarget, strategy: strategyOverride, ...fetchOptions } = options;
1621
969
  const { body } = fetchOptions;
@@ -1641,7 +989,7 @@ var WeaverseClient = class {
1641
989
  if (fetchOptions.signal?.aborted) return false;
1642
990
  const payload = parseResponseText(await readText());
1643
991
  if (validateBuilderPayload && !validateBuilderPayload(payload)) return false;
1644
- return !require_nested_key.hasError(payload) && payload !== null && payload !== "";
992
+ return !require_translation_store.hasError(payload) && payload !== null && payload !== "";
1645
993
  }
1646
994
  });
1647
995
  text = await response.text();
@@ -1649,37 +997,18 @@ var WeaverseClient = class {
1649
997
  throw validateBuilderPayload ? cachedTransportError(error, url) : error;
1650
998
  }
1651
999
  if (!response.ok) {
1652
- if (validateBuilderPayload) throw new require_nested_key.WeaverseError(`HTTP ${response.status}: ${response.statusText}`, "FETCH_ERROR", response.status, { url });
1000
+ if (validateBuilderPayload) throw new require_translation_store.WeaverseError(`HTTP ${response.status}: ${response.statusText}`, "FETCH_ERROR", response.status, { url });
1653
1001
  return null;
1654
1002
  }
1655
1003
  return parseResponseText(text);
1656
1004
  };
1657
- /**
1658
- * Safe origin of the incoming storefront request: scheme, host and explicit
1659
- * port. Userinfo, path, query and fragment are dropped, so no customer
1660
- * route or credential-bearing value leaves the storefront. Returns undefined
1661
- * for a non-http(s) request so the field is simply omitted.
1662
- */
1663
1005
  safeStorefrontOrigin() {
1664
1006
  const { protocol, host } = this.parsedUrl;
1665
1007
  if (protocol !== "http:" && protocol !== "https:") return;
1666
1008
  return host ? `${protocol}//${host}` : void 0;
1667
1009
  }
1668
- /**
1669
- * Load theme settings from Weaverse API with fallback to schema defaults.
1670
- * Merges remote settings with local theme schema and handles design mode serialization.
1671
- *
1672
- * @param strategy - Optional cache strategy override
1673
- * @returns Promise resolving to theme settings response
1674
- *
1675
- * @example
1676
- * ```typescript
1677
- * const settings = await weaverse.loadThemeSettings()
1678
- * const primaryColor = settings.theme.colors?.primary
1679
- * ```
1680
- */
1681
1010
  loadThemeSettings = async (strategy) => {
1682
- const defaultThemeSettings = require_nested_key.generateDataFromSchema(this.themeSchema);
1011
+ const defaultThemeSettings = require_translation_store.generateDataFromSchema(this.themeSchema);
1683
1012
  try {
1684
1013
  const { configs } = this;
1685
1014
  const { projectId, isDesignMode } = configs;
@@ -1703,7 +1032,7 @@ var WeaverseClient = class {
1703
1032
  bodyFreeCacheRequests.add(themeSettingsOptions);
1704
1033
  builderPayloadValidators.set(themeSettingsOptions, isThemeConfigsEnvelope);
1705
1034
  const [data, merchantOverrides] = await Promise.all([this.fetchWithCache(url, themeSettingsOptions), this.fetchMerchantOverrides(strategy)]);
1706
- if (!isThemeConfigsEnvelope(data)) throw new require_nested_key.WeaverseError("Invalid theme settings response format", "INVALID_RESPONSE");
1035
+ if (!isThemeConfigsEnvelope(data)) throw new require_translation_store.WeaverseError("Invalid theme settings response format", "INVALID_RESPONSE");
1707
1036
  let result = data;
1708
1037
  if (this.themeSchema?.settings || this.themeSchema?.inspector) if (!result.theme || typeof result.theme !== "object") result.theme = defaultThemeSettings;
1709
1038
  else result.theme = {
@@ -1743,11 +1072,6 @@ var WeaverseClient = class {
1743
1072
  };
1744
1073
  }
1745
1074
  };
1746
- /**
1747
- * Fetch locale-specific merchant overrides from the translation API.
1748
- * Returns a nested JSON object with translated values.
1749
- * Falls back to empty object on error to avoid blocking theme rendering.
1750
- */
1751
1075
  fetchMerchantOverrides = async (strategy) => {
1752
1076
  try {
1753
1077
  const { projectId, weaverseHost } = this.configs;
@@ -1769,13 +1093,6 @@ var WeaverseClient = class {
1769
1093
  return;
1770
1094
  }
1771
1095
  };
1772
- /**
1773
- * Generate fallback page with default structure when page data is unavailable.
1774
- * Used internally when API returns no page or when page needs default content.
1775
- *
1776
- * @param message - Custom message to display in the fallback page
1777
- * @returns WeaversePageData with single main component containing the message
1778
- */
1779
1096
  generateFallbackPage = (message) => {
1780
1097
  const rootId = crypto.randomUUID();
1781
1098
  return {
@@ -1789,10 +1106,6 @@ var WeaverseClient = class {
1789
1106
  }]
1790
1107
  };
1791
1108
  };
1792
- /**
1793
- * Fetch all published custom pages for sitemap generation.
1794
- * Paginates automatically, never throws, returns accumulated results on partial failure.
1795
- */
1796
1109
  async fetchCustomPages(opts) {
1797
1110
  const { weaverseApiBase, projectId } = this.configs;
1798
1111
  const entries = [];
@@ -1820,40 +1133,12 @@ var WeaverseClient = class {
1820
1133
  console.warn("[Weaverse] Custom pages pagination cap reached (100 iterations)");
1821
1134
  return entries;
1822
1135
  }
1823
- /**
1824
- * Load page data from Weaverse API with optional route-level project override.
1825
- * Fetches page content, executes component loaders, and handles empty items fallback.
1826
- *
1827
- * @param params - Optional page loading parameters
1828
- * @param params.type - Page type (INDEX, PAGE, PRODUCT, COLLECTION, etc.)
1829
- * @param params.handle - Page handle for dynamic routes
1830
- * @param params.locale - Locale override
1831
- * @param params.projectId - Route-level project ID override (for multi-project)
1832
- * @param params.strategy - Custom cache strategy override
1833
- * @returns Promise resolving to page data or null on error
1834
- *
1835
- * @example
1836
- * ```typescript
1837
- * // Basic usage
1838
- * const data = await weaverse.loadPage()
1839
- *
1840
- * // With page type
1841
- * const data = await weaverse.loadPage({ type: 'INDEX' })
1842
- *
1843
- * // Route-level project override
1844
- * const data = await weaverse.loadPage({
1845
- * type: 'PAGE',
1846
- * handle: 'about',
1847
- * projectId: 'campaign-project-123'
1848
- * })
1849
- * ```
1850
- */
1851
1136
  loadPage = async (params = {}) => {
1852
1137
  if (params.projectId !== void 0) {
1853
1138
  const message = typeof params.projectId === "string" ? this.validateProjectId(params.projectId).error : `must be a string. Received: ${typeof params.projectId}`;
1854
1139
  if (message) {
1855
1140
  console.error(`Route-level projectId validation failed: ${message}`);
1856
- if (this.throwPageLoadFailures) throw new require_nested_key.WeaverseLoadError("Route-level projectId validation failed", "configuration");
1141
+ if (this.throwPageLoadFailures) throw new require_translation_store.WeaverseLoadError("Route-level projectId validation failed", "configuration");
1857
1142
  return null;
1858
1143
  }
1859
1144
  }
@@ -1861,8 +1146,8 @@ var WeaverseClient = class {
1861
1146
  const { request, basePageRequestBody, basePageConfigs } = this;
1862
1147
  const { projectId: clientProjectId, weaverseHost, isPreviewMode, sectionType } = this.configs;
1863
1148
  const effectiveProjectId = params.projectId || clientProjectId;
1864
- if (isPreviewMode) return require_nested_key.getPreviewData(sectionType || "", this.components, weaverseHost);
1865
- if (!effectiveProjectId) throw new require_nested_key.WeaverseLoadError("Missing Weaverse projectId!", "configuration");
1149
+ if (isPreviewMode) return require_translation_store.getPreviewData(sectionType || "", this.components, weaverseHost);
1150
+ if (!effectiveProjectId) throw new require_translation_store.WeaverseLoadError("Missing Weaverse projectId!", "configuration");
1866
1151
  const { strategy, ...pageLoadParams } = params;
1867
1152
  const body = {
1868
1153
  ...basePageRequestBody,
@@ -1888,9 +1173,9 @@ var WeaverseClient = class {
1888
1173
  };
1889
1174
  builderPayloadValidators.set(projectOptions, isProjectEnvelope);
1890
1175
  const projectData = await this.fetchWithCache(url, projectOptions);
1891
- if (require_nested_key.hasError(projectData)) throw new require_nested_key.WeaverseLoadError("Weaverse API returned an error body", "invalid-response");
1176
+ if (require_translation_store.hasError(projectData)) throw new require_translation_store.WeaverseLoadError("Weaverse API returned an error body", "invalid-response");
1892
1177
  if (!isProjectEnvelope(projectData)) {
1893
- if (this.throwPageLoadFailures) throw new require_nested_key.WeaverseLoadError("Invalid project data structure received from API", "invalid-response");
1178
+ if (this.throwPageLoadFailures) throw new require_translation_store.WeaverseLoadError("Invalid project data structure received from API", "invalid-response");
1894
1179
  console.warn("Invalid project data structure received from API, using fallback data", { projectId: effectiveProjectId });
1895
1180
  }
1896
1181
  const responseData = projectData;
@@ -1923,7 +1208,7 @@ var WeaverseClient = class {
1923
1208
  ...basePageConfigs,
1924
1209
  requestInfo: {
1925
1210
  i18n: this.locale,
1926
- queries: require_nested_key.getRequestQueries(request),
1211
+ queries: require_translation_store.getRequestQueries(request),
1927
1212
  pathname: this.parsedUrl.pathname,
1928
1213
  search: this.parsedUrl.search
1929
1214
  }
@@ -1933,7 +1218,7 @@ var WeaverseClient = class {
1933
1218
  const failure = classifyPageLoadFailure(error);
1934
1219
  const errorMessage = "❌ Page load failed";
1935
1220
  const errorContext = { projectId: params.projectId || this.configs.projectId };
1936
- if (error instanceof require_nested_key.WeaverseError) console.error(errorMessage, {
1221
+ if (error instanceof require_translation_store.WeaverseError) console.error(errorMessage, {
1937
1222
  code: error.code,
1938
1223
  message: error.message,
1939
1224
  ...errorContext,
@@ -1949,11 +1234,10 @@ var WeaverseClient = class {
1949
1234
  ...errorContext
1950
1235
  });
1951
1236
  if (failure === "absent" || !this.throwPageLoadFailures) return null;
1952
- if (error instanceof require_nested_key.WeaverseLoadError) throw error;
1953
- throw new require_nested_key.WeaverseLoadError("Unable to load Weaverse page", failure, error instanceof require_nested_key.WeaverseError ? error.statusCode : void 0);
1237
+ if (error instanceof require_translation_store.WeaverseLoadError) throw error;
1238
+ throw new require_translation_store.WeaverseLoadError("Unable to load Weaverse page", failure, error instanceof require_translation_store.WeaverseError ? error.statusCode : void 0);
1954
1239
  }
1955
1240
  };
1956
- /** Executes the registered loader for one component and attaches its result. */
1957
1241
  execComponentLoader = async (item) => {
1958
1242
  const { data = {}, type, id } = item;
1959
1243
  const component = this.componentsByType.get(type);
@@ -1963,7 +1247,7 @@ var WeaverseClient = class {
1963
1247
  ...item,
1964
1248
  loaderData: await Promise.resolve(loader({
1965
1249
  data: {
1966
- ...require_nested_key.generateDataFromSchema(component.schema),
1250
+ ...require_translation_store.generateDataFromSchema(component.schema),
1967
1251
  ...data
1968
1252
  },
1969
1253
  weaverse: this
@@ -2043,12 +1327,6 @@ Object.defineProperty(exports, "getWeaverseSeoMeta", {
2043
1327
  return getWeaverseSeoMeta;
2044
1328
  }
2045
1329
  });
2046
- Object.defineProperty(exports, "interpolate", {
2047
- enumerable: true,
2048
- get: function() {
2049
- return interpolate;
2050
- }
2051
- });
2052
1330
  Object.defineProperty(exports, "registerComponent", {
2053
1331
  enumerable: true,
2054
1332
  get: function() {
@@ -2086,4 +1364,4 @@ Object.defineProperty(exports, "withWeaverse", {
2086
1364
  }
2087
1365
  });
2088
1366
 
2089
- //# sourceMappingURL=weaverse-client-C9IgIH7O.js.map
1367
+ //# sourceMappingURL=weaverse-client-BmceZc5q.js.map