@weaverse/next 1.0.1 → 1.1.0-beta.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.
@@ -1,1395 +1,1017 @@
1
1
  'use client'
2
-
3
- // src/client-boundary.ts
4
- import {
5
- useChildInstances,
6
- useItemInstance,
7
- useParentInstance,
8
- useWeaverse
9
- } from "@weaverse/react";
10
-
11
- // src/registry.ts
12
- import { Weaverse as Weaverse2 } from "@weaverse/react";
13
-
14
- // src/item.ts
15
- import { Weaverse, WeaverseItemStore } from "@weaverse/react";
16
-
17
- // src/utils.ts
2
+ import { Weaverse, WeaverseItemStore, WeaverseRoot, useChildInstances, useItemInstance, useParentInstance, useSafeExternalStore, useWeaverse } from "@weaverse/react";
3
+ import { PageTypeSchema, createSchema } from "@weaverse/schema";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
+ import { createContext, memo, useContext, useEffect, useLayoutEffect, useMemo, useRef, useSyncExternalStore } from "react";
6
+ import { useRouter } from "next/navigation";
7
+ //#region src/utils.ts
18
8
  function generateDataFromSchema(schema) {
19
- let data = {};
20
- if (!schema) {
21
- return data;
22
- }
23
- let groups = schema.settings ?? schema.inspector ?? [];
24
- for (let group of groups) {
25
- for (let input of group?.inputs ?? []) {
26
- let { name, defaultValue } = input;
27
- if (name && defaultValue !== null && defaultValue !== void 0) {
28
- data[name] = defaultValue;
29
- }
30
- }
31
- }
32
- return data;
33
- }
34
- var isBrowser = typeof window !== "undefined";
35
- var isIframe = isBrowser && window.top !== window.self;
36
-
37
- // src/item.ts
9
+ let data = {};
10
+ if (!schema) return data;
11
+ let groups = schema.settings ?? schema.inspector ?? [];
12
+ for (let group of groups) for (let input of group?.inputs ?? []) {
13
+ let { name, defaultValue } = input;
14
+ if (name && defaultValue !== null && defaultValue !== void 0) data[name] = defaultValue;
15
+ }
16
+ return data;
17
+ }
18
+ typeof window !== "undefined" && (window.top, window.self);
19
+ //#endregion
20
+ //#region src/item.ts
38
21
  function flattenItemData(update) {
39
- let { data, ...rest } = update;
40
- if (!(data && typeof data === "object" && !Array.isArray(data))) {
41
- return rest;
42
- }
43
- return { ...data, ...rest };
44
- }
45
- var deferredItemUpdates = null;
22
+ let { data, ...rest } = update;
23
+ if (!(data && typeof data === "object" && !Array.isArray(data))) return rest;
24
+ return {
25
+ ...data,
26
+ ...rest
27
+ };
28
+ }
29
+ let deferredItemUpdates = null;
46
30
  function collectDeferredItemUpdates(create) {
47
- let previousQueue = deferredItemUpdates;
48
- let queue = /* @__PURE__ */ new Set();
49
- deferredItemUpdates = queue;
50
- try {
51
- return [create(), [...queue]];
52
- } finally {
53
- deferredItemUpdates = previousQueue;
54
- }
31
+ let previousQueue = deferredItemUpdates;
32
+ let queue = /* @__PURE__ */ new Set();
33
+ deferredItemUpdates = queue;
34
+ try {
35
+ return [create(), [...queue]];
36
+ } finally {
37
+ deferredItemUpdates = previousQueue;
38
+ }
55
39
  }
56
40
  var WeaverseNextItem = class extends WeaverseItemStore {
57
- /**
58
- * Cached merged snapshot (base `_store` + translations). Reset whenever the
59
- * `_store` ref or the item's translation entry ref changes, so
60
- * `useSyncExternalStore` sees a stable object between unrelated re-renders.
61
- */
62
- _cachedSnapshot = null;
63
- _snapshotStoreRef = null;
64
- _snapshotTranslationRef = null;
65
- /** Create an item store from serialized component data and its runtime. */
66
- constructor(initialData, weaverse) {
67
- super(initialData, weaverse);
68
- let schemaData = generateDataFromSchema(this.Element?.schema);
69
- Object.assign(this._store, schemaData, flattenItemData(initialData));
70
- }
71
- /**
72
- * Flatten nested `data` on updates exactly like the constructor does. Core's
73
- * `initProject()` calls `setData(item)` when a new runtime serves a page
74
- * whose item instances already exist (e.g. locale/client navigation).
75
- *
76
- * A complete serialized item (it carries `id` and `type`; core's
77
- * `initProject()` always passes one) replaces the store the way the
78
- * constructor builds it: the schema defaults of the item's own `type` — the
79
- * Builder can replace a section in place, keeping its id — then the item's
80
- * settings. A payload omits a setting — or the whole optional `data` — when
81
- * its value equals the schema default, so merging into the previous store
82
- * would keep the previous locale's value visible. Partial updates still
83
- * merge. Either way the `_store` ref changes, which invalidates the memoized
84
- * snapshot below. The subscriber emit is queued instead of fired when a
85
- * render-phase deferral is active (see `collectDeferredItemUpdates`).
86
- */
87
- setData = (update) => {
88
- if ("id" in update && "type" in update) {
89
- let { data, type } = update;
90
- let schema = this.weaverse.elementRegistry.get(type)?.schema;
91
- this._store = {
92
- ...generateDataFromSchema(schema),
93
- ...data === void 0 ? {} : { data },
94
- ...flattenItemData(update)
95
- };
96
- } else {
97
- this.data = flattenItemData(update);
98
- }
99
- if (deferredItemUpdates) {
100
- deferredItemUpdates.add(this);
101
- } else {
102
- this.triggerUpdate();
103
- }
104
- return this.data;
105
- };
106
- /**
107
- * Overlay item-level translations onto the base store when the runtime is in
108
- * translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
109
- * memoized by `_store` ref + translation entry ref so the returned object is
110
- * referentially stable, and a fast path that returns the base store untouched
111
- * when the item has no translations.
112
- */
113
- getSnapShot = () => {
114
- let base = this._store;
115
- let translations = this.weaverse.translationMap[this._id];
116
- if (!translations) {
117
- return base;
118
- }
119
- if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
120
- return this._cachedSnapshot;
121
- }
122
- let merged = { ...base };
123
- for (let [key, entry] of Object.entries(translations)) {
124
- if (entry.translatedValue !== void 0) {
125
- merged[key] = entry.translatedValue;
126
- }
127
- }
128
- this._cachedSnapshot = merged;
129
- this._snapshotStoreRef = base;
130
- this._snapshotTranslationRef = translations;
131
- return merged;
132
- };
41
+ _cachedSnapshot = null;
42
+ _snapshotStoreRef = null;
43
+ _snapshotTranslationRef = null;
44
+ constructor(initialData, weaverse) {
45
+ super(initialData, weaverse);
46
+ let schemaData = generateDataFromSchema(this.Element?.schema);
47
+ Object.assign(this._store, schemaData, flattenItemData(initialData));
48
+ }
49
+ setData = (update) => {
50
+ if ("id" in update && "type" in update) {
51
+ let { data, type } = update;
52
+ let schema = this.weaverse.elementRegistry.get(type)?.schema;
53
+ this._store = {
54
+ ...generateDataFromSchema(schema),
55
+ ...data === void 0 ? {} : { data },
56
+ ...flattenItemData(update)
57
+ };
58
+ } else this.data = flattenItemData(update);
59
+ if (deferredItemUpdates) deferredItemUpdates.add(this);
60
+ else this.triggerUpdate();
61
+ return this.data;
62
+ };
63
+ getSnapShot = () => {
64
+ let base = this._store;
65
+ let translations = this.weaverse.translationMap[this._id];
66
+ if (!translations) return base;
67
+ if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) return this._cachedSnapshot;
68
+ let merged = { ...base };
69
+ for (let [key, entry] of Object.entries(translations)) if (entry.translatedValue !== void 0) merged[key] = entry.translatedValue;
70
+ this._cachedSnapshot = merged;
71
+ this._snapshotStoreRef = base;
72
+ this._snapshotTranslationRef = translations;
73
+ return merged;
74
+ };
133
75
  };
134
76
  function ensureNextItemConstructor() {
135
- if (!Weaverse.ItemConstructor || Weaverse.ItemConstructor === WeaverseItemStore || Weaverse.ItemConstructor === WeaverseNextItem) {
136
- Weaverse.ItemConstructor = WeaverseNextItem;
137
- }
77
+ if (!Weaverse.ItemConstructor || Weaverse.ItemConstructor === WeaverseItemStore || Weaverse.ItemConstructor === WeaverseNextItem) Weaverse.ItemConstructor = WeaverseNextItem;
138
78
  }
139
-
140
- // src/main.tsx
141
- import { createSchema } from "@weaverse/schema";
142
- import { jsx } from "react/jsx-runtime";
79
+ //#endregion
80
+ //#region src/main.tsx
143
81
  function Main(props) {
144
- let { children, loaderData, ...rest } = props;
145
- return /* @__PURE__ */ jsx("div", { ...rest, children });
82
+ let { children, loaderData, ...rest } = props;
83
+ return /* @__PURE__ */ jsx("div", {
84
+ ...rest,
85
+ children
86
+ });
146
87
  }
147
88
  Main.displayName = "main";
148
- var mainSchema = createSchema({
149
- type: "main",
150
- title: "Main"
151
- });
152
- var defaultMainComponent = {
153
- default: Main,
154
- schema: mainSchema
89
+ const defaultMainComponent = {
90
+ default: Main,
91
+ schema: createSchema({
92
+ type: "main",
93
+ title: "Main"
94
+ })
155
95
  };
156
-
157
- // src/registry.ts
158
- var MAIN_TYPE = "main";
159
- var registeredComponentTypes = /* @__PURE__ */ new Set();
96
+ //#endregion
97
+ //#region src/registry.ts
98
+ const MAIN_TYPE = "main";
99
+ const registeredComponentTypes = /* @__PURE__ */ new Set();
160
100
  function registerWeaverseNextComponents(components) {
161
- ensureNextItemConstructor();
162
- let hasUserMain = components.some(
163
- (component) => component.schema?.type === MAIN_TYPE
164
- );
165
- let effectiveComponents = hasUserMain ? components : [defaultMainComponent, ...components];
166
- for (let component of effectiveComponents) {
167
- let type = component.schema.type;
168
- let element = {
169
- type,
170
- Component: component.default,
171
- schema: component.schema,
172
- loader: component.loader
173
- };
174
- if (type === MAIN_TYPE && hasUserMain) {
175
- Weaverse2.elementRegistry.set(type, element);
176
- registeredComponentTypes.add(type);
177
- continue;
178
- }
179
- if (type && !registeredComponentTypes.has(type)) {
180
- Weaverse2.registerElement(element);
181
- registeredComponentTypes.add(type);
182
- }
183
- }
184
- }
185
-
186
- // src/client.ts
101
+ ensureNextItemConstructor();
102
+ let hasUserMain = components.some((component) => component.schema?.type === MAIN_TYPE);
103
+ let effectiveComponents = hasUserMain ? components : [defaultMainComponent, ...components];
104
+ for (let component of effectiveComponents) {
105
+ let type = component.schema.type;
106
+ let element = {
107
+ type,
108
+ Component: component.default,
109
+ schema: component.schema,
110
+ loader: component.loader
111
+ };
112
+ if (type === MAIN_TYPE && hasUserMain) {
113
+ Weaverse.elementRegistry.set(type, element);
114
+ registeredComponentTypes.add(type);
115
+ continue;
116
+ }
117
+ if (type && !registeredComponentTypes.has(type)) {
118
+ Weaverse.registerElement(element);
119
+ registeredComponentTypes.add(type);
120
+ }
121
+ }
122
+ }
123
+ //#endregion
124
+ //#region src/client.ts
187
125
  var NextClient = class {
188
- projectId;
189
- components;
190
- themeSchema;
191
- themeSettings;
192
- requestContext;
193
- commerce;
194
- data = null;
195
- dataContext = {};
196
- _fetchPage;
197
- _fetchThemeSettings;
198
- constructor(config) {
199
- this.projectId = config.projectId;
200
- this.components = config.components;
201
- registerWeaverseNextComponents(this.components);
202
- this.themeSchema = config.themeSchema;
203
- this.themeSettings = {
204
- ...generateDataFromSchema(config.themeSchema),
205
- ...config.themeSettings
206
- };
207
- this.requestContext = config.requestContext;
208
- this.commerce = config.commerce;
209
- this._fetchPage = config.fetchPage;
210
- this._fetchThemeSettings = config.fetchThemeSettings;
211
- }
212
- /** Compatibility alias so loaders can call `weaverse.storefront.query(...)`. */
213
- get storefront() {
214
- return this.commerce?.storefront;
215
- }
216
- loadPage = (input = {}) => {
217
- if (!this._fetchPage) {
218
- throw new Error(
219
- "[WeaverseNextClient] loadPage requires a `fetchPage` function in client config."
220
- );
221
- }
222
- return this._fetchPage(input);
223
- };
224
- loadThemeSettings = (context) => {
225
- if (!this._fetchThemeSettings) {
226
- throw new Error(
227
- "[WeaverseNextClient] loadThemeSettings requires a `fetchThemeSettings` function in client config."
228
- );
229
- }
230
- return this._fetchThemeSettings(context ?? this.requestContext);
231
- };
126
+ projectId;
127
+ components;
128
+ themeSchema;
129
+ themeSettings;
130
+ requestContext;
131
+ commerce;
132
+ data = null;
133
+ dataContext = {};
134
+ _fetchPage;
135
+ _fetchThemeSettings;
136
+ constructor(config) {
137
+ this.projectId = config.projectId;
138
+ this.components = config.components;
139
+ registerWeaverseNextComponents(this.components);
140
+ this.themeSchema = config.themeSchema;
141
+ this.themeSettings = {
142
+ ...generateDataFromSchema(config.themeSchema),
143
+ ...config.themeSettings
144
+ };
145
+ this.requestContext = config.requestContext;
146
+ this.commerce = config.commerce;
147
+ this._fetchPage = config.fetchPage;
148
+ this._fetchThemeSettings = config.fetchThemeSettings;
149
+ }
150
+ get storefront() {
151
+ return this.commerce?.storefront;
152
+ }
153
+ loadPage = (input = {}) => {
154
+ if (!this._fetchPage) throw new Error("[WeaverseNextClient] loadPage requires a `fetchPage` function in client config.");
155
+ return this._fetchPage(input);
156
+ };
157
+ loadThemeSettings = (context) => {
158
+ if (!this._fetchThemeSettings) throw new Error("[WeaverseNextClient] loadThemeSettings requires a `fetchThemeSettings` function in client config.");
159
+ return this._fetchThemeSettings(context ?? this.requestContext);
160
+ };
232
161
  };
