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