@weaverse/next 0.1.0-alpha.0 → 0.1.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +562 -0
- package/dist/chunk-XXGMPTWH.mjs +219 -0
- package/dist/chunk-XXGMPTWH.mjs.map +1 -0
- package/dist/index.d.mts +487 -161
- package/dist/index.d.ts +487 -161
- package/dist/index.js +1060 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +896 -106
- package/dist/index.mjs.map +1 -1
- package/dist/seo-CgO21rLg.d.mts +517 -0
- package/dist/seo-CgO21rLg.d.ts +517 -0
- package/dist/server.d.mts +99 -0
- package/dist/server.d.ts +99 -0
- package/dist/server.js +892 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +671 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +23 -4
package/dist/index.mjs
CHANGED
|
@@ -1,38 +1,91 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { buildWeaverseNextRequestInfo, generateDataFromSchema } from './chunk-XXGMPTWH.mjs';
|
|
2
|
+
export { buildWeaverseNextRequestInfo, formatWeaverseNextSeoMetadata, generateDataFromSchema, getWeaverseNextSeoMetadata, runWeaverseComponentLoaders } from './chunk-XXGMPTWH.mjs';
|
|
3
|
+
import { WeaverseRoot, Weaverse, WeaverseItemStore, useSafeExternalStore } from '@weaverse/react';
|
|
2
4
|
export { isBrowser, isIframe, useChildInstances, useItemInstance, useParentInstance, useWeaverse } from '@weaverse/react';
|
|
3
5
|
import { createSchema } from '@weaverse/schema';
|
|
4
|
-
export
|
|
5
|
-
import { jsx } from 'react/jsx-runtime';
|
|
6
|
-
import { createContext, memo, useContext, useMemo } from 'react';
|
|
6
|
+
export * from '@weaverse/schema';
|
|
7
|
+
import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
|
|
8
|
+
import { createContext, memo, useContext, useMemo, useEffect, useLayoutEffect, useRef, useSyncExternalStore } from 'react';
|
|
9
|
+
import { useRouter } from 'next/navigation';
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
11
|
+
function flattenItemData(update) {
|
|
12
|
+
let { data, ...rest } = update;
|
|
13
|
+
if (!(data && typeof data === "object" && !Array.isArray(data))) {
|
|
14
|
+
return rest;
|
|
15
|
+
}
|
|
16
|
+
return { ...data, ...rest };
|
|
17
|
+
}
|
|
18
|
+
var deferredItemUpdates = null;
|
|
19
|
+
function collectDeferredItemUpdates(create) {
|
|
20
|
+
let previousQueue = deferredItemUpdates;
|
|
21
|
+
let queue = /* @__PURE__ */ new Set();
|
|
22
|
+
deferredItemUpdates = queue;
|
|
23
|
+
try {
|
|
24
|
+
return [create(), [...queue]];
|
|
25
|
+
} finally {
|
|
26
|
+
deferredItemUpdates = previousQueue;
|
|
24
27
|
}
|
|
25
|
-
return data;
|
|
26
28
|
}
|
|
27
|
-
|
|
28
|
-
// src/item.ts
|
|
29
29
|
var WeaverseNextItem = class extends WeaverseItemStore {
|
|
30
|
+
/**
|
|
31
|
+
* Cached merged snapshot (base `_store` + translations). Reset whenever the
|
|
32
|
+
* `_store` ref or the item's translation entry ref changes, so
|
|
33
|
+
* `useSyncExternalStore` sees a stable object between unrelated re-renders.
|
|
34
|
+
*/
|
|
35
|
+
_cachedSnapshot = null;
|
|
36
|
+
_snapshotStoreRef = null;
|
|
37
|
+
_snapshotTranslationRef = null;
|
|
30
38
|
constructor(initialData, weaverse) {
|
|
31
39
|
super(initialData, weaverse);
|
|
32
|
-
let { data, ...rest } = initialData;
|
|
33
40
|
let schemaData = generateDataFromSchema(this.Element?.schema);
|
|
34
|
-
Object.assign(this._store, schemaData,
|
|
41
|
+
Object.assign(this._store, schemaData, flattenItemData(initialData));
|
|
35
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Flatten nested `data` on updates exactly like the constructor does. Core's
|
|
45
|
+
* `initProject()` calls `setData(item)` when a new runtime serves a page
|
|
46
|
+
* whose item instances already exist (e.g. locale/client navigation), and
|
|
47
|
+
* the inherited shallow merge would leave stale top-level props behind.
|
|
48
|
+
* Assigning through the inherited `data` setter swaps the `_store` ref,
|
|
49
|
+
* which invalidates the memoized snapshot below. The subscriber emit is
|
|
50
|
+
* queued instead of fired when a render-phase deferral is active (see
|
|
51
|
+
* `collectDeferredItemUpdates`).
|
|
52
|
+
*/
|
|
53
|
+
setData = (update) => {
|
|
54
|
+
this.data = flattenItemData(update);
|
|
55
|
+
if (deferredItemUpdates) {
|
|
56
|
+
deferredItemUpdates.add(this);
|
|
57
|
+
} else {
|
|
58
|
+
this.triggerUpdate();
|
|
59
|
+
}
|
|
60
|
+
return this.data;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Overlay item-level translations onto the base store when the runtime is in
|
|
64
|
+
* translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
|
|
65
|
+
* memoized by `_store` ref + translation entry ref so the returned object is
|
|
66
|
+
* referentially stable, and a fast path that returns the base store untouched
|
|
67
|
+
* when the item has no translations.
|
|
68
|
+
*/
|
|
69
|
+
getSnapShot = () => {
|
|
70
|
+
let base = this._store;
|
|
71
|
+
let translations = this.weaverse.translationMap[this._id];
|
|
72
|
+
if (!translations) {
|
|
73
|
+
return base;
|
|
74
|
+
}
|
|
75
|
+
if (this._cachedSnapshot && this._snapshotStoreRef === base && this._snapshotTranslationRef === translations) {
|
|
76
|
+
return this._cachedSnapshot;
|
|
77
|
+
}
|
|
78
|
+
let merged = { ...base };
|
|
79
|
+
for (let [key, entry] of Object.entries(translations)) {
|
|
80
|
+
if (entry.translatedValue !== void 0) {
|
|
81
|
+
merged[key] = entry.translatedValue;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
this._cachedSnapshot = merged;
|
|
85
|
+
this._snapshotStoreRef = base;
|
|
86
|
+
this._snapshotTranslationRef = translations;
|
|
87
|
+
return merged;
|
|
88
|
+
};
|
|
36
89
|
};
|
|
37
90
|
function ensureNextItemConstructor() {
|
|
38
91
|
if (!Weaverse.ItemConstructor || Weaverse.ItemConstructor === WeaverseItemStore || Weaverse.ItemConstructor === WeaverseNextItem) {
|
|
@@ -132,20 +185,283 @@ var NextClient = class {
|
|
|
132
185
|
function createWeaverseNextClient(config) {
|
|
133
186
|
return new NextClient(config);
|
|
134
187
|
}
|
|
188
|
+
|
|
189
|
+
// src/theme-settings-store.ts
|
|
190
|
+
function createWeaverseNextThemeSettingsStore(options = {}) {
|
|
191
|
+
let listeners = /* @__PURE__ */ new Set();
|
|
192
|
+
let store = {
|
|
193
|
+
publicEnv: options.publicEnv,
|
|
194
|
+
schema: options.schema,
|
|
195
|
+
settings: { ...options.settings ?? {} },
|
|
196
|
+
getServerSnapshot: () => store.settings,
|
|
197
|
+
getSnapshot: () => store.settings,
|
|
198
|
+
subscribe: (listener) => {
|
|
199
|
+
listeners.add(listener);
|
|
200
|
+
return () => {
|
|
201
|
+
listeners.delete(listener);
|
|
202
|
+
};
|
|
203
|
+
},
|
|
204
|
+
updateThemeSettings: (next) => {
|
|
205
|
+
store.settings = { ...store.settings, ...next };
|
|
206
|
+
for (let listener of listeners) {
|
|
207
|
+
listener();
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
};
|
|
211
|
+
return store;
|
|
212
|
+
}
|
|
213
|
+
function getNestedKey(obj, path, fallback) {
|
|
214
|
+
let keys = path.split(".");
|
|
215
|
+
let current = obj;
|
|
216
|
+
for (let key of keys) {
|
|
217
|
+
if (current == null || typeof current !== "object") {
|
|
218
|
+
return fallback;
|
|
219
|
+
}
|
|
220
|
+
current = current[key];
|
|
221
|
+
}
|
|
222
|
+
if (typeof current === "string") {
|
|
223
|
+
return current;
|
|
224
|
+
}
|
|
225
|
+
return fallback;
|
|
226
|
+
}
|
|
227
|
+
function interpolate(template, variables) {
|
|
228
|
+
if (!variables) {
|
|
229
|
+
return template;
|
|
230
|
+
}
|
|
231
|
+
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
232
|
+
let value = variables[key];
|
|
233
|
+
return value === void 0 ? match : String(value);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
var TranslationContext = createContext(null);
|
|
237
|
+
TranslationContext.displayName = "WeaverseNextTranslationContext";
|
|
238
|
+
function createTranslate(sources) {
|
|
239
|
+
let { staticContent, merchantOverrides, designOverrides, externalT } = sources;
|
|
240
|
+
return (key, variables) => {
|
|
241
|
+
if (externalT) {
|
|
242
|
+
let external = externalT(key, variables);
|
|
243
|
+
if (external && external !== key) {
|
|
244
|
+
return external;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
let design = designOverrides && Object.hasOwn(designOverrides, key) ? designOverrides[key] : void 0;
|
|
248
|
+
let override = merchantOverrides ? getNestedKey(merchantOverrides, key) : void 0;
|
|
249
|
+
let staticValue = getNestedKey(staticContent, key);
|
|
250
|
+
let raw = design ?? override ?? staticValue ?? key;
|
|
251
|
+
return interpolate(raw, variables);
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
var EMPTY = {};
|
|
255
|
+
var NOOP_SUBSCRIBE = () => () => {
|
|
256
|
+
};
|
|
257
|
+
var NOOP_SNAPSHOT = () => EMPTY;
|
|
258
|
+
function TranslationProvider({
|
|
259
|
+
staticContent,
|
|
260
|
+
merchantOverrides,
|
|
261
|
+
t: externalT,
|
|
262
|
+
translationStore,
|
|
263
|
+
themeTextStore,
|
|
264
|
+
children
|
|
265
|
+
}) {
|
|
266
|
+
let store = translationStore ?? themeTextStore ?? null;
|
|
267
|
+
let designOverrides = useSafeExternalStore(
|
|
268
|
+
store?.subscribe ?? NOOP_SUBSCRIBE,
|
|
269
|
+
store?.getSnapshot ?? NOOP_SNAPSHOT,
|
|
270
|
+
store?.getServerSnapshot ?? NOOP_SNAPSHOT
|
|
271
|
+
);
|
|
272
|
+
let value = useMemo(
|
|
273
|
+
() => ({
|
|
274
|
+
t: createTranslate({
|
|
275
|
+
staticContent,
|
|
276
|
+
merchantOverrides,
|
|
277
|
+
designOverrides,
|
|
278
|
+
externalT
|
|
279
|
+
}),
|
|
280
|
+
translationStore: store,
|
|
281
|
+
// Deprecated alias — same instance, kept for backward compatibility.
|
|
282
|
+
themeTextStore: store,
|
|
283
|
+
merchantOverrides: merchantOverrides ?? null
|
|
284
|
+
}),
|
|
285
|
+
[staticContent, merchantOverrides, designOverrides, externalT, store]
|
|
286
|
+
);
|
|
287
|
+
return /* @__PURE__ */ jsx(TranslationContext.Provider, { value, children });
|
|
288
|
+
}
|
|
289
|
+
function useTranslation() {
|
|
290
|
+
let ctx = useContext(TranslationContext);
|
|
291
|
+
if (!ctx) {
|
|
292
|
+
throw new Error(
|
|
293
|
+
"useTranslation must be used within <TranslationProvider>. Wrap your app with <WeaverseNextRootProvider>."
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
return ctx;
|
|
297
|
+
}
|
|
298
|
+
var ThemeTextProvider = TranslationProvider;
|
|
299
|
+
var useThemeText = useTranslation;
|
|
300
|
+
|
|
301
|
+
// src/translation-store.ts
|
|
302
|
+
var TranslationStore = class {
|
|
303
|
+
overrides = {};
|
|
304
|
+
listeners = /* @__PURE__ */ new Set();
|
|
305
|
+
setOverrides = (overrides) => {
|
|
306
|
+
this.overrides = { ...overrides };
|
|
307
|
+
this.emit();
|
|
308
|
+
};
|
|
309
|
+
updateOverrides = (newOverrides) => {
|
|
310
|
+
this.overrides = { ...this.overrides, ...newOverrides };
|
|
311
|
+
this.emit();
|
|
312
|
+
};
|
|
313
|
+
getSnapshot = () => this.overrides;
|
|
314
|
+
getServerSnapshot = () => this.overrides;
|
|
315
|
+
subscribe = (callback) => {
|
|
316
|
+
this.listeners.add(callback);
|
|
317
|
+
return () => {
|
|
318
|
+
this.listeners.delete(callback);
|
|
319
|
+
};
|
|
320
|
+
};
|
|
321
|
+
emit = () => {
|
|
322
|
+
for (const listener of Array.from(this.listeners)) {
|
|
323
|
+
try {
|
|
324
|
+
listener();
|
|
325
|
+
} catch (error) {
|
|
326
|
+
console.error("TranslationStore: Listener error", error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
};
|
|
331
|
+
var ThemeTextStore = TranslationStore;
|
|
332
|
+
var WeaverseNextRootContext = createContext(null);
|
|
333
|
+
function WeaverseNextRootProvider(props) {
|
|
334
|
+
let {
|
|
335
|
+
children,
|
|
336
|
+
initialThemeSettings,
|
|
337
|
+
merchantOverrides,
|
|
338
|
+
staticContent,
|
|
339
|
+
t,
|
|
340
|
+
themeSchema,
|
|
341
|
+
publicEnv
|
|
342
|
+
} = props;
|
|
343
|
+
let storeRef = useRef(null);
|
|
344
|
+
if (!storeRef.current) {
|
|
345
|
+
storeRef.current = createWeaverseNextThemeSettingsStore({
|
|
346
|
+
publicEnv,
|
|
347
|
+
schema: themeSchema,
|
|
348
|
+
settings: initialThemeSettings
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
let themeSettingsStore = storeRef.current;
|
|
352
|
+
let translationStoreRef = useRef(null);
|
|
353
|
+
if (!translationStoreRef.current) {
|
|
354
|
+
translationStoreRef.current = new TranslationStore();
|
|
355
|
+
}
|
|
356
|
+
let translationStore = translationStoreRef.current;
|
|
357
|
+
let appliedThemeSettingsRef = useRef(initialThemeSettings);
|
|
358
|
+
useEffect(() => {
|
|
359
|
+
if (initialThemeSettings && appliedThemeSettingsRef.current !== initialThemeSettings) {
|
|
360
|
+
themeSettingsStore.updateThemeSettings(initialThemeSettings);
|
|
361
|
+
appliedThemeSettingsRef.current = initialThemeSettings;
|
|
362
|
+
}
|
|
363
|
+
}, [initialThemeSettings, themeSettingsStore]);
|
|
364
|
+
let resolvedStaticContent = staticContent ?? getSchemaStaticContent(themeSchema);
|
|
365
|
+
let rootContextValue = useMemo(
|
|
366
|
+
() => ({
|
|
367
|
+
merchantOverrides,
|
|
368
|
+
staticContent: resolvedStaticContent,
|
|
369
|
+
themeSettingsStore,
|
|
370
|
+
translationStore
|
|
371
|
+
}),
|
|
372
|
+
[
|
|
373
|
+
merchantOverrides,
|
|
374
|
+
resolvedStaticContent,
|
|
375
|
+
themeSettingsStore,
|
|
376
|
+
translationStore
|
|
377
|
+
]
|
|
378
|
+
);
|
|
379
|
+
let contextValue = useMemo(
|
|
380
|
+
() => ({
|
|
381
|
+
merchantOverrides,
|
|
382
|
+
themeSettings: themeSettingsStore.getSnapshot(),
|
|
383
|
+
themeSettingsStore,
|
|
384
|
+
translationStore
|
|
385
|
+
}),
|
|
386
|
+
[merchantOverrides, themeSettingsStore, translationStore]
|
|
387
|
+
);
|
|
388
|
+
return /* @__PURE__ */ jsx(WeaverseNextRootContext.Provider, { value: rootContextValue, children: /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx(
|
|
389
|
+
TranslationProvider,
|
|
390
|
+
{
|
|
391
|
+
merchantOverrides,
|
|
392
|
+
staticContent: resolvedStaticContent,
|
|
393
|
+
t,
|
|
394
|
+
translationStore,
|
|
395
|
+
children
|
|
396
|
+
}
|
|
397
|
+
) }) });
|
|
398
|
+
}
|
|
399
|
+
var EMPTY_THEME_SETTINGS = {};
|
|
400
|
+
var EMPTY_STATIC_CONTENT = {};
|
|
401
|
+
function getSchemaStaticContent(schema) {
|
|
402
|
+
let i18n = schema?.i18n;
|
|
403
|
+
return i18n?.staticContent ?? EMPTY_STATIC_CONTENT;
|
|
404
|
+
}
|
|
135
405
|
var WeaverseNextContext = createContext(null);
|
|
136
406
|
function WeaverseNextProvider(props) {
|
|
137
407
|
let { children, client, rootData, pageData, commerce, themeSettings } = props;
|
|
408
|
+
let rootContext = useContext(WeaverseNextRootContext);
|
|
409
|
+
let themeSettingsValue = themeSettings ?? client?.themeSettings ?? EMPTY_THEME_SETTINGS;
|
|
410
|
+
let ownTranslationStoreRef = useRef(null);
|
|
411
|
+
if (!(rootContext || ownTranslationStoreRef.current)) {
|
|
412
|
+
ownTranslationStoreRef.current = new TranslationStore();
|
|
413
|
+
}
|
|
414
|
+
let translationStore = rootContext?.translationStore ?? ownTranslationStoreRef.current;
|
|
415
|
+
let staticContent = props.staticContent ?? rootContext?.staticContent ?? getSchemaStaticContent(client?.themeSchema);
|
|
416
|
+
let merchantOverrides = props.merchantOverrides ?? rootContext?.merchantOverrides;
|
|
417
|
+
let ownThemeSettingsStore = useMemo(() => {
|
|
418
|
+
if (rootContext) {
|
|
419
|
+
return null;
|
|
420
|
+
}
|
|
421
|
+
return createWeaverseNextThemeSettingsStore({
|
|
422
|
+
schema: client?.themeSchema,
|
|
423
|
+
settings: themeSettingsValue
|
|
424
|
+
});
|
|
425
|
+
}, [rootContext, client?.themeSchema, themeSettingsValue]);
|
|
426
|
+
let themeSettingsStore = rootContext?.themeSettingsStore ?? ownThemeSettingsStore;
|
|
427
|
+
let mergedIntoRootRef = useRef(void 0);
|
|
428
|
+
useEffect(() => {
|
|
429
|
+
if (rootContext && themeSettingsValue !== EMPTY_THEME_SETTINGS && mergedIntoRootRef.current !== themeSettingsValue) {
|
|
430
|
+
rootContext.themeSettingsStore.updateThemeSettings(themeSettingsValue);
|
|
431
|
+
mergedIntoRootRef.current = themeSettingsValue;
|
|
432
|
+
}
|
|
433
|
+
}, [rootContext, themeSettingsValue]);
|
|
138
434
|
let value = useMemo(
|
|
139
435
|
() => ({
|
|
140
436
|
client,
|
|
141
437
|
rootData,
|
|
142
438
|
pageData,
|
|
143
439
|
commerce: commerce ?? client?.commerce,
|
|
144
|
-
|
|
440
|
+
merchantOverrides,
|
|
441
|
+
themeSettings: themeSettingsStore.getSnapshot(),
|
|
442
|
+
themeSettingsStore,
|
|
443
|
+
translationStore
|
|
145
444
|
}),
|
|
146
|
-
[
|
|
445
|
+
[
|
|
446
|
+
client,
|
|
447
|
+
rootData,
|
|
448
|
+
pageData,
|
|
449
|
+
commerce,
|
|
450
|
+
merchantOverrides,
|
|
451
|
+
themeSettingsStore,
|
|
452
|
+
translationStore
|
|
453
|
+
]
|
|
147
454
|
);
|
|
148
|
-
return /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value, children
|
|
455
|
+
return /* @__PURE__ */ jsx(WeaverseNextContext.Provider, { value, children: /* @__PURE__ */ jsx(
|
|
456
|
+
TranslationProvider,
|
|
457
|
+
{
|
|
458
|
+
merchantOverrides,
|
|
459
|
+
staticContent,
|
|
460
|
+
t: props.t,
|
|
461
|
+
translationStore,
|
|
462
|
+
children
|
|
463
|
+
}
|
|
464
|
+
) });
|
|
149
465
|
}
|
|
150
466
|
|
|
151
467
|
// src/hooks.ts
|
|
@@ -167,87 +483,438 @@ function useWeaverseCommerce() {
|
|
|
167
483
|
return useWeaverseNextContext("useWeaverseCommerce").commerce;
|
|
168
484
|
}
|
|
169
485
|
function useThemeSettings() {
|
|
170
|
-
|
|
486
|
+
let { themeSettingsStore } = useWeaverseNextContext("useThemeSettings");
|
|
487
|
+
return useSyncExternalStore(
|
|
488
|
+
themeSettingsStore.subscribe,
|
|
489
|
+
themeSettingsStore.getSnapshot,
|
|
490
|
+
themeSettingsStore.getServerSnapshot
|
|
491
|
+
);
|
|
171
492
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
function isItemNode(node) {
|
|
175
|
-
return typeof node === "object" && node !== null && typeof node.type === "string";
|
|
493
|
+
function getRuntimeWindow() {
|
|
494
|
+
return typeof window === "undefined" ? void 0 : window;
|
|
176
495
|
}
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
(child) => isItemNode(child) ? cloneItem(child) : { ...child }
|
|
182
|
-
) : item.children
|
|
183
|
-
};
|
|
496
|
+
function getRenderablePage(data) {
|
|
497
|
+
let page = data.page;
|
|
498
|
+
let rootId = page.rootId ?? page.items.find((item) => item.type === "main")?.id ?? page.items[0]?.id ?? page.id;
|
|
499
|
+
return { ...page, rootId };
|
|
184
500
|
}
|
|
185
|
-
|
|
186
|
-
let
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
501
|
+
function getConfigString(configs, key) {
|
|
502
|
+
let value = configs?.[key];
|
|
503
|
+
return typeof value === "string" ? value : void 0;
|
|
504
|
+
}
|
|
505
|
+
function getRecordString(record, key) {
|
|
506
|
+
let value = record?.[key];
|
|
507
|
+
return typeof value === "string" ? value : void 0;
|
|
508
|
+
}
|
|
509
|
+
function resolveProjectId(client, data, fallback) {
|
|
510
|
+
let projectId = client?.projectId;
|
|
511
|
+
if (projectId) {
|
|
512
|
+
return projectId;
|
|
513
|
+
}
|
|
514
|
+
let configProjectId = getConfigString(data.configs, "projectId");
|
|
515
|
+
if (configProjectId) {
|
|
516
|
+
return configProjectId;
|
|
517
|
+
}
|
|
518
|
+
return getRecordString(data.project, "id") ?? fallback;
|
|
519
|
+
}
|
|
520
|
+
function resolveDataContext(config) {
|
|
521
|
+
if (config.dataContext) {
|
|
522
|
+
return config.dataContext;
|
|
523
|
+
}
|
|
524
|
+
if (config.client?.dataContext) {
|
|
525
|
+
return config.client.dataContext;
|
|
190
526
|
}
|
|
191
|
-
|
|
192
|
-
|
|
527
|
+
return {};
|
|
528
|
+
}
|
|
529
|
+
function getRuntimeKey(pageId, requestInfo) {
|
|
530
|
+
return `${pageId}:${requestInfo.pathname}:${requestInfo.search}`;
|
|
531
|
+
}
|
|
532
|
+
function registerRuntime(runtime) {
|
|
533
|
+
let runtimeWindow = getRuntimeWindow();
|
|
534
|
+
if (!runtimeWindow) {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
runtimeWindow.__weaverses ??= {};
|
|
538
|
+
runtimeWindow.__weaverses[runtime.pageId] = runtime;
|
|
539
|
+
runtimeWindow.__weaverse = runtime;
|
|
540
|
+
}
|
|
541
|
+
var WeaverseNextRuntime = class extends Weaverse {
|
|
542
|
+
pageId;
|
|
543
|
+
internal;
|
|
544
|
+
requestInfo;
|
|
545
|
+
isPreviewMode;
|
|
546
|
+
isRevisionPreview;
|
|
547
|
+
sectionType;
|
|
548
|
+
// ─── Item-level translation sidecar (design mode only) ─────────────
|
|
549
|
+
/**
|
|
550
|
+
* Translation map received from Builder in design mode, keyed by item ID.
|
|
551
|
+
* `WeaverseNextItem.getSnapShot()` overlays these onto the data handed to
|
|
552
|
+
* components, so translations render without mutating the base `_store`.
|
|
553
|
+
*/
|
|
554
|
+
translationMap = {};
|
|
555
|
+
translationLocale = String();
|
|
556
|
+
translationLanguageId = String();
|
|
557
|
+
/**
|
|
558
|
+
* Fresh page data captured while React was rendering. Runtime reuse happens
|
|
559
|
+
* inside the renderer's render phase (`useMemo`), where applying it through
|
|
560
|
+
* `setProjectData()` would emit item updates to `useSyncExternalStore`
|
|
561
|
+
* subscribers mid-render. The renderer applies it post-commit via
|
|
562
|
+
* `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
|
|
563
|
+
* Studio tree owns the page data there.
|
|
564
|
+
*/
|
|
565
|
+
pendingProjectData;
|
|
566
|
+
/**
|
|
567
|
+
* Reused item instances whose data was refreshed while this runtime was
|
|
568
|
+
* constructed during render (core `initProject()` calls `setData()` on
|
|
569
|
+
* them). Their data is already fresh; only the subscriber notification was
|
|
570
|
+
* deferred to `flushRenderPhaseUpdates()`.
|
|
571
|
+
*/
|
|
572
|
+
pendingItemUpdates = [];
|
|
573
|
+
constructor(config) {
|
|
574
|
+
let { client, data } = config;
|
|
575
|
+
let page = getRenderablePage(data);
|
|
576
|
+
let configs = data.configs;
|
|
577
|
+
let requestContext = client?.requestContext;
|
|
578
|
+
let projectId = resolveProjectId(client, data, page.id);
|
|
579
|
+
ensureNextItemConstructor();
|
|
580
|
+
super({
|
|
581
|
+
projectId,
|
|
582
|
+
data: page,
|
|
583
|
+
isDesignMode: requestContext?.isDesignMode ?? false,
|
|
584
|
+
weaverseHost: getConfigString(configs, "weaverseHost"),
|
|
585
|
+
weaverseVersion: getConfigString(configs, "weaverseVersion")
|
|
586
|
+
});
|
|
587
|
+
this.pageId = page.id;
|
|
588
|
+
this.dataContext = resolveDataContext(config);
|
|
589
|
+
this.requestInfo = buildWeaverseNextRequestInfo(requestContext);
|
|
590
|
+
this.isDesignMode = requestContext?.isDesignMode ?? false;
|
|
591
|
+
this.isPreviewMode = requestContext?.isPreviewMode ?? false;
|
|
592
|
+
this.isRevisionPreview = requestContext?.isRevisionPreview ?? false;
|
|
593
|
+
this.sectionType = requestContext?.sectionType;
|
|
594
|
+
let translationStore = config.translationStore ?? new TranslationStore();
|
|
595
|
+
this.internal = {
|
|
596
|
+
merchantOverrides: config.merchantOverrides,
|
|
597
|
+
navigate: config.navigate,
|
|
598
|
+
pageAssignment: data.pageAssignment,
|
|
599
|
+
project: data.project,
|
|
600
|
+
revalidate: config.revalidate,
|
|
601
|
+
themeSettingsStore: config.themeSettingsStore ?? createWeaverseNextThemeSettingsStore({
|
|
602
|
+
schema: client?.themeSchema,
|
|
603
|
+
settings: client?.themeSettings
|
|
604
|
+
}),
|
|
605
|
+
translationStore,
|
|
606
|
+
themeTextStore: translationStore
|
|
607
|
+
};
|
|
608
|
+
this.extractTranslationSidecar();
|
|
193
609
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
610
|
+
/**
|
|
611
|
+
* Pull `translationMap` / `translationLocale` / `translationLanguageId` off
|
|
612
|
+
* the current page data (Builder attaches them in design mode). Unlike
|
|
613
|
+
* Hydrogen, this also clears the sidecar to defaults when the new page data
|
|
614
|
+
* carries none, so a reused runtime / project-data swap can't leave a stale
|
|
615
|
+
* map overlaying the fresh tree.
|
|
616
|
+
*/
|
|
617
|
+
extractTranslationSidecar = () => {
|
|
618
|
+
let pageData = this.data;
|
|
619
|
+
let translationMap = pageData?.translationMap;
|
|
620
|
+
if (translationMap) {
|
|
621
|
+
this.translationMap = translationMap;
|
|
622
|
+
this.translationLocale = pageData?.translationLocale || "";
|
|
623
|
+
this.translationLanguageId = pageData?.translationLanguageId || "";
|
|
624
|
+
} else {
|
|
625
|
+
this.translationMap = {};
|
|
626
|
+
this.translationLocale = "";
|
|
627
|
+
this.translationLanguageId = "";
|
|
199
628
|
}
|
|
200
629
|
};
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
630
|
+
/**
|
|
631
|
+
* Replace the translation sidecar (Builder pushes this when translation data
|
|
632
|
+
* arrives or the active language changes) and refresh every item so their
|
|
633
|
+
* merged snapshots recompute.
|
|
634
|
+
*/
|
|
635
|
+
setTranslationSidecar = (map = {}, locale = "", languageId = "") => {
|
|
636
|
+
this.translationMap = map;
|
|
637
|
+
this.translationLocale = locale;
|
|
638
|
+
this.translationLanguageId = languageId;
|
|
639
|
+
this.refreshAllItems();
|
|
640
|
+
};
|
|
641
|
+
/**
|
|
642
|
+
* Update a single translatable field for one item. Assigns a new per-item
|
|
643
|
+
* entry object so `WeaverseNextItem.getSnapShot()`'s translation-ref cache
|
|
644
|
+
* invalidates, then triggers only that item's subscribers.
|
|
645
|
+
*/
|
|
646
|
+
updateTranslation = (itemId, key, originalValue, translatedValue) => {
|
|
647
|
+
if (!this.translationMap[itemId]) {
|
|
648
|
+
this.translationMap[itemId] = {};
|
|
649
|
+
}
|
|
650
|
+
this.translationMap[itemId] = {
|
|
651
|
+
...this.translationMap[itemId],
|
|
652
|
+
[key]: { originalValue, translatedValue }
|
|
653
|
+
};
|
|
654
|
+
let instance = this.itemInstances.get(itemId);
|
|
655
|
+
if (instance) {
|
|
656
|
+
instance.triggerUpdate();
|
|
657
|
+
}
|
|
215
658
|
};
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
659
|
+
/**
|
|
660
|
+
* Collect translation changes for the save flow. Returns `undefined` unless
|
|
661
|
+
* both the locale and language ID are set and at least one entry exists;
|
|
662
|
+
* each entry key is namespaced as `data.<field>` to match Builder.
|
|
663
|
+
*/
|
|
664
|
+
getTranslationChanges = () => {
|
|
665
|
+
let languageId = this.translationLanguageId;
|
|
666
|
+
if (!(this.translationLocale && languageId)) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
let entries = [];
|
|
670
|
+
for (let [itemId, fields] of Object.entries(this.translationMap)) {
|
|
671
|
+
for (let [key, entry] of Object.entries(fields)) {
|
|
672
|
+
entries.push({
|
|
673
|
+
itemId,
|
|
674
|
+
key: `data.${key}`,
|
|
675
|
+
originalValue: entry.originalValue,
|
|
676
|
+
translatedValue: entry.translatedValue
|
|
677
|
+
});
|
|
220
678
|
}
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
679
|
+
}
|
|
680
|
+
if (entries.length === 0) {
|
|
681
|
+
return;
|
|
682
|
+
}
|
|
683
|
+
return { languageId, entries };
|
|
684
|
+
};
|
|
685
|
+
/**
|
|
686
|
+
* Re-extract the translation sidecar whenever project data is replaced (route
|
|
687
|
+
* change / non-design reuse), before rebuilding item stores. Takes the
|
|
688
|
+
* renderable page shape (`rootId` resolved) that `getRenderablePage()` and
|
|
689
|
+
* the reuse branch pass in.
|
|
690
|
+
*/
|
|
691
|
+
setProjectData = (data) => {
|
|
692
|
+
this.data = data;
|
|
693
|
+
this.extractTranslationSidecar();
|
|
694
|
+
this.initProject();
|
|
695
|
+
};
|
|
696
|
+
/**
|
|
697
|
+
* Apply updates deferred off the render phase: swap in any pending page data
|
|
698
|
+
* captured on runtime reuse, then notify items whose data was refreshed
|
|
699
|
+
* during construction. The renderer calls this from a layout effect right
|
|
700
|
+
* after commit, so subscribers re-render before paint (no content flash) and
|
|
701
|
+
* without React's setState-in-render warning.
|
|
702
|
+
*/
|
|
703
|
+
flushRenderPhaseUpdates = () => {
|
|
704
|
+
let pendingData = this.pendingProjectData;
|
|
705
|
+
if (pendingData) {
|
|
706
|
+
this.pendingProjectData = void 0;
|
|
707
|
+
this.setProjectData(pendingData);
|
|
708
|
+
}
|
|
709
|
+
let pendingItems = this.pendingItemUpdates;
|
|
710
|
+
if (pendingItems.length > 0) {
|
|
711
|
+
this.pendingItemUpdates = [];
|
|
712
|
+
for (let item of pendingItems) {
|
|
713
|
+
item.triggerUpdate();
|
|
234
714
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
715
|
+
}
|
|
716
|
+
};
|
|
717
|
+
};
|
|
718
|
+
function createWeaverseNextRuntime(config) {
|
|
719
|
+
let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
|
|
720
|
+
let page = getRenderablePage(config.data);
|
|
721
|
+
let runtimeWindow = getRuntimeWindow();
|
|
722
|
+
let existing = runtimeWindow?.__weaverses?.[page.id];
|
|
723
|
+
let requestKey = getRuntimeKey(page.id, requestInfo);
|
|
724
|
+
if (existing?.__weaverseNextRequestKey === requestKey) {
|
|
725
|
+
let nextIsDesignMode = config.client?.requestContext?.isDesignMode ?? false;
|
|
726
|
+
if (existing.isDesignMode || nextIsDesignMode) {
|
|
727
|
+
existing.pendingProjectData = void 0;
|
|
728
|
+
} else {
|
|
729
|
+
existing.pendingProjectData = page;
|
|
730
|
+
}
|
|
731
|
+
existing.__weaverseNextLatestData = page;
|
|
732
|
+
existing.dataContext = resolveDataContext(config);
|
|
733
|
+
existing.requestInfo = requestInfo;
|
|
734
|
+
existing.projectId = resolveProjectId(config.client, config.data, page.id);
|
|
735
|
+
existing.isDesignMode = nextIsDesignMode;
|
|
736
|
+
existing.isPreviewMode = config.client?.requestContext?.isPreviewMode ?? false;
|
|
737
|
+
existing.isRevisionPreview = config.client?.requestContext?.isRevisionPreview ?? false;
|
|
738
|
+
existing.sectionType = config.client?.requestContext?.sectionType;
|
|
739
|
+
existing.weaverseHost = getConfigString(config.data.configs, "weaverseHost") ?? existing.weaverseHost;
|
|
740
|
+
existing.weaverseVersion = getConfigString(config.data.configs, "weaverseVersion") ?? existing.weaverseVersion;
|
|
741
|
+
existing.internal.pageAssignment = config.data.pageAssignment;
|
|
742
|
+
existing.internal.project = config.data.project;
|
|
743
|
+
if (config.navigate) {
|
|
744
|
+
existing.internal.navigate = config.navigate;
|
|
745
|
+
}
|
|
746
|
+
if (config.revalidate) {
|
|
747
|
+
existing.internal.revalidate = config.revalidate;
|
|
748
|
+
}
|
|
749
|
+
if (config.themeSettingsStore) {
|
|
750
|
+
existing.internal.themeSettingsStore = config.themeSettingsStore;
|
|
751
|
+
}
|
|
752
|
+
if (config.translationStore) {
|
|
753
|
+
existing.internal.translationStore = config.translationStore;
|
|
754
|
+
existing.internal.themeTextStore = config.translationStore;
|
|
755
|
+
}
|
|
756
|
+
existing.internal.merchantOverrides = config.merchantOverrides;
|
|
757
|
+
registerRuntime(existing);
|
|
758
|
+
return existing;
|
|
759
|
+
}
|
|
760
|
+
let [runtime, refreshedItems] = collectDeferredItemUpdates(
|
|
761
|
+
() => new WeaverseNextRuntime(config)
|
|
762
|
+
);
|
|
763
|
+
runtime.pendingItemUpdates = refreshedItems;
|
|
764
|
+
runtime.__weaverseNextRequestKey = requestKey;
|
|
765
|
+
runtime.__weaverseNextLatestData = page;
|
|
766
|
+
registerRuntime(runtime);
|
|
767
|
+
return runtime;
|
|
768
|
+
}
|
|
769
|
+
function bindWeaverseNextStudioRuntime(runtime) {
|
|
770
|
+
if (!runtime.isDesignMode) {
|
|
771
|
+
return false;
|
|
772
|
+
}
|
|
773
|
+
let studio = getRuntimeWindow()?.weaverseStudio;
|
|
774
|
+
if (!studio) {
|
|
775
|
+
return false;
|
|
776
|
+
}
|
|
777
|
+
let boundRuntime = runtime;
|
|
778
|
+
if (!boundRuntime.__weaverseNextStudioBound) {
|
|
779
|
+
studio.init?.(runtime);
|
|
780
|
+
boundRuntime.__weaverseNextStudioBound = true;
|
|
781
|
+
return true;
|
|
782
|
+
}
|
|
783
|
+
studio.refreshStudio?.({
|
|
784
|
+
data: boundRuntime.__weaverseNextLatestData ?? runtime.data,
|
|
785
|
+
pageId: runtime.pageId,
|
|
786
|
+
requestInfo: runtime.requestInfo
|
|
787
|
+
});
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// src/revalidate-item.ts
|
|
792
|
+
var DEFAULT_REVALIDATE_ENDPOINT = "/api/weaverse/revalidate";
|
|
793
|
+
async function revalidateWeaverseNextItem(runtime, draftItem, endpoint = DEFAULT_REVALIDATE_ENDPOINT) {
|
|
794
|
+
let instance = runtime.itemInstances.get(draftItem.id);
|
|
795
|
+
if (!instance) {
|
|
796
|
+
throw new Error(
|
|
797
|
+
`[weaverse-next] No live item instance for "${draftItem.id}".`
|
|
798
|
+
);
|
|
799
|
+
}
|
|
800
|
+
let response = await fetch(endpoint, {
|
|
801
|
+
method: "POST",
|
|
802
|
+
headers: { "Content-Type": "application/json" },
|
|
803
|
+
body: JSON.stringify({ draftItem })
|
|
804
|
+
});
|
|
805
|
+
if (!response.ok) {
|
|
806
|
+
throw new Error(
|
|
807
|
+
`[weaverse-next] Revalidate endpoint responded ${response.status}.`
|
|
808
|
+
);
|
|
809
|
+
}
|
|
810
|
+
let { loaderData } = await response.json();
|
|
811
|
+
instance.setData({ loaderData: loaderData ?? null });
|
|
812
|
+
}
|
|
813
|
+
var STUDIO_BIND_RETRY_INTERVAL_MS = 50;
|
|
814
|
+
var STUDIO_BIND_MAX_ATTEMPTS = 100;
|
|
815
|
+
function WeaverseNextStudioBridge(props) {
|
|
816
|
+
let { runtime, navigate, revalidate, revalidateItem } = props;
|
|
817
|
+
let lastRuntimeRef = useRef(runtime);
|
|
818
|
+
let lastRuntimeDataRef = useRef(runtime.data);
|
|
819
|
+
let lastRequestInfoRef = useRef(runtime.requestInfo);
|
|
820
|
+
useEffect(() => {
|
|
821
|
+
if (navigate) {
|
|
822
|
+
runtime.internal.navigate = navigate;
|
|
823
|
+
}
|
|
824
|
+
if (revalidate) {
|
|
825
|
+
runtime.internal.revalidate = revalidate;
|
|
826
|
+
}
|
|
827
|
+
if (revalidateItem) {
|
|
828
|
+
runtime.internal.revalidateItem = revalidateItem;
|
|
829
|
+
}
|
|
830
|
+
if (bindWeaverseNextStudioRuntime(runtime) || !runtime.isDesignMode) {
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
let attempts = 0;
|
|
834
|
+
let interval = window.setInterval(() => {
|
|
835
|
+
attempts += 1;
|
|
836
|
+
if (bindWeaverseNextStudioRuntime(runtime) || attempts >= STUDIO_BIND_MAX_ATTEMPTS) {
|
|
837
|
+
window.clearInterval(interval);
|
|
243
838
|
}
|
|
839
|
+
}, STUDIO_BIND_RETRY_INTERVAL_MS);
|
|
840
|
+
return () => window.clearInterval(interval);
|
|
841
|
+
}, [runtime, navigate, revalidate, revalidateItem]);
|
|
842
|
+
useEffect(() => {
|
|
843
|
+
if (lastRuntimeRef.current !== runtime) {
|
|
844
|
+
lastRuntimeRef.current = runtime;
|
|
845
|
+
lastRuntimeDataRef.current = runtime.data;
|
|
846
|
+
lastRequestInfoRef.current = runtime.requestInfo;
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
849
|
+
if (lastRuntimeDataRef.current === runtime.data && lastRequestInfoRef.current === runtime.requestInfo) {
|
|
850
|
+
return;
|
|
244
851
|
}
|
|
852
|
+
lastRuntimeDataRef.current = runtime.data;
|
|
853
|
+
lastRequestInfoRef.current = runtime.requestInfo;
|
|
854
|
+
bindWeaverseNextStudioRuntime(runtime);
|
|
855
|
+
}, [runtime, runtime.data, runtime.requestInfo]);
|
|
856
|
+
return null;
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
// src/studio-router.ts
|
|
860
|
+
function shouldResetScroll(options) {
|
|
861
|
+
if (!options || typeof options !== "object") {
|
|
862
|
+
return true;
|
|
245
863
|
}
|
|
246
|
-
|
|
247
|
-
|
|
864
|
+
return !options.preventScrollReset;
|
|
865
|
+
}
|
|
866
|
+
function createWeaverseNextStudioInternals(router, options = {}) {
|
|
867
|
+
return {
|
|
868
|
+
navigate: (to, navigateOptions) => {
|
|
869
|
+
let scroll = shouldResetScroll(navigateOptions);
|
|
870
|
+
if (options.replace) {
|
|
871
|
+
router.replace(to, { scroll });
|
|
872
|
+
} else {
|
|
873
|
+
router.push(to, { scroll });
|
|
874
|
+
}
|
|
875
|
+
},
|
|
876
|
+
revalidate: () => {
|
|
877
|
+
router.refresh();
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
function useWeaverseNextStudioInternals(options) {
|
|
882
|
+
let router = useRouter();
|
|
883
|
+
let ref = useRef(null);
|
|
884
|
+
if (!ref.current || ref.current.router !== router || ref.current.replace !== options?.replace) {
|
|
885
|
+
ref.current = {
|
|
886
|
+
internals: createWeaverseNextStudioInternals(router, options),
|
|
887
|
+
replace: options?.replace,
|
|
888
|
+
router
|
|
889
|
+
};
|
|
890
|
+
}
|
|
891
|
+
return ref.current.internals;
|
|
892
|
+
}
|
|
893
|
+
function WeaverseNextStudio(props) {
|
|
894
|
+
let { runtime, replace, revalidateEndpoint } = props;
|
|
895
|
+
let { navigate, revalidate } = useWeaverseNextStudioInternals({ replace });
|
|
896
|
+
let endpoint = revalidateEndpoint ?? DEFAULT_REVALIDATE_ENDPOINT;
|
|
897
|
+
let revalidateItemRef = useRef(null);
|
|
898
|
+
if (revalidateItemRef.current?.endpoint !== endpoint || revalidateItemRef.current.runtime !== runtime) {
|
|
899
|
+
revalidateItemRef.current = {
|
|
900
|
+
endpoint,
|
|
901
|
+
revalidateItem: (draftItem) => revalidateWeaverseNextItem(runtime, draftItem, endpoint),
|
|
902
|
+
runtime
|
|
903
|
+
};
|
|
904
|
+
}
|
|
905
|
+
return /* @__PURE__ */ jsx(
|
|
906
|
+
WeaverseNextStudioBridge,
|
|
907
|
+
{
|
|
908
|
+
navigate,
|
|
909
|
+
revalidate,
|
|
910
|
+
revalidateItem: revalidateItemRef.current.revalidateItem,
|
|
911
|
+
runtime
|
|
912
|
+
}
|
|
913
|
+
);
|
|
248
914
|
}
|
|
249
915
|
var EMPTY_DATA_CONTEXT = {};
|
|
250
|
-
|
|
916
|
+
var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect : useLayoutEffect;
|
|
917
|
+
function getRenderablePage2(data) {
|
|
251
918
|
let page = data?.page;
|
|
252
919
|
if (!page) {
|
|
253
920
|
return null;
|
|
@@ -260,30 +927,153 @@ var WeaverseNextRenderer = memo(function WeaverseNextRendererComponent(props) {
|
|
|
260
927
|
let client = props.client ?? context?.client;
|
|
261
928
|
let data = props.data ?? client?.data ?? null;
|
|
262
929
|
let dataContext = props.dataContext ?? client?.dataContext ?? EMPTY_DATA_CONTEXT;
|
|
263
|
-
let page = useMemo(() =>
|
|
930
|
+
let page = useMemo(() => getRenderablePage2(data), [data]);
|
|
264
931
|
let weaverse = useMemo(() => {
|
|
265
932
|
if (!page) {
|
|
266
933
|
return null;
|
|
267
934
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
data: page
|
|
935
|
+
return createWeaverseNextRuntime({
|
|
936
|
+
client,
|
|
937
|
+
data: { ...data, page },
|
|
938
|
+
dataContext,
|
|
939
|
+
merchantOverrides: context?.merchantOverrides,
|
|
940
|
+
themeSettingsStore: context?.themeSettingsStore,
|
|
941
|
+
translationStore: context?.translationStore
|
|
271
942
|
});
|
|
272
|
-
instance.dataContext = dataContext;
|
|
273
|
-
instance.isDesignMode = client?.requestContext?.isDesignMode ?? false;
|
|
274
|
-
return instance;
|
|
275
943
|
}, [
|
|
276
|
-
client
|
|
277
|
-
client?.requestContext?.isDesignMode,
|
|
944
|
+
client,
|
|
278
945
|
page,
|
|
279
|
-
|
|
946
|
+
data,
|
|
947
|
+
dataContext,
|
|
948
|
+
context?.merchantOverrides,
|
|
949
|
+
context?.themeSettingsStore,
|
|
950
|
+
context?.translationStore
|
|
280
951
|
]);
|
|
952
|
+
useIsomorphicLayoutEffect(() => {
|
|
953
|
+
weaverse?.flushRenderPhaseUpdates();
|
|
954
|
+
}, [weaverse]);
|
|
281
955
|
if (!weaverse) {
|
|
282
956
|
return null;
|
|
283
957
|
}
|
|
284
|
-
return /* @__PURE__ */
|
|
958
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
959
|
+
/* @__PURE__ */ jsx(WeaverseRoot, { context: weaverse }),
|
|
960
|
+
/* @__PURE__ */ jsx(WeaverseNextStudio, { runtime: weaverse })
|
|
961
|
+
] });
|
|
285
962
|
});
|
|
286
963
|
|
|
287
|
-
|
|
964
|
+
// src/studio-script-src.ts
|
|
965
|
+
var TRUSTED_STUDIO_DOMAINS = ["weaverse.io", "weaverse.dev"];
|
|
966
|
+
function isLoopbackHostname(hostname) {
|
|
967
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname.endsWith(".localhost");
|
|
968
|
+
}
|
|
969
|
+
function normalizeOrigin(value) {
|
|
970
|
+
if (!value) {
|
|
971
|
+
return null;
|
|
972
|
+
}
|
|
973
|
+
try {
|
|
974
|
+
return new URL(value).origin;
|
|
975
|
+
} catch {
|
|
976
|
+
return null;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
function isTrustedStudioOrigin(origin, storefrontHostname) {
|
|
980
|
+
let parsed;
|
|
981
|
+
try {
|
|
982
|
+
parsed = new URL(origin);
|
|
983
|
+
} catch {
|
|
984
|
+
return false;
|
|
985
|
+
}
|
|
986
|
+
let { hostname, protocol } = parsed;
|
|
987
|
+
if (isLoopbackHostname(storefrontHostname) && isLoopbackHostname(hostname)) {
|
|
988
|
+
return protocol === "http:" || protocol === "https:";
|
|
989
|
+
}
|
|
990
|
+
if (protocol !== "https:") {
|
|
991
|
+
return false;
|
|
992
|
+
}
|
|
993
|
+
return TRUSTED_STUDIO_DOMAINS.some(
|
|
994
|
+
(domain) => hostname === domain || hostname.endsWith(`.${domain}`)
|
|
995
|
+
);
|
|
996
|
+
}
|
|
997
|
+
function toSearchParams(context) {
|
|
998
|
+
if (context?.searchParams) {
|
|
999
|
+
return new URLSearchParams(context.searchParams);
|
|
1000
|
+
}
|
|
1001
|
+
if (context?.url) {
|
|
1002
|
+
let url = typeof context.url === "string" ? new URL(context.url, "http://localhost") : context.url;
|
|
1003
|
+
return new URLSearchParams(url.searchParams);
|
|
1004
|
+
}
|
|
1005
|
+
return new URLSearchParams();
|
|
1006
|
+
}
|
|
1007
|
+
function last(searchParams, key) {
|
|
1008
|
+
let values = searchParams.getAll(key);
|
|
1009
|
+
return values.length ? values.at(-1) ?? null : null;
|
|
1010
|
+
}
|
|
1011
|
+
function resolveWeaverseNextStudioScriptSrc(context, options = {}) {
|
|
1012
|
+
let searchParams = toSearchParams(context);
|
|
1013
|
+
let isDesignMode = context?.isDesignMode ?? last(searchParams, "isDesignMode") === "true";
|
|
1014
|
+
let isPreviewMode = context?.isPreviewMode ?? last(searchParams, "isPreviewMode") === "true";
|
|
1015
|
+
let isRevisionPreview = context?.isRevisionPreview ?? Boolean(last(searchParams, "__revisionId"));
|
|
1016
|
+
if (!(isDesignMode || isPreviewMode || isRevisionPreview)) {
|
|
1017
|
+
return null;
|
|
1018
|
+
}
|
|
1019
|
+
let origin = normalizeOrigin(last(searchParams, "weaverseHost"));
|
|
1020
|
+
if (!origin) {
|
|
1021
|
+
return null;
|
|
1022
|
+
}
|
|
1023
|
+
let storefrontHostname = options.storefrontHostname ?? "";
|
|
1024
|
+
if (!isTrustedStudioOrigin(origin, storefrontHostname)) {
|
|
1025
|
+
return null;
|
|
1026
|
+
}
|
|
1027
|
+
let bundle = isDesignMode ? "index.js" : "preview.js";
|
|
1028
|
+
let version = last(searchParams, "weaverseVersion");
|
|
1029
|
+
let url = `${origin}/static/studio/next/${bundle}`;
|
|
1030
|
+
return version ? `${url}?v=${encodeURIComponent(version)}` : url;
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
// src/studio-connect.tsx
|
|
1034
|
+
var loadedScriptSrcs = /* @__PURE__ */ new Set();
|
|
1035
|
+
function loadScript(src) {
|
|
1036
|
+
if (typeof document === "undefined") {
|
|
1037
|
+
return;
|
|
1038
|
+
}
|
|
1039
|
+
if (loadedScriptSrcs.has(src)) {
|
|
1040
|
+
return;
|
|
1041
|
+
}
|
|
1042
|
+
let existing = document.querySelector(`script[src="${src}"]`);
|
|
1043
|
+
if (existing) {
|
|
1044
|
+
loadedScriptSrcs.add(src);
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
let script = document.createElement("script");
|
|
1048
|
+
script.async = true;
|
|
1049
|
+
script.src = src;
|
|
1050
|
+
document.head.appendChild(script);
|
|
1051
|
+
loadedScriptSrcs.add(src);
|
|
1052
|
+
}
|
|
1053
|
+
function loadWeaverseNextStudioScript(context, options = {}) {
|
|
1054
|
+
let resolvedContext = context;
|
|
1055
|
+
if (!resolvedContext && typeof window !== "undefined") {
|
|
1056
|
+
resolvedContext = {
|
|
1057
|
+
searchParams: new URLSearchParams(window.location.search),
|
|
1058
|
+
url: window.location.href
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
let src = resolveWeaverseNextStudioScriptSrc(resolvedContext, {
|
|
1062
|
+
storefrontHostname: options.storefrontHostname ?? (typeof window === "undefined" ? void 0 : window.location.hostname)
|
|
1063
|
+
});
|
|
1064
|
+
if (src) {
|
|
1065
|
+
loadScript(src);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
function WeaverseNextStudioConnect(props) {
|
|
1069
|
+
useEffect(() => {
|
|
1070
|
+
loadWeaverseNextStudioScript(props.context, {
|
|
1071
|
+
storefrontHostname: props.storefrontHostname
|
|
1072
|
+
});
|
|
1073
|
+
}, [props.context, props.storefrontHostname]);
|
|
1074
|
+
return null;
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
export { DEFAULT_REVALIDATE_ENDPOINT, ThemeTextProvider, ThemeTextStore, TranslationProvider, TranslationStore, WeaverseNextProvider, WeaverseNextRenderer, WeaverseNextRootProvider, WeaverseNextRuntime, WeaverseNextStudio, WeaverseNextStudioBridge, WeaverseNextStudioConnect, bindWeaverseNextStudioRuntime, createTranslate, createWeaverseNextClient, createWeaverseNextRuntime, createWeaverseNextStudioInternals, createWeaverseNextThemeSettingsStore, getNestedKey, interpolate, loadWeaverseNextStudioScript, resolveWeaverseNextStudioScriptSrc, revalidateWeaverseNextItem, useThemeSettings, useThemeText, useTranslation, useWeaverseCommerce, useWeaverseNextStudioInternals, useWeaversePageData, useWeaverseRootData };
|
|
288
1078
|
//# sourceMappingURL=index.mjs.map
|
|
289
1079
|
//# sourceMappingURL=index.mjs.map
|