233
162
  function createWeaverseNextClient(config) {
234
- return new NextClient(config);
163
+ return new NextClient(config);
235
164
  }
236
-
237
- // src/hooks.ts
238
- import { useContext as useContext3, useSyncExternalStore } from "react";
239
-
240
- // src/provider.tsx
241
- import {
242
- createContext as createContext3,
243
- useContext as useContext2,
244
- useEffect as useEffect2,
245
- useMemo as useMemo3,
246
- useRef as useRef2
247
- } from "react";
248
-
249
- // src/root-provider.tsx
250
- import {
251
- createContext as createContext2,
252
- useEffect,
253
- useMemo as useMemo2,
254
- useRef
255
- } from "react";
256
-
257
- // src/theme-settings-store.ts
165
+ //#endregion
166
+ //#region src/theme-settings-store.ts
258
167
  function createWeaverseNextThemeSettingsStore(options = {}) {
259
- let listeners = /* @__PURE__ */ new Set();
260
- let store = {
261
- publicEnv: options.publicEnv,
262
- schema: options.schema,
263
- settings: { ...options.settings ?? {} },
264
- getServerSnapshot: () => store.settings,
265
- getSnapshot: () => store.settings,
266
- subscribe: (listener) => {
267
- listeners.add(listener);
268
- return () => {
269
- listeners.delete(listener);
270
- };
271
- },
272
- updateThemeSettings: (next) => {
273
- store.settings = { ...store.settings, ...next };
274
- for (let listener of listeners) {
275
- listener();
276
- }
277
- }
278
- };
279
- return store;
280
- }
281
-
282
- // src/translation-context.tsx
283
- import { useSafeExternalStore } from "@weaverse/react";
284
- import { createContext, useContext, useMemo } from "react";
285
-
286
- // src/translate.ts
168
+ let listeners = /* @__PURE__ */ new Set();
169
+ let store = {
170
+ publicEnv: options.publicEnv,
171
+ schema: options.schema,
172
+ settings: { ...options.settings ?? {} },
173
+ getServerSnapshot: () => store.settings,
174
+ getSnapshot: () => store.settings,
175
+ subscribe: (listener) => {
176
+ listeners.add(listener);
177
+ return () => {
178
+ listeners.delete(listener);
179
+ };
180
+ },
181
+ updateThemeSettings: (next) => {
182
+ store.settings = {
183
+ ...store.settings,
184
+ ...next
185
+ };
186
+ for (let listener of listeners) listener();
187
+ }
188
+ };
189
+ return store;
190
+ }
191
+ //#endregion
192
+ //#region src/translate.ts
287
193
  function getNestedKey(obj, path, fallback) {
288
- let keys = path.split(".");
289
- let current = obj;
290
- for (let key of keys) {
291
- if (current == null || typeof current !== "object") {
292
- return fallback;
293
- }
294
- current = current[key];
295
- }
296
- if (typeof current === "string") {
297
- return current;
298
- }
299
- return fallback;
194
+ let keys = path.split(".");
195
+ let current = obj;
196
+ for (let key of keys) {
197
+ if (current == null || typeof current !== "object") return fallback;
198
+ current = current[key];
199
+ }
200
+ if (typeof current === "string") return current;
201
+ return fallback;
300
202
  }
301
203
  function interpolate(template, variables) {
302
- if (!variables) {
303
- return template;
304
- }
305
- return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
306
- let value = variables[key];
307
- return value === void 0 ? match : String(value);
308
- });
204
+ if (!variables) return template;
205
+ return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
206
+ let value = variables[key];
207
+ return value === void 0 ? match : String(value);
208
+ });
309
209
  }
310
210
  function createTranslate(sources) {
311
- let { staticContent, merchantOverrides, designOverrides, externalT } = sources;
312
- return (key, variables) => {
313
- if (externalT) {
314
- let external = externalT(key, variables);
315
- if (external && external !== key) {
316
- return external;
317
- }
318
- }
319
- let design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
320
- let override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
321
- let staticValue = getNestedKey(staticContent, key);
322
- let raw = design ?? override ?? staticValue ?? key;
323
- return interpolate(raw, variables);
324
- };
325
- }
326
-
327
- // src/translation-context.tsx
328
- import { jsx as jsx2 } from "react/jsx-runtime";
329
- var TranslationContext = createContext(null);
211
+ let { staticContent, merchantOverrides, designOverrides, externalT } = sources;
212
+ return (key, variables) => {
213
+ if (externalT) {
214
+ let external = externalT(key, variables);
215
+ if (external && external !== key) return external;
216
+ }
217
+ let design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
218
+ let override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
219
+ let staticValue = getNestedKey(staticContent, key);
220
+ return interpolate(design ?? override ?? staticValue ?? key, variables);
221
+ };
222
+ }
223
+ //#endregion
224
+ //#region src/translation-context.tsx
225
+ const TranslationContext = createContext(null);
330
226
  TranslationContext.displayName = "WeaverseNextTranslationContext";
331
- var EMPTY = {};
332
- var NOOP_SUBSCRIBE = () => () => {
333
- };
334
- var NOOP_SNAPSHOT = () => EMPTY;
335
- function TranslationProvider({
336
- staticContent,
337
- merchantOverrides,
338
- t: externalT,
339
- translationStore,
340
- themeTextStore,
341
- children
342
- }) {
343
- let store = translationStore ?? themeTextStore ?? null;
344
- let designOverrides = useSafeExternalStore(
345
- store?.subscribe ?? NOOP_SUBSCRIBE,
346
- store?.getSnapshot ?? NOOP_SNAPSHOT,
347
- store?.getServerSnapshot ?? NOOP_SNAPSHOT
348
- );
349
- let value = useMemo(
350
- () => ({
351
- t: createTranslate({
352
- staticContent,
353
- merchantOverrides,
354
- designOverrides,
355
- externalT
356
- }),
357
- translationStore: store,
358
- // Deprecated alias — same instance, kept for backward compatibility.
359
- themeTextStore: store,
360
- merchantOverrides: merchantOverrides ?? null
361
- }),
362
- [staticContent, merchantOverrides, designOverrides, externalT, store]
363
- );
364
- return /* @__PURE__ */ jsx2(TranslationContext.Provider, { value, children });
227
+ const EMPTY = {};
228
+ const NOOP_SUBSCRIBE = () => () => {};
229
+ const NOOP_SNAPSHOT = () => EMPTY;
230
+ function TranslationProvider({ staticContent, merchantOverrides, t: externalT, translationStore, themeTextStore, children }) {
231
+ let store = translationStore ?? themeTextStore ?? null;
232
+ let designOverrides = useSafeExternalStore(store?.subscribe ?? NOOP_SUBSCRIBE, store?.getSnapshot ?? NOOP_SNAPSHOT, store?.getServerSnapshot ?? NOOP_SNAPSHOT);
233
+ let value = useMemo(() => ({
234
+ t: createTranslate({
235
+ staticContent,
236
+ merchantOverrides,
237
+ designOverrides,
238
+ externalT
239
+ }),
240
+ translationStore: store,
241
+ themeTextStore: store,
242
+ merchantOverrides: merchantOverrides ?? null
243
+ }), [
244
+ staticContent,
245
+ merchantOverrides,
246
+ designOverrides,
247
+ externalT,
248
+ store
249
+ ]);
250
+ return /* @__PURE__ */ jsx(TranslationContext.Provider, {
251
+ value,
252
+ children
253
+ });
365
254
  }
366
255
  function useTranslation() {
367
- let ctx = useContext(TranslationContext);
368
- if (!ctx) {
369
- throw new Error(
370
- "useTranslation must be used within <TranslationProvider>. Wrap your app with <WeaverseNextRootProvider>."
371
- );
372
- }
373
- return ctx;
374
- }
375
- var ThemeTextProvider = TranslationProvider;
376
- var useThemeText = useTranslation;
377
-
378
- // src/translation-store.ts
256
+ let ctx = useContext(TranslationContext);
257
+ if (!ctx) throw new Error("useTranslation must be used within <TranslationProvider>. Wrap your app with <WeaverseNextRootProvider>.");
258
+ return ctx;
259
+ }
260
+ const ThemeTextProvider = TranslationProvider;
261
+ const useThemeText = useTranslation;
262
+ //#endregion
263
+ //#region src/translation-store.ts
379
264
  var TranslationStore = class {
380
- /** Current flat translation overrides keyed by dot path. */
381
- overrides = {};
382
- listeners = /* @__PURE__ */ new Set();
383
- /** Replace every override and notify subscribers. */
384
- setOverrides = (overrides) => {
385
- this.overrides = { ...overrides };
386
- this.emit();
387
- };
388
- /** Merge changed overrides into the current values and notify subscribers. */
389
- updateOverrides = (newOverrides) => {
390
- this.overrides = { ...this.overrides, ...newOverrides };
391
- this.emit();
392
- };
393
- /** Return the current client-side override snapshot. */
394
- getSnapshot = () => this.overrides;
395
- /** Return the override snapshot used during server rendering. */
396
- getServerSnapshot = () => this.overrides;
397
- /** Subscribe to override changes and return an unsubscribe function. */
398
- subscribe = (callback) => {
399
- this.listeners.add(callback);
400
- return () => {
401
- this.listeners.delete(callback);
402
- };
403
- };
404
- emit = () => {
405
- for (const listener of Array.from(this.listeners)) {
406
- try {
407
- listener();
408
- } catch (error) {
409
- console.error("TranslationStore: Listener error", error);
410
- }
411
- }
412
- };
265
+ overrides = {};
266
+ listeners = /* @__PURE__ */ new Set();
267
+ setOverrides = (overrides) => {
268
+ this.overrides = { ...overrides };
269
+ this.emit();
270
+ };
271
+ updateOverrides = (newOverrides) => {
272
+ this.overrides = {
273
+ ...this.overrides,
274
+ ...newOverrides
275
+ };
276
+ this.emit();
277
+ };
278
+ getSnapshot = () => this.overrides;
279
+ getServerSnapshot = () => this.overrides;
280
+ subscribe = (callback) => {
281
+ this.listeners.add(callback);
282
+ return () => {
283
+ this.listeners.delete(callback);
284
+ };
285
+ };
286
+ emit = () => {
287
+ for (const listener of Array.from(this.listeners)) try {
288
+ listener();
289
+ } catch (error) {
290
+ console.error("TranslationStore: Listener error", error);
291
+ }
292
+ };
413
293
  };
414
-
415
- // src/root-provider.tsx
416
- import { jsx as jsx3 } from "react/jsx-runtime";
417
- var WeaverseNextRootContext = createContext2(null);
294
+ //#endregion
295
+ //#region src/root-provider.tsx
296
+ const WeaverseNextRootContext = createContext(null);
418
297
  function WeaverseNextRootProvider(props) {
419
- let {
420
- children,
421
- initialThemeSettings,
422
- merchantOverrides,
423
- staticContent,
424
- t,
425
- themeSchema,
426
- publicEnv
427
- } = props;
428
- let storeRef = useRef(null);
429
- if (!storeRef.current) {
430
- storeRef.current = createWeaverseNextThemeSettingsStore({
431
- publicEnv,
432
- schema: themeSchema,
433
- settings: initialThemeSettings
434
- });
435
- }
436
- let themeSettingsStore = storeRef.current;
437
- let translationStoreRef = useRef(null);
438
- if (!translationStoreRef.current) {
439
- translationStoreRef.current = new TranslationStore();
440
- }
441
- let translationStore = translationStoreRef.current;
442
- let appliedThemeSettingsRef = useRef(initialThemeSettings);
443
- useEffect(() => {
444
- if (initialThemeSettings && appliedThemeSettingsRef.current !== initialThemeSettings) {
445
- themeSettingsStore.updateThemeSettings(initialThemeSettings);
446
- appliedThemeSettingsRef.current = initialThemeSettings;
447
- }
448
- }, [initialThemeSettings, themeSettingsStore]);
449
- let resolvedStaticContent = staticContent ?? getSchemaStaticContent(themeSchema);
450
- let rootContextValue = useMemo2(
451
- () => ({
452
- merchantOverrides,
453
- staticContent: resolvedStaticContent,
454
- themeSettingsStore,
455
- translationStore
456
- }),
457
- [
458
- merchantOverrides,
459
- resolvedStaticContent,
460
- themeSettingsStore,
461
- translationStore
462
- ]
463
- );
464
- let contextValue = useMemo2(
465
- () => ({
466
- merchantOverrides,
467
- themeSettings: themeSettingsStore.getSnapshot(),
468
- themeSettingsStore,
469
- translationStore
470
- }),
471
- [merchantOverrides, themeSettingsStore, translationStore]
472
- );
473
- return /* @__PURE__ */ jsx3(WeaverseNextRootContext.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx3(WeaverseNextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx3(
474
- TranslationProvider,
475
- {
476
- merchantOverrides,
477
- staticContent: resolvedStaticContent,
478
- t,
479
- translationStore,
480
- children
481
- }
482
- ) }) });
483
- }
484
-
485
- // src/provider.tsx
486
- import { jsx as jsx4 } from "react/jsx-runtime";
487
- var EMPTY_THEME_SETTINGS = {};
488
- var EMPTY_STATIC_CONTENT = {};
298
+ let { children, initialThemeSettings, merchantOverrides, staticContent, t, themeSchema, publicEnv } = props;
299
+ let storeRef = useRef(null);
300
+ if (!storeRef.current) storeRef.current = createWeaverseNextThemeSettingsStore({
301
+ publicEnv,
302
+ schema: themeSchema,
303
+ settings: initialThemeSettings
304
+ });
305
+ let themeSettingsStore = storeRef.current;
306
+ let translationStoreRef = useRef(null);
307
+ if (!translationStoreRef.current) translationStoreRef.current = new TranslationStore();
308
+ let translationStore = translationStoreRef.current;
309
+ let appliedThemeSettingsRef = useRef(initialThemeSettings);
310
+ useEffect(() => {
311
+ if (initialThemeSettings && appliedThemeSettingsRef.current !== initialThemeSettings) {
312
+ themeSettingsStore.updateThemeSettings(initialThemeSettings);
313
+ appliedThemeSettingsRef.current = initialThemeSettings;
314
+ }
315
+ }, [initialThemeSettings, themeSettingsStore]);
316
+ let resolvedStaticContent = staticContent ?? getSchemaStaticContent(themeSchema);
317
+ let rootContextValue = useMemo(() => ({
318
+ merchantOverrides,
319
+ staticContent: resolvedStaticContent,
320
+ themeSettingsStore,
321
+ translationStore
322
+ }), [
323
+ merchantOverrides,
324
+ resolvedStaticContent,
325
+ themeSettingsStore,
326
+ translationStore
327
+ ]);
328
+ let contextValue = useMemo(() => ({
329
+ merchantOverrides,
330
+ themeSettings: themeSettingsStore.getSnapshot(),
331
+ themeSettingsStore,
332
+ translationStore
333
+ }), [
334
+ merchantOverrides,
335
+ themeSettingsStore,
336
+ translationStore
337
+ ]);
338
+ return /* @__PURE__ */ jsx(WeaverseNextRootContext.Provider, {
339
+ value: rootContextValue,
340
+ children: /* @__PURE__ */ jsx(WeaverseNextContext.Provider, {
341
+ value: contextValue,
342
+ children: /* @__PURE__ */ jsx(TranslationProvider, {
343
+ merchantOverrides,
344
+ staticContent: resolvedStaticContent,
345
+ t,
346
+ translationStore,
347
+ children
348
+ })
349
+ })
350
+ });
351
+ }
352
+ //#endregion
353
+ //#region src/provider.tsx
354
+ const EMPTY_THEME_SETTINGS = {};
355
+ const EMPTY_STATIC_CONTENT = {};
489
356
  function getSchemaStaticContent(schema) {
490
- let i18n = schema?.i18n;
491
- return i18n?.staticContent ?? EMPTY_STATIC_CONTENT;
357
+ return (schema?.i18n)?.staticContent ?? EMPTY_STATIC_CONTENT;
492
358
  }
493
- var WeaverseNextContext = createContext3(null);
359
+ const WeaverseNextContext = createContext(null);
494
360
  function WeaverseNextProvider(props) {
495
- let { children, client, rootData, pageData, commerce, themeSettings } = props;
496
- let rootContext = useContext2(WeaverseNextRootContext);
497
- let themeSettingsValue = themeSettings ?? client?.themeSettings ?? EMPTY_THEME_SETTINGS;
498
- let ownTranslationStoreRef = useRef2(null);
499
- if (!(rootContext || ownTranslationStoreRef.current)) {
500
- ownTranslationStoreRef.current = new TranslationStore();
501
- }
502
- let translationStore = rootContext?.translationStore ?? ownTranslationStoreRef.current;
503
- let staticContent = props.staticContent ?? rootContext?.staticContent ?? getSchemaStaticContent(client?.themeSchema);
504
- let merchantOverrides = props.merchantOverrides ?? rootContext?.merchantOverrides;
505
- let ownThemeSettingsStore = useMemo3(() => {
506
- if (rootContext) {
507
- return null;
508
- }
509
- return createWeaverseNextThemeSettingsStore({
510
- schema: client?.themeSchema,
511
- settings: themeSettingsValue
512
- });
513
- }, [rootContext, client?.themeSchema, themeSettingsValue]);
514
- let themeSettingsStore = rootContext?.themeSettingsStore ?? ownThemeSettingsStore;
515
- let mergedIntoRootRef = useRef2(void 0);
516
- useEffect2(() => {
517
- if (rootContext && themeSettingsValue !== EMPTY_THEME_SETTINGS && mergedIntoRootRef.current !== themeSettingsValue) {
518
- rootContext.themeSettingsStore.updateThemeSettings(themeSettingsValue);
519
- mergedIntoRootRef.current = themeSettingsValue;
520
- }
521
- }, [rootContext, themeSettingsValue]);
522
- let value = useMemo3(
523
- () => ({
524
- client,
525
- rootData,
526
- pageData,
527
- commerce: commerce ?? client?.commerce,
528
- merchantOverrides,
529
- themeSettings: themeSettingsStore.getSnapshot(),
530
- themeSettingsStore,
531
- translationStore
532
- }),
533
- [
534
- client,
535
- rootData,
536
- pageData,
537
- commerce,
538
- merchantOverrides,
539
- themeSettingsStore,
540
- translationStore
541
- ]
542
- );
543
- return /* @__PURE__ */ jsx4(WeaverseNextContext.Provider, { value, children: /* @__PURE__ */ jsx4(
544
- TranslationProvider,
545
- {
546
- merchantOverrides,
547
- staticContent,
548
- t: props.t,
549
- translationStore,
550
- children
551
- }
552
- ) });
553
- }
554
-
555
- // src/hooks.ts
556
- var OUTSIDE_PROVIDER_ERROR = "must be used inside a <WeaverseNextProvider>.";
361
+ let { children, client, rootData, pageData, commerce, themeSettings } = props;
362
+ let rootContext = useContext(WeaverseNextRootContext);
363
+ let themeSettingsValue = themeSettings ?? client?.themeSettings ?? EMPTY_THEME_SETTINGS;
364
+ let ownTranslationStoreRef = useRef(null);
365
+ if (!(rootContext || ownTranslationStoreRef.current)) ownTranslationStoreRef.current = new TranslationStore();
366
+ let translationStore = rootContext?.translationStore ?? ownTranslationStoreRef.current;
367
+ let staticContent = props.staticContent ?? rootContext?.staticContent ?? getSchemaStaticContent(client?.themeSchema);
368
+ let merchantOverrides = props.merchantOverrides ?? rootContext?.merchantOverrides;
369
+ let ownThemeSettingsStore = useMemo(() => {
370
+ if (rootContext) return null;
371
+ return createWeaverseNextThemeSettingsStore({
372
+ schema: client?.themeSchema,
373
+ settings: themeSettingsValue
374
+ });
375
+ }, [
376
+ rootContext,
377
+ client?.themeSchema,
378
+ themeSettingsValue
379
+ ]);
380
+ let themeSettingsStore = rootContext?.themeSettingsStore ?? ownThemeSettingsStore;
381
+ let mergedIntoRootRef = useRef(void 0);
382
+ useEffect(() => {
383
+ if (rootContext && themeSettingsValue !== EMPTY_THEME_SETTINGS && mergedIntoRootRef.current !== themeSettingsValue) {
384
+ rootContext.themeSettingsStore.updateThemeSettings(themeSettingsValue);
385
+ mergedIntoRootRef.current = themeSettingsValue;
386
+ }
387
+ }, [rootContext, themeSettingsValue]);
388
+ let value = useMemo(() => ({
389
+ client,
390
+ rootData,
391
+ pageData,
392
+ commerce: commerce ?? client?.commerce,
393
+ merchantOverrides,
394
+ themeSettings: themeSettingsStore.getSnapshot(),
395
+ themeSettingsStore,
396
+ translationStore
397
+ }), [
398
+ client,
399
+ rootData,
400
+ pageData,
401
+ commerce,
402
+ merchantOverrides,
403
+ themeSettingsStore,
404
+ translationStore
405
+ ]);
406
+ return /* @__PURE__ */ jsx(WeaverseNextContext.Provider, {
407
+ value,
408
+ children: /* @__PURE__ */ jsx(TranslationProvider, {
409
+ merchantOverrides,
410
+ staticContent,
411
+ t: props.t,
412
+ translationStore,
413
+ children
414
+ })
415
+ });
416
+ }
417
+ //#endregion
418
+ //#region src/hooks.ts
419
+ const OUTSIDE_PROVIDER_ERROR = "must be used inside a <WeaverseNextProvider>.";
557
420
  function useWeaverseNextContext(hookName) {
558
- let context = useContext3(WeaverseNextContext);
559
- if (!context) {
560
- throw new Error(`[@weaverse/next] ${hookName} ${OUTSIDE_PROVIDER_ERROR}`);
561
- }
562
- return context;
421
+ let context = useContext(WeaverseNextContext);
422
+ if (!context) throw new Error(`[@weaverse/next] ${hookName} ${OUTSIDE_PROVIDER_ERROR}`);
423
+ return context;
563
424
  }
564
425
  function useWeaverseRootData() {
565
- return useWeaverseNextContext("useWeaverseRootData").rootData;
426
+ return useWeaverseNextContext("useWeaverseRootData").rootData;
566
427
  }
567
428
  function useWeaversePageData() {
568
- return useWeaverseNextContext("useWeaversePageData").pageData;
429
+ return useWeaverseNextContext("useWeaversePageData").pageData;
569
430
  }
570
431
  function useWeaverseCommerce() {
571
- return useWeaverseNextContext("useWeaverseCommerce").commerce;
432
+ return useWeaverseNextContext("useWeaverseCommerce").commerce;
572
433
  }
573
434
  function useThemeSettings() {
574
- let { themeSettingsStore } = useWeaverseNextContext("useThemeSettings");
575
- return useSyncExternalStore(
576
- themeSettingsStore.subscribe,
577
- themeSettingsStore.getSnapshot,
578
- themeSettingsStore.getServerSnapshot
579
- );
435
+ let { themeSettingsStore } = useWeaverseNextContext("useThemeSettings");
436
+ return useSyncExternalStore(themeSettingsStore.subscribe, themeSettingsStore.getSnapshot, themeSettingsStore.getServerSnapshot);
580
437
  }
581
-
582
- // src/renderer.tsx
583
- import { WeaverseRoot } from "@weaverse/react";
584
- import { memo, useContext as useContext4, useEffect as useEffect4, useLayoutEffect, useMemo as useMemo4 } from "react";
585
-
586
- // src/runtime.ts
587
- import { Weaverse as Weaverse3 } from "@weaverse/react";
588
-
589
- // src/request-info.ts
438
+ //#endregion
439
+ //#region src/request-info.ts
590
440
  function toUrl(value) {
591
- return typeof value === "string" ? new URL(value, "http://localhost") : value;
441
+ return typeof value === "string" ? new URL(value, "http://localhost") : value;
592
442
  }
593
443
  function getSearchParamsFromContext(context) {
594
- if (context?.searchParams) {
595
- return new URLSearchParams(context.searchParams);
596
- }
597
- if (context?.url) {
598
- let url = toUrl(context.url);
599
- return new URLSearchParams(url.searchParams);
600
- }
601
- return new URLSearchParams();
444
+ if (context?.searchParams) return new URLSearchParams(context.searchParams);
445
+ if (context?.url) {
446
+ let url = toUrl(context.url);
447
+ return new URLSearchParams(url.searchParams);
448
+ }
449
+ return new URLSearchParams();
602
450
  }
603
451
  function withPathPrefix(pathname, i18n) {
604
- let raw = typeof i18n?.pathPrefix === "string" ? i18n.pathPrefix : "";
605
- let segments = raw.split("/").filter(Boolean);
606
- let prefix = segments.length > 0 ? `/${segments.join("/")}` : "";
607
- if (prefix === "" || pathname === prefix || pathname.startsWith(`${prefix}/`)) {
608
- return pathname;
609
- }
610
- return pathname === "/" ? prefix : `${prefix}${pathname}`;
452
+ let segments = (typeof i18n?.pathPrefix === "string" ? i18n.pathPrefix : "").split("/").filter(Boolean);
453
+ let prefix = segments.length > 0 ? `/${segments.join("/")}` : "";
454
+ if (prefix === "" || pathname === prefix || pathname.startsWith(`${prefix}/`)) return pathname;
455
+ return pathname === "/" ? prefix : `${prefix}${pathname}`;
611
456
  }
612
457
  function getPathnameFromContext(context) {
613
- if (context?.pathname) {
614
- return withPathPrefix(context.pathname, context.i18n);
615
- }
616
- if (context?.url) {
617
- let url = toUrl(context.url);
618
- return withPathPrefix(url.pathname || "/", context.i18n);
619
- }
620
- return "/";
458
+ if (context?.pathname) return withPathPrefix(context.pathname, context.i18n);
459
+ if (context?.url) return withPathPrefix(toUrl(context.url).pathname || "/", context.i18n);
460
+ return "/";
621
461
  }
622
462
  function coerceQueryValue(value) {
623
- if (value === "true") {
624
- return true;
625
- }
626
- if (value === "false") {
627
- return false;
628
- }
629
- return value;
463
+ if (value === "true") return true;
464
+ if (value === "false") return false;
465
+ return value;
630
466
  }
631
467
  function toQueryRecord(searchParams) {
632
- let queries = {};
633
- for (let [key, value] of searchParams.entries()) {
634
- queries[key] = coerceQueryValue(value);
635
- }
636
- return queries;
468
+ let queries = {};
469
+ for (let [key, value] of searchParams.entries()) queries[key] = coerceQueryValue(value);
470
+ return queries;
637
471
  }
638
- var TRANSIENT_STUDIO_PARAMS = /* @__PURE__ */ new Set([
639
- "weaverseDraftItem",
640
- // Legacy name from the original design-mode draft-item spike. Keep it out of
641
- // runtime requestInfo too, in case an older Builder bundle is in front of a
642
- // newer Next storefront.
643
- "__weaverseDraftItem"
644
- ]);
472
+ const TRANSIENT_STUDIO_PARAMS = new Set(["weaverseDraftItem", "__weaverseDraftItem"]);
645
473
  function getRequestInfoSearchParams(context) {
646
- let searchParams = new URLSearchParams(getSearchParamsFromContext(context));
647
- for (let key of TRANSIENT_STUDIO_PARAMS) {
648
- searchParams.delete(key);
649
- }
650
- return searchParams;
474
+ let searchParams = new URLSearchParams(getSearchParamsFromContext(context));
475
+ for (let key of TRANSIENT_STUDIO_PARAMS) searchParams.delete(key);
476
+ return searchParams;
651
477
  }
652
478
  function buildWeaverseNextRequestInfo(context) {
653
- let searchParams = getRequestInfoSearchParams(context);
654
- let search = searchParams.toString();
655
- return {
656
- pathname: getPathnameFromContext(context),
657
- search: search ? `?${search}` : "",
658
- queries: toQueryRecord(searchParams),
659
- ...context?.i18n ? { i18n: context.i18n } : {},
660
- ...context?.pageType ? { pageType: context.pageType } : {},
661
- ...context?.handle ? { handle: context.handle } : {}
662
- };
663
- }
664
-
665
- // src/runtime.ts
479
+ let searchParams = getRequestInfoSearchParams(context);
480
+ let search = searchParams.toString();
481
+ return {
482
+ pathname: getPathnameFromContext(context),
483
+ search: search ? `?${search}` : "",
484
+ queries: toQueryRecord(searchParams),
485
+ ...context?.i18n ? { i18n: context.i18n } : {},
486
+ ...context?.pageType ? { pageType: context.pageType } : {},
487
+ ...context?.handle ? { handle: context.handle } : {}
488
+ };
489
+ }
490
+ //#endregion
491
+ //#region src/runtime.ts
666
492
  function getRuntimeWindow() {
667
- return typeof window === "undefined" ? void 0 : window;
493
+ return typeof window === "undefined" ? void 0 : window;
668
494
  }
669
- function getRenderablePage(data) {
670
- let page = data.page;
671
- let rootId = page.rootId ?? page.items.find((item) => item.type === "main")?.id ?? page.items[0]?.id ?? page.id;
672
- return { ...page, rootId };
495
+ function getRenderablePage$1(data) {
496
+ let page = data.page;
497
+ let rootId = page.rootId ?? page.items.find((item) => item.type === "main")?.id ?? page.items[0]?.id ?? page.id;
498
+ return {
499
+ ...page,
500
+ rootId
501
+ };
673
502
  }
674
503
  function getConfigString(configs, key) {
675
- let value = configs?.[key];
676
- return typeof value === "string" ? value : void 0;
504
+ let value = configs?.[key];
505
+ return typeof value === "string" ? value : void 0;
677
506
  }
678
507
  function resolveModeFlag(config, key) {
679
- return config.client?.requestContext?.[key] === true || config.data.configs?.[key] === true;
508
+ return config.client?.requestContext?.[key] === true || config.data.configs?.[key] === true;
680
509
  }
681
510
  function resolveSectionType(config) {
682
- return config.client?.requestContext?.sectionType || getConfigString(config.data.configs, "sectionType") || void 0;
511
+ return config.client?.requestContext?.sectionType || getConfigString(config.data.configs, "sectionType") || void 0;
683
512
  }
684
513
  function getRecordString(record, key) {
685
- let value = record?.[key];
686
- return typeof value === "string" ? value : void 0;
514
+ let value = record?.[key];
515
+ return typeof value === "string" ? value : void 0;
687
516
  }
688
517
  function resolveProjectId(client, data, fallback) {
689
- let projectId = client?.projectId;
690
- if (projectId) {
691
- return projectId;
692
- }
693
- let configProjectId = getConfigString(data.configs, "projectId");
694
- if (configProjectId) {
695
- return configProjectId;
696
- }
697
- return getRecordString(data.project, "id") ?? fallback;
518
+ let projectId = client?.projectId;
519
+ if (projectId) return projectId;
520
+ let configProjectId = getConfigString(data.configs, "projectId");
521
+ if (configProjectId) return configProjectId;
522
+ return getRecordString(data.project, "id") ?? fallback;
698
523
  }
699
524
  function resolveDataContext(config) {
700
- if (config.dataContext) {
701
- return config.dataContext;
702
- }
703
- if (config.client?.dataContext) {
704
- return config.client.dataContext;
705
- }
706
- return {};
525
+ if (config.dataContext) return config.dataContext;
526
+ if (config.client?.dataContext) return config.client.dataContext;
527
+ return {};
707
528
  }
708
529
  function getRuntimeKey(pageId, requestInfo) {
709
- return `${pageId}:${requestInfo.pathname}:${requestInfo.search}`;
530
+ return `${pageId}:${requestInfo.pathname}:${requestInfo.search}`;
710
531
  }
711
532
  function registerRuntime(runtime) {
712
- let runtimeWindow = getRuntimeWindow();
713
- if (!runtimeWindow) {
714
- return;
715
- }
716
- runtimeWindow.__weaverses ??= {};
717
- runtimeWindow.__weaverses[runtime.pageId] = runtime;
718
- runtimeWindow.__weaverse = runtime;
533
+ let runtimeWindow = getRuntimeWindow();
534
+ if (!runtimeWindow) return;
535
+ runtimeWindow.__weaverses ??= {};
536
+ runtimeWindow.__weaverses[runtime.pageId] = runtime;
537
+ runtimeWindow.__weaverse = runtime;
719
538
  }
720
539
  function rebindPageItemsToRuntime(runtime) {
721
- let items = runtime.data?.items;
722
- if (!items) {
723
- return;
724
- }
725
- for (let { id } of items) {
726
- let instance = runtime.itemInstances.get(id);
727
- if (instance && instance.weaverse !== runtime) {
728
- instance.weaverse = runtime;
729
- }
730
- }
731
- }
732
- var WeaverseNextRuntime = class extends Weaverse3 {
733
- /** Stable ID of the page owned by this runtime. */
734
- pageId;
735
- /** Mutable callbacks and stores consumed by the Studio bridge. */
736
- internal;
737
- /** Path, query, and locale metadata for Studio navigation. */
738
- requestInfo;
739
- /** Whether this runtime renders a component preview. */
740
- isPreviewMode;
741
- /** Whether this runtime renders a saved revision. */
742
- isRevisionPreview;
743
- /** Component type rendered in section preview mode. */
744
- sectionType;
745
- // ─── Item-level translation sidecar (design mode only) ─────────────
746
- /**
747
- * Translation map received from Builder in design mode, keyed by item ID.
748
- * `WeaverseNextItem.getSnapShot()` overlays these onto the data handed to
749
- * components, so translations render without mutating the base `_store`.
750
- */
751
- translationMap = {};
752
- /** Locale associated with the item-level translation sidecar. */
753
- translationLocale = String();
754
- /** Weaverse language ID used when saving translation changes. */
755
- translationLanguageId = String();
756
- /**
757
- * Fresh page data captured while React was rendering. Runtime reuse happens
758
- * inside the renderer's render phase (`useMemo`), where applying it through
759
- * `setProjectData()` would emit item updates to `useSyncExternalStore`
760
- * subscribers mid-render. The renderer applies it post-commit via
761
- * `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
762
- * Studio tree owns the page data there.
763
- */
764
- pendingProjectData;
765
- /**
766
- * Reused item instances whose data was refreshed while this runtime was
767
- * constructed during render (core `initProject()` calls `setData()` on
768
- * them). Their data is already fresh; only the subscriber notification was
769
- * deferred to `flushRenderPhaseUpdates()`.
770
- */
771
- pendingItemUpdates = [];
772
- /** Create a browser runtime from a loaded page and its request context. */
773
- constructor(config) {
774
- let { client, data } = config;
775
- let page = getRenderablePage(data);
776
- let configs = data.configs;
777
- let requestContext = client?.requestContext;
778
- let isDesignMode = resolveModeFlag(config, "isDesignMode");
779
- let isPreviewMode = resolveModeFlag(config, "isPreviewMode");
780
- let isRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
781
- let sectionType = resolveSectionType(config);
782
- let projectId = resolveProjectId(client, data, page.id);
783
- ensureNextItemConstructor();
784
- super({
785
- projectId,
786
- data: page,
787
- isDesignMode,
788
- weaverseHost: getConfigString(configs, "weaverseHost"),
789
- weaverseVersion: getConfigString(configs, "weaverseVersion")
790
- });
791
- this.pageId = page.id;
792
- this.dataContext = resolveDataContext(config);
793
- this.requestInfo = buildWeaverseNextRequestInfo(requestContext);
794
- this.isDesignMode = isDesignMode;
795
- this.isPreviewMode = isPreviewMode;
796
- this.isRevisionPreview = isRevisionPreview;
797
- this.sectionType = sectionType;
798
- let translationStore = config.translationStore ?? new TranslationStore();
799
- this.internal = {
800
- merchantOverrides: config.merchantOverrides,
801
- navigate: config.navigate,
802
- pageAssignment: data.pageAssignment,
803
- project: data.project,
804
- revalidate: config.revalidate,
805
- themeSettingsStore: config.themeSettingsStore ?? createWeaverseNextThemeSettingsStore({
806
- schema: client?.themeSchema,
807
- settings: client?.themeSettings
808
- }),
809
- translationStore,
810
- themeTextStore: translationStore
811
- };
812
- this.extractTranslationSidecar();
813
- }
814
- /**
815
- * Pull `translationMap` / `translationLocale` / `translationLanguageId` off
816
- * the current page data (Builder attaches them in design mode). Unlike
817
- * Hydrogen, this also clears the sidecar to defaults when the new page data
818
- * carries none, so a reused runtime / project-data swap can't leave a stale
819
- * map overlaying the fresh tree.
820
- */
821
- extractTranslationSidecar = () => {
822
- let pageData = this.data;
823
- let translationMap = pageData?.translationMap;
824
- if (translationMap) {
825
- this.translationMap = translationMap;
826
- this.translationLocale = pageData?.translationLocale || "";
827
- this.translationLanguageId = pageData?.translationLanguageId || "";
828
- } else {
829
- this.translationMap = {};
830
- this.translationLocale = "";
831
- this.translationLanguageId = "";
832
- }
833
- };
834
- /**
835
- * Replace the translation sidecar (Builder pushes this when translation data
836
- * arrives or the active language changes) and refresh every item so their
837
- * merged snapshots recompute.
838
- */
839
- setTranslationSidecar = (map = {}, locale = "", languageId = "") => {
840
- this.translationMap = map;
841
- this.translationLocale = locale;
842
- this.translationLanguageId = languageId;
843
- this.refreshAllItems();
844
- };
845
- /**
846
- * Update a single translatable field for one item. Assigns a new per-item
847
- * entry object so `WeaverseNextItem.getSnapShot()`'s translation-ref cache
848
- * invalidates, then triggers only that item's subscribers.
849
- */
850
- updateTranslation = (itemId, key, originalValue, translatedValue) => {
851
- if (!this.translationMap[itemId]) {
852
- this.translationMap[itemId] = {};
853
- }
854
- this.translationMap[itemId] = {
855
- ...this.translationMap[itemId],
856
- [key]: { originalValue, translatedValue }
857
- };
858
- let instance = this.itemInstances.get(itemId);
859
- if (instance) {
860
- instance.triggerUpdate();
861
- }
862
- };
863
- /**
864
- * Collect translation changes for the save flow. Returns `undefined` unless
865
- * both the locale and language ID are set and at least one entry exists;
866
- * each entry key is namespaced as `data.<field>` to match Builder.
867
- */
868
- getTranslationChanges = () => {
869
- let languageId = this.translationLanguageId;
870
- if (!(this.translationLocale && languageId)) {
871
- return;
872
- }
873
- let entries = [];
874
- for (let [itemId, fields] of Object.entries(this.translationMap)) {
875
- for (let [key, entry] of Object.entries(fields)) {
876
- entries.push({
877
- itemId,
878
- key: `data.${key}`,
879
- originalValue: entry.originalValue,
880
- translatedValue: entry.translatedValue
881
- });
882
- }
883
- }
884
- if (entries.length === 0) {
885
- return;
886
- }
887
- return { languageId, entries };
888
- };
889
- /**
890
- * Re-extract the translation sidecar whenever project data is replaced (route
891
- * change / non-design reuse), before rebuilding item stores. Takes the
892
- * renderable page shape (`rootId` resolved) that `getRenderablePage()` and
893
- * the reuse branch pass in.
894
- */
895
- setProjectData = (data) => {
896
- this.data = data;
897
- this.extractTranslationSidecar();
898
- this.initProject();
899
- };
900
- /**
901
- * Apply updates deferred off the render phase: swap in any pending page data
902
- * captured on runtime reuse, then notify items whose data was refreshed
903
- * during construction. The renderer calls this from a layout effect right
904
- * after commit, so subscribers re-render before paint (no content flash) and
905
- * without React's setState-in-render warning.
906
- */
907
- flushRenderPhaseUpdates = () => {
908
- let pendingData = this.pendingProjectData;
909
- if (pendingData) {
910
- this.pendingProjectData = void 0;
911
- this.setProjectData(pendingData);
912
- }
913
- let pendingItems = this.pendingItemUpdates;
914
- if (pendingItems.length > 0) {
915
- this.pendingItemUpdates = [];
916
- for (let item of pendingItems) {
917
- item.triggerUpdate();
918
- }
919
- }
920
- };
540
+ let items = runtime.data?.items;
541
+ if (!items) return;
542
+ for (let { id } of items) {
543
+ let instance = runtime.itemInstances.get(id);
544
+ if (instance && instance.weaverse !== runtime) instance.weaverse = runtime;
545
+ }
546
+ }
547
+ var WeaverseNextRuntime = class extends Weaverse {
548
+ pageId;
549
+ internal;
550
+ requestInfo;
551
+ isPreviewMode;
552
+ isRevisionPreview;
553
+ sectionType;
554
+ translationMap = {};
555
+ translationLocale = String();
556
+ translationLanguageId = String();
557
+ pendingProjectData;
558
+ pendingItemUpdates = [];
559
+ constructor(config) {
560
+ let { client, data } = config;
561
+ let page = getRenderablePage$1(data);
562
+ let configs = data.configs;
563
+ let requestContext = client?.requestContext;
564
+ let isDesignMode = resolveModeFlag(config, "isDesignMode");
565
+ let isPreviewMode = resolveModeFlag(config, "isPreviewMode");
566
+ let isRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
567
+ let sectionType = resolveSectionType(config);
568
+ let projectId = resolveProjectId(client, data, page.id);
569
+ ensureNextItemConstructor();
570
+ super({
571
+ projectId,
572
+ data: page,
573
+ isDesignMode,
574
+ weaverseHost: getConfigString(configs, "weaverseHost"),
575
+ weaverseVersion: getConfigString(configs, "weaverseVersion")
576
+ });
577
+ this.pageId = page.id;
578
+ this.dataContext = resolveDataContext(config);
579
+ this.requestInfo = buildWeaverseNextRequestInfo(requestContext);
580
+ this.isDesignMode = isDesignMode;
581
+ this.isPreviewMode = isPreviewMode;
582
+ this.isRevisionPreview = isRevisionPreview;
583
+ this.sectionType = sectionType;
584
+ let translationStore = config.translationStore ?? new TranslationStore();
585
+ this.internal = {
586
+ merchantOverrides: config.merchantOverrides,
587
+ navigate: config.navigate,
588
+ pageAssignment: data.pageAssignment,
589
+ project: data.project,
590
+ revalidate: config.revalidate,
591
+ themeSettingsStore: config.themeSettingsStore ?? createWeaverseNextThemeSettingsStore({
592
+ schema: client?.themeSchema,
593
+ settings: client?.themeSettings
594
+ }),
595
+ translationStore,
596
+ themeTextStore: translationStore
597
+ };
598
+ this.extractTranslationSidecar();
599
+ }
600
+ extractTranslationSidecar = () => {
601
+ let pageData = this.data;
602
+ let translationMap = pageData?.translationMap;
603
+ if (translationMap) {
604
+ this.translationMap = translationMap;
605
+ this.translationLocale = pageData?.translationLocale || "";
606
+ this.translationLanguageId = pageData?.translationLanguageId || "";
607
+ } else {
608
+ this.translationMap = {};
609
+ this.translationLocale = "";
610
+ this.translationLanguageId = "";
611
+ }
612
+ };
613
+ setTranslationSidecar = (map = {}, locale = "", languageId = "") => {
614
+ this.translationMap = map;
615
+ this.translationLocale = locale;
616
+ this.translationLanguageId = languageId;
617
+ this.refreshAllItems();
618
+ };
619
+ updateTranslation = (itemId, key, originalValue, translatedValue) => {
620
+ if (!this.translationMap[itemId]) this.translationMap[itemId] = {};
621
+ this.translationMap[itemId] = {
622
+ ...this.translationMap[itemId],
623
+ [key]: {
624
+ originalValue,
625
+ translatedValue
626
+ }
627
+ };
628
+ let instance = this.itemInstances.get(itemId);
629
+ if (instance) instance.triggerUpdate();
630
+ };
631
+ getTranslationChanges = () => {
632
+ let languageId = this.translationLanguageId;
633
+ if (!(this.translationLocale && languageId)) return;
634
+ let entries = [];
635
+ for (let [itemId, fields] of Object.entries(this.translationMap)) for (let [key, entry] of Object.entries(fields)) entries.push({
636
+ itemId,
637
+ key: `data.${key}`,
638
+ originalValue: entry.originalValue,
639
+ translatedValue: entry.translatedValue
640
+ });
641
+ if (entries.length === 0) return;
642
+ return {
643
+ languageId,
644
+ entries
645
+ };
646
+ };
647
+ setProjectData = (data) => {
648
+ this.data = data;
649
+ this.extractTranslationSidecar();
650
+ this.initProject();
651
+ };
652
+ flushRenderPhaseUpdates = () => {
653
+ let pendingData = this.pendingProjectData;
654
+ if (pendingData) {
655
+ this.pendingProjectData = void 0;
656
+ this.setProjectData(pendingData);
657
+ }
658
+ let pendingItems = this.pendingItemUpdates;
659
+ if (pendingItems.length > 0) {
660
+ this.pendingItemUpdates = [];
661
+ for (let item of pendingItems) item.triggerUpdate();
662
+ }
663
+ };
921
664
  };
922
665
  function createWeaverseNextRuntime(config) {
923
- let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
924
- let page = getRenderablePage(config.data);
925
- let runtimeWindow = getRuntimeWindow();
926
- let existing = runtimeWindow?.__weaverses?.[page.id];
927
- let requestKey = getRuntimeKey(page.id, requestInfo);
928
- if (existing?.__weaverseNextRequestKey === requestKey) {
929
- let configs = config.data.configs;
930
- let nextIsDesignMode = resolveModeFlag(config, "isDesignMode");
931
- let nextIsPreviewMode = resolveModeFlag(config, "isPreviewMode");
932
- let nextIsRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
933
- let nextSectionType = resolveSectionType(config);
934
- if (existing.isDesignMode || nextIsDesignMode) {
935
- existing.pendingProjectData = void 0;
936
- } else {
937
- existing.pendingProjectData = page;
938
- }
939
- existing.__weaverseNextLatestData = page;
940
- existing.dataContext = resolveDataContext(config);
941
- existing.requestInfo = requestInfo;
942
- existing.projectId = resolveProjectId(config.client, config.data, page.id);
943
- existing.isDesignMode = nextIsDesignMode;
944
- existing.isPreviewMode = nextIsPreviewMode;
945
- existing.isRevisionPreview = nextIsRevisionPreview;
946
- existing.sectionType = nextSectionType;
947
- existing.weaverseHost = getConfigString(configs, "weaverseHost") ?? existing.weaverseHost;
948
- existing.weaverseVersion = getConfigString(configs, "weaverseVersion") ?? existing.weaverseVersion;
949
- existing.internal.pageAssignment = config.data.pageAssignment;
950
- existing.internal.project = config.data.project;
951
- if (config.navigate) {
952
- existing.internal.navigate = config.navigate;
953
- }
954
- if (config.revalidate) {
955
- existing.internal.revalidate = config.revalidate;
956
- }
957
- if (config.themeSettingsStore) {
958
- existing.internal.themeSettingsStore = config.themeSettingsStore;
959
- }
960
- if (config.translationStore) {
961
- existing.internal.translationStore = config.translationStore;
962
- existing.internal.themeTextStore = config.translationStore;
963
- }
964
- existing.internal.merchantOverrides = config.merchantOverrides;
965
- registerRuntime(existing);
966
- return existing;
967
- }
968
- let [runtime, refreshedItems] = collectDeferredItemUpdates(
969
- () => new WeaverseNextRuntime(config)
970
- );
971
- runtime.pendingItemUpdates = refreshedItems;
972
- rebindPageItemsToRuntime(runtime);
973
- runtime.__weaverseNextRequestKey = requestKey;
974
- runtime.__weaverseNextLatestData = page;
975
- registerRuntime(runtime);
976
- return runtime;
666
+ let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
667
+ let page = getRenderablePage$1(config.data);
668
+ let existing = getRuntimeWindow()?.__weaverses?.[page.id];
669
+ let requestKey = getRuntimeKey(page.id, requestInfo);
670
+ if (existing?.__weaverseNextRequestKey === requestKey) {
671
+ let configs = config.data.configs;
672
+ let nextIsDesignMode = resolveModeFlag(config, "isDesignMode");
673
+ let nextIsPreviewMode = resolveModeFlag(config, "isPreviewMode");
674
+ let nextIsRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
675
+ let nextSectionType = resolveSectionType(config);
676
+ if (existing.isDesignMode || nextIsDesignMode) existing.pendingProjectData = void 0;
677
+ else existing.pendingProjectData = page;
678
+ existing.__weaverseNextLatestData = page;
679
+ existing.dataContext = resolveDataContext(config);
680
+ existing.requestInfo = requestInfo;
681
+ existing.projectId = resolveProjectId(config.client, config.data, page.id);
682
+ existing.isDesignMode = nextIsDesignMode;
683
+ existing.isPreviewMode = nextIsPreviewMode;
684
+ existing.isRevisionPreview = nextIsRevisionPreview;
685
+ existing.sectionType = nextSectionType;
686
+ existing.weaverseHost = getConfigString(configs, "weaverseHost") ?? existing.weaverseHost;
687
+ existing.weaverseVersion = getConfigString(configs, "weaverseVersion") ?? existing.weaverseVersion;
688
+ existing.internal.pageAssignment = config.data.pageAssignment;
689
+ existing.internal.project = config.data.project;
690
+ if (config.navigate) existing.internal.navigate = config.navigate;
691
+ if (config.revalidate) existing.internal.revalidate = config.revalidate;
692
+ if (config.themeSettingsStore) existing.internal.themeSettingsStore = config.themeSettingsStore;
693
+ if (config.translationStore) {
694
+ existing.internal.translationStore = config.translationStore;
695
+ existing.internal.themeTextStore = config.translationStore;
696
+ }
697
+ existing.internal.merchantOverrides = config.merchantOverrides;
698
+ registerRuntime(existing);
699
+ return existing;
700
+ }
701
+ let [runtime, refreshedItems] = collectDeferredItemUpdates(() => new WeaverseNextRuntime(config));
702
+ runtime.pendingItemUpdates = refreshedItems;
703
+ rebindPageItemsToRuntime(runtime);
704
+ runtime.__weaverseNextRequestKey = requestKey;
705
+ runtime.__weaverseNextLatestData = page;
706
+ registerRuntime(runtime);
707
+ return runtime;
977
708
  }
978
709
  function bindWeaverseNextStudioRuntime(runtime) {
979
- if (!runtime.isDesignMode) {
980
- return false;
981
- }
982
- let studio = getRuntimeWindow()?.weaverseStudio;
983
- if (!studio) {
984
- return false;
985
- }
986
- let boundRuntime = runtime;
987
- let activeRuntime = studio.weaverse;
988
- let activeRequestInfo = activeRuntime?.requestInfo;
989
- let isActiveUrl = !activeRequestInfo || activeRequestInfo.pathname === runtime.requestInfo.pathname && activeRequestInfo.search === runtime.requestInfo.search;
990
- if (!(boundRuntime.__weaverseNextStudioBound && isActiveUrl)) {
991
- studio.init?.(runtime);
992
- boundRuntime.__weaverseNextStudioBound = true;
993
- return true;
994
- }
995
- studio.refreshStudio?.({
996
- data: boundRuntime.__weaverseNextLatestData ?? runtime.data,
997
- pageId: runtime.pageId,
998
- requestInfo: runtime.requestInfo
999
- });
1000
- return true;
1001
- }
1002
-
1003
- // src/use-weaverse-next-studio.tsx
1004
- import { useRouter } from "next/navigation";
1005
- import { useRef as useRef4 } from "react";
1006
-
1007
- // src/revalidate-item.ts
1008
- import { PageTypeSchema } from "@weaverse/schema";
1009
- var DEFAULT_REVALIDATE_ENDPOINT = "/api/weaverse/revalidate";
1010
- var MAX_ROUTE_CONTEXT_HANDLE_LENGTH = 512;
1011
- var DENIED_ROUTE_CONTEXT_PARAMS = [
1012
- "weaverseprojectid",
1013
- "weaversehost",
1014
- "weaverseapikey",
1015
- "weaverseapibase",
1016
- "weaversepublicapibase",
1017
- "weaverseversion",
1018
- "projectid",
1019
- "weaversedraftitem",
1020
- "__weaversedraftitem",
1021
- "_rsc"
710
+ if (!runtime.isDesignMode) return false;
711
+ let studio = getRuntimeWindow()?.weaverseStudio;
712
+ if (!studio) return false;
713
+ let boundRuntime = runtime;
714
+ let activeRequestInfo = studio.weaverse?.requestInfo;
715
+ let isActiveUrl = !activeRequestInfo || activeRequestInfo.pathname === runtime.requestInfo.pathname && activeRequestInfo.search === runtime.requestInfo.search;
716
+ if (!(boundRuntime.__weaverseNextStudioBound && isActiveUrl)) {
717
+ studio.init?.(runtime);
718
+ boundRuntime.__weaverseNextStudioBound = true;
719
+ return true;
720
+ }
721
+ studio.refreshStudio?.({
722
+ data: boundRuntime.__weaverseNextLatestData ?? runtime.data,
723
+ pageId: runtime.pageId,
724
+ requestInfo: runtime.requestInfo
725
+ });
726
+ return true;
727
+ }
728
+ //#endregion
729
+ //#region src/revalidate-item.ts
730
+ const DEFAULT_REVALIDATE_ENDPOINT = "/api/weaverse/revalidate";
731
+ const MAX_ROUTE_CONTEXT_HANDLE_LENGTH = 512;
732
+ const DENIED_ROUTE_CONTEXT_PARAMS = [
733
+ "weaverseprojectid",
734
+ "weaversehost",
735
+ "weaverseapikey",
736
+ "weaverseapibase",
737
+ "weaversepublicapibase",
738
+ "weaverseversion",
739
+ "projectid",
740
+ "weaversedraftitem",
741
+ "__weaversedraftitem",
742
+ "_rsc"
1022
743
  ];
1023
- var ROUTE_CONTEXT_I18N_KEYS = [
1024
- "country",
1025
- "label",
1026
- "language",
1027
- "locale",
1028
- "pathPrefix"
744
+ const ROUTE_CONTEXT_I18N_KEYS = [
745
+ "country",
746
+ "label",
747
+ "language",
748
+ "locale",
749
+ "pathPrefix"
1029
750
  ];
1030
751
  function sanitizeRouteContextSearch(search) {
1031
- let params = new URLSearchParams(search);
1032
- let denied = new Set(DENIED_ROUTE_CONTEXT_PARAMS);
1033
- for (let key of [...new Set(params.keys())]) {
1034
- if (denied.has(key.toLowerCase())) {
1035
- params.delete(key);
1036
- }
1037
- }
1038
- let serialized = params.toString();
1039
- return serialized ? `?${serialized}` : "";
752
+ let params = new URLSearchParams(search);
753
+ let denied = new Set(DENIED_ROUTE_CONTEXT_PARAMS);
754
+ for (let key of [...new Set(params.keys())]) if (denied.has(key.toLowerCase())) params.delete(key);
755
+ let serialized = params.toString();
756
+ return serialized ? `?${serialized}` : "";
1040
757
  }
1041
758
  function buildWeaverseNextRevalidateRouteContext(requestInfo) {
1042
- if (!requestInfo || typeof requestInfo.pathname !== "string" || !requestInfo.pathname) {
1043
- return;
1044
- }
1045
- let routeContext = {
1046
- pathname: requestInfo.pathname,
1047
- search: sanitizeRouteContextSearch(requestInfo.search ?? "")
1048
- };
1049
- let { i18n } = requestInfo;
1050
- if (i18n && typeof i18n === "object") {
1051
- let picked = {};
1052
- for (let key of ROUTE_CONTEXT_I18N_KEYS) {
1053
- let value = i18n[key];
1054
- if (typeof value === "string") {
1055
- picked[key] = value;
1056
- }
1057
- }
1058
- if (Object.keys(picked).length) {
1059
- routeContext.i18n = picked;
1060
- }
1061
- }
1062
- if (requestInfo.pageType && PageTypeSchema.safeParse(requestInfo.pageType).success) {
1063
- routeContext.pageType = requestInfo.pageType;
1064
- }
1065
- if (typeof requestInfo.handle === "string" && requestInfo.handle && requestInfo.handle.length <= MAX_ROUTE_CONTEXT_HANDLE_LENGTH) {
1066
- routeContext.handle = requestInfo.handle;
1067
- }
1068
- return routeContext;
759
+ if (!requestInfo || typeof requestInfo.pathname !== "string" || !requestInfo.pathname) return;
760
+ let routeContext = {
761
+ pathname: requestInfo.pathname,
762
+ search: sanitizeRouteContextSearch(requestInfo.search ?? "")
763
+ };
764
+ let { i18n } = requestInfo;
765
+ if (i18n && typeof i18n === "object") {
766
+ let picked = {};
767
+ for (let key of ROUTE_CONTEXT_I18N_KEYS) {
768
+ let value = i18n[key];
769
+ if (typeof value === "string") picked[key] = value;
770
+ }
771
+ if (Object.keys(picked).length) routeContext.i18n = picked;
772
+ }
773
+ if (requestInfo.pageType && PageTypeSchema.safeParse(requestInfo.pageType).success) routeContext.pageType = requestInfo.pageType;
774
+ if (typeof requestInfo.handle === "string" && requestInfo.handle && requestInfo.handle.length <= MAX_ROUTE_CONTEXT_HANDLE_LENGTH) routeContext.handle = requestInfo.handle;
775
+ return routeContext;
1069
776
  }
1070
777
  async function revalidateWeaverseNextItem(runtime, draftItem, endpoint = DEFAULT_REVALIDATE_ENDPOINT) {
1071
- let instance = runtime.itemInstances.get(draftItem.id);
1072
- if (!instance) {
1073
- throw new Error(
1074
- `[weaverse-next] No live item instance for "${draftItem.id}".`
1075
- );
1076
- }
1077
- let routeContext = buildWeaverseNextRevalidateRouteContext(
1078
- runtime.requestInfo
1079
- );
1080
- let body = routeContext ? { draftItem, routeContext } : { draftItem };
1081
- let response = await fetch(endpoint, {
1082
- method: "POST",
1083
- headers: { "Content-Type": "application/json" },
1084
- body: JSON.stringify(body)
1085
- });
1086
- if (!response.ok) {
1087
- throw new Error(
1088
- `[weaverse-next] Revalidate endpoint responded ${response.status}.`
1089
- );
1090
- }
1091
- let { loaderData } = await response.json();
1092
- instance.setData({ loaderData: loaderData ?? null });
1093
- }
1094
-
1095
- // src/studio-bridge.tsx
1096
- import { useEffect as useEffect3, useRef as useRef3 } from "react";
1097
- var STUDIO_BIND_RETRY_INTERVAL_MS = 50;
1098
- var STUDIO_BIND_MAX_ATTEMPTS = 100;
778
+ let instance = runtime.itemInstances.get(draftItem.id);
779
+ if (!instance) throw new Error(`[weaverse-next] No live item instance for "${draftItem.id}".`);
780
+ let routeContext = buildWeaverseNextRevalidateRouteContext(runtime.requestInfo);
781
+ let response = await fetch(endpoint, {
782
+ method: "POST",
783
+ headers: { "Content-Type": "application/json" },
784
+ body: JSON.stringify(routeContext ? {
785
+ draftItem,
786
+ routeContext
787
+ } : { draftItem })
788
+ });
789
+ if (!response.ok) throw new Error(`[weaverse-next] Revalidate endpoint responded ${response.status}.`);
790
+ let { loaderData } = await response.json();
791
+ instance.setData({ loaderData: loaderData ?? null });
792
+ }
793
+ //#endregion
794
+ //#region src/studio-bridge.tsx
795
+ const STUDIO_BIND_RETRY_INTERVAL_MS = 50;
796
+ const STUDIO_BIND_MAX_ATTEMPTS = 100;
1099
797
  function WeaverseNextStudioBridge(props) {
1100
- let { runtime, navigate, revalidate, revalidateItem } = props;
1101
- let lastRuntimeRef = useRef3(runtime);
1102
- let lastRuntimeDataRef = useRef3(runtime.data);
1103
- let lastRequestInfoRef = useRef3(runtime.requestInfo);
1104
- useEffect3(() => {
1105
- if (navigate) {
1106
- runtime.internal.navigate = navigate;
1107
- }
1108
- if (revalidate) {
1109
- runtime.internal.revalidate = revalidate;
1110
- }
1111
- if (revalidateItem) {
1112
- runtime.internal.revalidateItem = revalidateItem;
1113
- }
1114
- if (bindWeaverseNextStudioRuntime(runtime) || !runtime.isDesignMode) {
1115
- return;
1116
- }
1117
- let attempts = 0;
1118
- let interval = window.setInterval(() => {
1119
- attempts += 1;
1120
- if (bindWeaverseNextStudioRuntime(runtime) || attempts >= STUDIO_BIND_MAX_ATTEMPTS) {
1121
- window.clearInterval(interval);
1122
- }
1123
- }, STUDIO_BIND_RETRY_INTERVAL_MS);
1124
- return () => window.clearInterval(interval);
1125
- }, [runtime, navigate, revalidate, revalidateItem]);
1126
- useEffect3(() => {
1127
- if (lastRuntimeRef.current !== runtime) {
1128
- lastRuntimeRef.current = runtime;
1129
- lastRuntimeDataRef.current = runtime.data;
1130
- lastRequestInfoRef.current = runtime.requestInfo;
1131
- return;
1132
- }
1133
- if (lastRuntimeDataRef.current === runtime.data && lastRequestInfoRef.current === runtime.requestInfo) {
1134
- return;
1135
- }
1136
- lastRuntimeDataRef.current = runtime.data;
1137
- lastRequestInfoRef.current = runtime.requestInfo;
1138
- bindWeaverseNextStudioRuntime(runtime);
1139
- }, [runtime, runtime.data, runtime.requestInfo]);
1140
- return null;
1141
- }
1142
-
1143
- // src/studio-router.ts
798
+ let { runtime, navigate, revalidate, revalidateItem } = props;
799
+ let lastRuntimeRef = useRef(runtime);
800
+ let lastRuntimeDataRef = useRef(runtime.data);
801
+ let lastRequestInfoRef = useRef(runtime.requestInfo);
802
+ useEffect(() => {
803
+ if (navigate) runtime.internal.navigate = navigate;
804
+ if (revalidate) runtime.internal.revalidate = revalidate;
805
+ if (revalidateItem) runtime.internal.revalidateItem = revalidateItem;
806
+ if (bindWeaverseNextStudioRuntime(runtime) || !runtime.isDesignMode) return;
807
+ let attempts = 0;
808
+ let interval = window.setInterval(() => {
809
+ attempts += 1;
810
+ if (bindWeaverseNextStudioRuntime(runtime) || attempts >= STUDIO_BIND_MAX_ATTEMPTS) window.clearInterval(interval);
811
+ }, STUDIO_BIND_RETRY_INTERVAL_MS);
812
+ return () => window.clearInterval(interval);
813
+ }, [
814
+ runtime,
815
+ navigate,
816
+ revalidate,
817
+ revalidateItem
818
+ ]);
819
+ useEffect(() => {
820
+ if (lastRuntimeRef.current !== runtime) {
821
+ lastRuntimeRef.current = runtime;
822
+ lastRuntimeDataRef.current = runtime.data;
823
+ lastRequestInfoRef.current = runtime.requestInfo;
824
+ return;
825
+ }
826
+ if (lastRuntimeDataRef.current === runtime.data && lastRequestInfoRef.current === runtime.requestInfo) return;
827
+ lastRuntimeDataRef.current = runtime.data;
828
+ lastRequestInfoRef.current = runtime.requestInfo;
829
+ bindWeaverseNextStudioRuntime(runtime);
830
+ }, [
831
+ runtime,
832
+ runtime.data,
833
+ runtime.requestInfo
834
+ ]);
835
+ return null;
836
+ }
837
+ //#endregion
838
+ //#region src/studio-router.ts
1144
839
  function shouldResetScroll(options) {
1145
- if (!options || typeof options !== "object") {
1146
- return true;
1147
- }
1148
- return !options.preventScrollReset;
840
+ if (!options || typeof options !== "object") return true;
841
+ return !options.preventScrollReset;
1149
842
  }
1150
843
  function createWeaverseNextStudioInternals(router, options = {}) {
1151
- return {
1152
- navigate: (to, navigateOptions) => {
1153
- let scroll = shouldResetScroll(navigateOptions);
1154
- if (options.replace) {
1155
- router.replace(to, { scroll });
1156
- } else {
1157
- router.push(to, { scroll });
1158
- }
1159
- },
1160
- revalidate: () => {
1161
- router.refresh();
1162
- }
1163
- };
1164
- }
1165
-
1166
- // src/use-weaverse-next-studio.tsx
1167
- import { jsx as jsx5 } from "react/jsx-runtime";
844
+ return {
845
+ navigate: (to, navigateOptions) => {
846
+ let scroll = shouldResetScroll(navigateOptions);
847
+ if (options.replace) router.replace(to, { scroll });
848
+ else router.push(to, { scroll });
849
+ },
850
+ revalidate: () => {
851
+ router.refresh();
852
+ }
853
+ };
854
+ }
855
+ //#endregion
856
+ //#region src/use-weaverse-next-studio.tsx
1168
857
  function useWeaverseNextStudioInternals(options) {
1169
- let router = useRouter();
1170
- let ref = useRef4(null);
1171
- if (!ref.current || ref.current.router !== router || ref.current.replace !== options?.replace) {
1172
- ref.current = {
1173
- internals: createWeaverseNextStudioInternals(router, options),
1174
- replace: options?.replace,
1175
- router
1176
- };
1177
- }
1178
- return ref.current.internals;
858
+ let router = useRouter();
859
+ let ref = useRef(null);
860
+ if (!ref.current || ref.current.router !== router || ref.current.replace !== options?.replace) ref.current = {
861
+ internals: createWeaverseNextStudioInternals(router, options),
862
+ replace: options?.replace,
863
+ router
864
+ };
865
+ return ref.current.internals;
1179
866
  }
1180
867
  function WeaverseNextStudio(props) {
1181
- let { runtime, replace, revalidateEndpoint } = props;
1182
- let { navigate, revalidate } = useWeaverseNextStudioInternals({ replace });
1183
- let endpoint = revalidateEndpoint ?? DEFAULT_REVALIDATE_ENDPOINT;
1184
- let revalidateItemRef = useRef4(null);
1185
- if (revalidateItemRef.current?.endpoint !== endpoint || revalidateItemRef.current.runtime !== runtime) {
1186
- revalidateItemRef.current = {
1187
- endpoint,
1188
- revalidateItem: (draftItem) => revalidateWeaverseNextItem(runtime, draftItem, endpoint),
1189
- runtime
1190
- };
1191
- }
1192
- return /* @__PURE__ */ jsx5(
1193
- WeaverseNextStudioBridge,
1194
- {
1195
- navigate,
1196
- revalidate,
1197
- revalidateItem: revalidateItemRef.current.revalidateItem,
1198
- runtime
1199
- }
1200
- );
1201
- }
1202
-
1203
- // src/renderer.tsx
1204
- import { Fragment, jsx as jsx6, jsxs } from "react/jsx-runtime";
1205
- var EMPTY_DATA_CONTEXT = {};
1206
- var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect4 : useLayoutEffect;
1207
- function getRenderablePage2(data) {
1208
- let page = data?.page;
1209
- if (!page) {
1210
- return null;
1211
- }
1212
- let rootId = page.rootId ?? page.items.find((item) => item.type === "main")?.id ?? page.items[0]?.id ?? page.id;
1213
- return { ...page, rootId };
1214
- }
1215
- var WeaverseNextRenderer = memo(function WeaverseNextRendererComponent(props) {
1216
- let context = useContext4(WeaverseNextContext);
1217
- let client = props.client ?? context?.client;
1218
- let data = props.data ?? client?.data ?? null;
1219
- let dataContext = props.dataContext ?? client?.dataContext ?? EMPTY_DATA_CONTEXT;
1220
- let page = useMemo4(() => getRenderablePage2(data), [data]);
1221
- let weaverse = useMemo4(() => {
1222
- if (!page) {
1223
- return null;
1224
- }
1225
- return createWeaverseNextRuntime({
1226
- client,
1227
- data: { ...data, page },
1228
- dataContext,
1229
- merchantOverrides: context?.merchantOverrides,
1230
- themeSettingsStore: context?.themeSettingsStore,
1231
- translationStore: context?.translationStore
1232
- });
1233
- }, [
1234
- client,
1235
- page,
1236
- data,
1237
- dataContext,
1238
- context?.merchantOverrides,
1239
- context?.themeSettingsStore,
1240
- context?.translationStore
1241
- ]);
1242
- useIsomorphicLayoutEffect(() => {
1243
- weaverse?.flushRenderPhaseUpdates();
1244
- }, [weaverse]);
1245
- if (!weaverse) {
1246
- return null;
1247
- }
1248
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1249
- /* @__PURE__ */ jsx6(WeaverseRoot, { context: weaverse }),
1250
- /* @__PURE__ */ jsx6(WeaverseNextStudio, { runtime: weaverse })
1251
- ] });
868
+ let { runtime, replace, revalidateEndpoint } = props;
869
+ let { navigate, revalidate } = useWeaverseNextStudioInternals({ replace });
870
+ let endpoint = revalidateEndpoint ?? "/api/weaverse/revalidate";
871
+ let revalidateItemRef = useRef(null);
872
+ if (revalidateItemRef.current?.endpoint !== endpoint || revalidateItemRef.current.runtime !== runtime) revalidateItemRef.current = {
873
+ endpoint,
874
+ revalidateItem: (draftItem) => revalidateWeaverseNextItem(runtime, draftItem, endpoint),
875
+ runtime
876
+ };
877
+ return /* @__PURE__ */ jsx(WeaverseNextStudioBridge, {
878
+ navigate,
879
+ revalidate,
880
+ revalidateItem: revalidateItemRef.current.revalidateItem,
881
+ runtime
882
+ });
883
+ }
884
+ //#endregion
885
+ //#region src/renderer.tsx
886
+ const EMPTY_DATA_CONTEXT = {};
887
+ const useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
888
+ function getRenderablePage(data) {
889
+ let page = data?.page;
890
+ if (!page) return null;
891
+ let rootId = page.rootId ?? page.items.find((item) => item.type === "main")?.id ?? page.items[0]?.id ?? page.id;
892
+ return {
893
+ ...page,
894
+ rootId
895
+ };
896
+ }
897
+ const WeaverseNextRenderer = memo(function WeaverseNextRendererComponent(props) {
898
+ let context = useContext(WeaverseNextContext);
899
+ let client = props.client ?? context?.client;
900
+ let data = props.data ?? client?.data ?? null;
901
+ let dataContext = props.dataContext ?? client?.dataContext ?? EMPTY_DATA_CONTEXT;
902
+ let page = useMemo(() => getRenderablePage(data), [data]);
903
+ let weaverse = useMemo(() => {
904
+ if (!page) return null;
905
+ return createWeaverseNextRuntime({
906
+ client,
907
+ data: {
908
+ ...data,
909
+ page
910
+ },
911
+ dataContext,
912
+ merchantOverrides: context?.merchantOverrides,
913
+ themeSettingsStore: context?.themeSettingsStore,
914
+ translationStore: context?.translationStore
915
+ });
916
+ }, [
917
+ client,
918
+ page,
919
+ data,
920
+ dataContext,
921
+ context?.merchantOverrides,
922
+ context?.themeSettingsStore,
923
+ context?.translationStore
924
+ ]);
925
+ useIsomorphicLayoutEffect(() => {
926
+ weaverse?.flushRenderPhaseUpdates();
927
+ }, [weaverse]);
928
+ if (!weaverse) return null;
929
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(WeaverseRoot, { context: weaverse }), /* @__PURE__ */ jsx(WeaverseNextStudio, { runtime: weaverse })] });
1252
930
  });
1253
-
1254
- // src/studio-connect.tsx
1255
- import { useEffect as useEffect5 } from "react";
1256
-
1257
- // src/studio-script-src.ts
1258
- var TRUSTED_STUDIO_DOMAINS = ["weaverse.io", "weaverse.dev"];
931
+ //#endregion
932
+ //#region src/studio-script-src.ts
933
+ const TRUSTED_STUDIO_DOMAINS = ["weaverse.io", "weaverse.dev"];
1259
934
  function isLoopbackHostname(hostname) {
1260
- return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".localhost");
935
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".localhost");
1261
936
  }
1262
937
  function normalizeOrigin(value) {
1263
- if (!value) {
1264
- return null;
1265
- }
1266
- try {
1267
- return new URL(value).origin;
1268
- } catch {
1269
- return null;
1270
- }
938
+ if (!value) return null;
939
+ try {
940
+ return new URL(value).origin;
941
+ } catch {
942
+ return null;
943
+ }
1271
944
  }
1272
945
  function isTrustedStudioOrigin(origin, storefrontHostname) {
1273
- let parsed;
1274
- try {
1275
- parsed = new URL(origin);
1276
- } catch {
1277
- return false;
1278
- }
1279
- let { hostname, protocol } = parsed;
1280
- if (isLoopbackHostname(storefrontHostname) && isLoopbackHostname(hostname)) {
1281
- return protocol === "http:" || protocol === "https:";
1282
- }
1283
- if (protocol !== "https:") {
1284
- return false;
1285
- }
1286
- return TRUSTED_STUDIO_DOMAINS.some(
1287
- (domain) => hostname === domain || hostname.endsWith(`.${domain}`)
1288
- );
946
+ let parsed;
947
+ try {
948
+ parsed = new URL(origin);
949
+ } catch {
950
+ return false;
951
+ }
952
+ let { hostname, protocol } = parsed;
953
+ if (isLoopbackHostname(storefrontHostname) && isLoopbackHostname(hostname)) return protocol === "http:" || protocol === "https:";
954
+ if (protocol !== "https:") return false;
955
+ return TRUSTED_STUDIO_DOMAINS.some((domain) => hostname === domain || hostname.endsWith(`.${domain}`));
1289
956
  }
1290
957
  function toSearchParams(context) {
1291
- if (context?.searchParams) {
1292
- return new URLSearchParams(context.searchParams);
1293
- }
1294
- if (context?.url) {
1295
- let url = typeof context.url === "string" ? new URL(context.url, "http://localhost") : context.url;
1296
- return new URLSearchParams(url.searchParams);
1297
- }
1298
- return new URLSearchParams();
958
+ if (context?.searchParams) return new URLSearchParams(context.searchParams);
959
+ if (context?.url) {
960
+ let url = typeof context.url === "string" ? new URL(context.url, "http://localhost") : context.url;
961
+ return new URLSearchParams(url.searchParams);
962
+ }
963
+ return new URLSearchParams();
1299
964
  }
1300
965
  function last(searchParams, key) {
1301
- let values = searchParams.getAll(key);
1302
- return values.length ? values.at(-1) ?? null : null;
966
+ let values = searchParams.getAll(key);
967
+ return values.length ? values.at(-1) ?? null : null;
1303
968
  }
1304
969
  function resolveWeaverseNextStudioScriptSrc(context, options = {}) {
1305
- let searchParams = toSearchParams(context);
1306
- let isDesignMode = context?.isDesignMode ?? last(searchParams, "isDesignMode") === "true";
1307
- let isPreviewMode = context?.isPreviewMode ?? last(searchParams, "isPreviewMode") === "true";
1308
- let isRevisionPreview = context?.isRevisionPreview ?? Boolean(last(searchParams, "__revisionId"));
1309
- if (!(isDesignMode || isPreviewMode || isRevisionPreview)) {
1310
- return null;
1311
- }
1312
- let origin = normalizeOrigin(last(searchParams, "weaverseHost"));
1313
- if (!origin) {
1314
- return null;
1315
- }
1316
- let storefrontHostname = options.storefrontHostname ?? "";
1317
- if (!isTrustedStudioOrigin(origin, storefrontHostname)) {
1318
- return null;
1319
- }
1320
- let bundle = isPreviewMode || isRevisionPreview ? "preview.js" : "index.js";
1321
- let version = last(searchParams, "weaverseVersion");
1322
- let url = `${origin}/static/studio/next/${bundle}`;
1323
- return version ? `${url}?v=${encodeURIComponent(version)}` : url;
1324
- }
1325
-
1326
- // src/studio-connect.tsx
1327
- var loadedScriptSrcs = /* @__PURE__ */ new Set();
970
+ let searchParams = toSearchParams(context);
971
+ let isDesignMode = context?.isDesignMode ?? last(searchParams, "isDesignMode") === "true";
972
+ let isPreviewMode = context?.isPreviewMode ?? last(searchParams, "isPreviewMode") === "true";
973
+ let isRevisionPreview = context?.isRevisionPreview ?? Boolean(last(searchParams, "__revisionId"));
974
+ if (!(isDesignMode || isPreviewMode || isRevisionPreview)) return null;
975
+ let origin = normalizeOrigin(last(searchParams, "weaverseHost"));
976
+ if (!origin) return null;
977
+ if (!isTrustedStudioOrigin(origin, options.storefrontHostname ?? "")) return null;
978
+ let bundle = isPreviewMode || isRevisionPreview ? "preview.js" : "index.js";
979
+ let version = last(searchParams, "weaverseVersion");
980
+ let url = `${origin}/static/studio/next/${bundle}`;
981
+ return version ? `${url}?v=${encodeURIComponent(version)}` : url;
982
+ }
983
+ //#endregion
984
+ //#region src/studio-connect.tsx
985
+ const loadedScriptSrcs = /* @__PURE__ */ new Set();
1328
986
  function loadScript(src) {
1329
- if (typeof document === "undefined") {
1330
- return;
1331
- }
1332
- if (loadedScriptSrcs.has(src)) {
1333
- return;
1334
- }
1335
- let existing = document.querySelector(`script[src="${src}"]`);
1336
- if (existing) {
1337
- loadedScriptSrcs.add(src);
1338
- return;
1339
- }
1340
- let script = document.createElement("script");
1341
- script.async = true;
1342
- script.src = src;
1343
- document.head.appendChild(script);
1344
- loadedScriptSrcs.add(src);
987
+ if (typeof document === "undefined") return;
988
+ if (loadedScriptSrcs.has(src)) return;
989
+ if (document.querySelector(`script[src="${src}"]`)) {
990
+ loadedScriptSrcs.add(src);
991
+ return;
992
+ }
993
+ let script = document.createElement("script");
994
+ script.async = true;
995
+ script.src = src;
996
+ document.head.appendChild(script);
997
+ loadedScriptSrcs.add(src);
1345
998
  }
1346
999
  function loadWeaverseNextStudioScript(context, options = {}) {
1347
- let resolvedContext = context;
1348
- if (!resolvedContext && typeof window !== "undefined") {
1349
- resolvedContext = {
1350
- searchParams: new URLSearchParams(window.location.search),
1351
- url: window.location.href
1352
- };
1353
- }
1354
- let src = resolveWeaverseNextStudioScriptSrc(resolvedContext, {
1355
- storefrontHostname: options.storefrontHostname ?? (typeof window === "undefined" ? void 0 : window.location.hostname)
1356
- });
1357
- if (src) {
1358
- loadScript(src);
1359
- }
1000
+ let resolvedContext = context;
1001
+ if (!resolvedContext && typeof window !== "undefined") resolvedContext = {
1002
+ searchParams: new URLSearchParams(window.location.search),
1003
+ url: window.location.href
1004
+ };
1005
+ let src = resolveWeaverseNextStudioScriptSrc(resolvedContext, { storefrontHostname: options.storefrontHostname ?? (typeof window === "undefined" ? void 0 : window.location.hostname) });
1006
+ if (src) loadScript(src);
1360
1007
  }
1361
1008
  function WeaverseNextStudioConnect(props) {
1362
- useEffect5(() => {
1363
- loadWeaverseNextStudioScript(props.context, {
1364
- storefrontHostname: props.storefrontHostname
1365
- });
1366
- }, [props.context, props.storefrontHostname]);
1367
- return null;
1009
+ useEffect(() => {
1010
+ loadWeaverseNextStudioScript(props.context, { storefrontHostname: props.storefrontHostname });
1011
+ }, [props.context, props.storefrontHostname]);
1012
+ return null;
1368
1013
  }
1369
- export {
1370
- ThemeTextProvider,
1371
- TranslationProvider,
1372
- WeaverseNextProvider,
1373
- WeaverseNextRenderer,
1374
- WeaverseNextRootProvider,
1375
- WeaverseNextRuntime,
1376
- WeaverseNextStudio,
1377
- WeaverseNextStudioBridge,
1378
- WeaverseNextStudioConnect,
1379
- bindWeaverseNextStudioRuntime,
1380
- createWeaverseNextClient,
1381
- createWeaverseNextRuntime,
1382
- loadWeaverseNextStudioScript,
1383
- useChildInstances,
1384
- useItemInstance,
1385
- useParentInstance,
1386
- useThemeSettings,
1387
- useThemeText,
1388
- useTranslation,
1389
- useWeaverse,
1390
- useWeaverseCommerce,
1391
- useWeaverseNextStudioInternals,
1392
- useWeaversePageData,
1393
- useWeaverseRootData
1394
- };
1014
+ //#endregion
1015
+ export { ThemeTextProvider, TranslationProvider, WeaverseNextProvider, WeaverseNextRenderer, WeaverseNextRootProvider, WeaverseNextRuntime, WeaverseNextStudio, WeaverseNextStudioBridge, WeaverseNextStudioConnect, bindWeaverseNextStudioRuntime, createWeaverseNextClient, createWeaverseNextRuntime, loadWeaverseNextStudioScript, useChildInstances, useItemInstance, useParentInstance, useThemeSettings, useThemeText, useTranslation, useWeaverse, useWeaverseCommerce, useWeaverseNextStudioInternals, useWeaversePageData, useWeaverseRootData };
1016
+
1395
1017
  //# sourceMappingURL=client-boundary.mjs.map