@weaverse/next 0.1.0-alpha.2 → 0.1.0-alpha.20
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 +586 -123
- package/dist/chunk-LH6AAEIK.mjs +326 -0
- package/dist/chunk-LH6AAEIK.mjs.map +1 -0
- package/dist/index.js +784 -60
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +588 -58
- package/dist/index.mjs.map +1 -1
- package/dist/server.js +537 -76
- package/dist/server.js.map +1 -1
- package/dist/server.mjs +363 -27
- package/dist/server.mjs.map +1 -1
- 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 +34 -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/translation-context.d.ts +156 -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 +12 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/package.json +12 -8
- package/src/client.ts +102 -0
- package/src/hooks.ts +50 -0
- package/src/index.ts +153 -0
- package/src/item.ts +167 -0
- package/src/loader.ts +135 -0
- package/src/main.tsx +45 -0
- package/src/provider.tsx +225 -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 +182 -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/translation-context.tsx +299 -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 +37 -0
- package/dist/chunk-SS6QUKYY.mjs +0 -149
- package/dist/chunk-SS6QUKYY.mjs.map +0 -1
- package/dist/index.d.mts +0 -250
- package/dist/index.d.ts +0 -250
- package/dist/server.d.mts +0 -60
- package/dist/server.d.ts +0 -60
- package/dist/types-DvEeLX6L.d.mts +0 -321
- package/dist/types-DvEeLX6L.d.ts +0 -321
package/dist/server.js
CHANGED
|
@@ -1,5 +1,72 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var schema = require('@weaverse/schema');
|
|
4
|
+
|
|
5
|
+
// src/seo.ts
|
|
6
|
+
function hasOpenGraphContent(seo) {
|
|
7
|
+
return Boolean(seo?.title || seo?.description || seo?.image || seo?.type);
|
|
8
|
+
}
|
|
9
|
+
function hasTwitterContent(seo) {
|
|
10
|
+
return Boolean(seo?.title || seo?.description || seo?.image || seo?.cardType);
|
|
11
|
+
}
|
|
12
|
+
function normalizeTwitterCard(cardType) {
|
|
13
|
+
return cardType === "summary_large_image" ? "summary_large_image" : "summary";
|
|
14
|
+
}
|
|
15
|
+
function normalizeOpenGraphType(type) {
|
|
16
|
+
if (type === "article" || type === "profile" || type === "video.other") {
|
|
17
|
+
return type;
|
|
18
|
+
}
|
|
19
|
+
return "website";
|
|
20
|
+
}
|
|
21
|
+
function formatWeaverseNextSeoMetadata(seo) {
|
|
22
|
+
let index = seo?.robots?.index !== false;
|
|
23
|
+
let follow = seo?.robots?.follow !== false;
|
|
24
|
+
let metadata = {
|
|
25
|
+
robots: { index, follow }
|
|
26
|
+
};
|
|
27
|
+
if (!seo) {
|
|
28
|
+
return metadata;
|
|
29
|
+
}
|
|
30
|
+
if (seo.title) {
|
|
31
|
+
metadata.title = seo.title;
|
|
32
|
+
}
|
|
33
|
+
if (seo.description) {
|
|
34
|
+
metadata.description = seo.description;
|
|
35
|
+
}
|
|
36
|
+
if (seo.keywords) {
|
|
37
|
+
metadata.keywords = seo.keywords;
|
|
38
|
+
}
|
|
39
|
+
if (seo.canonicalUrl) {
|
|
40
|
+
metadata.alternates = { canonical: seo.canonicalUrl };
|
|
41
|
+
}
|
|
42
|
+
let openGraph = seo.openGraph;
|
|
43
|
+
if (hasOpenGraphContent(openGraph)) {
|
|
44
|
+
metadata.openGraph = {
|
|
45
|
+
title: openGraph?.title,
|
|
46
|
+
description: openGraph?.description,
|
|
47
|
+
images: openGraph?.image ? [openGraph.image] : void 0,
|
|
48
|
+
type: normalizeOpenGraphType(openGraph?.type)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
let twitter = seo.twitter;
|
|
52
|
+
if (hasTwitterContent(twitter)) {
|
|
53
|
+
metadata.twitter = {
|
|
54
|
+
card: normalizeTwitterCard(twitter?.cardType),
|
|
55
|
+
title: twitter?.title,
|
|
56
|
+
description: twitter?.description,
|
|
57
|
+
images: twitter?.image ? [twitter.image] : void 0
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
return metadata;
|
|
61
|
+
}
|
|
62
|
+
function getWeaverseNextSeoMetadata(data) {
|
|
63
|
+
if (!data) {
|
|
64
|
+
return formatWeaverseNextSeoMetadata(null);
|
|
65
|
+
}
|
|
66
|
+
let page = "items" in data && "id" in data ? data : data.page ?? null;
|
|
67
|
+
return formatWeaverseNextSeoMetadata(page?.seo ?? null);
|
|
68
|
+
}
|
|
69
|
+
|
|
3
70
|
// src/server/configs.ts
|
|
4
71
|
var DEFAULT_WEAVERSE_HOST = "https://studio.weaverse.io";
|
|
5
72
|
var DEFAULT_WEAVERSE_API_BASE = "https://api.weaverse.io";
|
|
@@ -71,7 +138,6 @@ function getWeaverseNextConfigs(context, options = {}) {
|
|
|
71
138
|
envProjectId: readEnv(env, "WEAVERSE_PROJECT_ID") || "",
|
|
72
139
|
weaverseHost,
|
|
73
140
|
weaverseApiBase,
|
|
74
|
-
weaverseApiKey: lastParam(searchParams, "weaverseApiKey") || readEnv(env, "WEAVERSE_API_KEY") || "",
|
|
75
141
|
weaverseVersion: lastParam(searchParams, "weaverseVersion") || options.weaverseVersion || "",
|
|
76
142
|
isDesignMode,
|
|
77
143
|
isPreviewMode,
|
|
@@ -84,8 +150,84 @@ function getWeaverseNextConfigs(context, options = {}) {
|
|
|
84
150
|
};
|
|
85
151
|
}
|
|
86
152
|
|
|
153
|
+
// src/request-info.ts
|
|
154
|
+
function toUrl2(value) {
|
|
155
|
+
return typeof value === "string" ? new URL(value, "http://localhost") : value;
|
|
156
|
+
}
|
|
157
|
+
function getSearchParamsFromContext(context) {
|
|
158
|
+
if (context?.searchParams) {
|
|
159
|
+
return new URLSearchParams(context.searchParams);
|
|
160
|
+
}
|
|
161
|
+
if (context?.url) {
|
|
162
|
+
let url = toUrl2(context.url);
|
|
163
|
+
return new URLSearchParams(url.searchParams);
|
|
164
|
+
}
|
|
165
|
+
return new URLSearchParams();
|
|
166
|
+
}
|
|
167
|
+
function withPathPrefix(pathname, i18n) {
|
|
168
|
+
let raw = typeof i18n?.pathPrefix === "string" ? i18n.pathPrefix : "";
|
|
169
|
+
let segments = raw.split("/").filter(Boolean);
|
|
170
|
+
let prefix = segments.length > 0 ? `/${segments.join("/")}` : "";
|
|
171
|
+
if (prefix === "" || pathname === prefix || pathname.startsWith(`${prefix}/`)) {
|
|
172
|
+
return pathname;
|
|
173
|
+
}
|
|
174
|
+
return pathname === "/" ? prefix : `${prefix}${pathname}`;
|
|
175
|
+
}
|
|
176
|
+
function getPathnameFromContext(context) {
|
|
177
|
+
if (context?.pathname) {
|
|
178
|
+
return withPathPrefix(context.pathname, context.i18n);
|
|
179
|
+
}
|
|
180
|
+
if (context?.url) {
|
|
181
|
+
let url = toUrl2(context.url);
|
|
182
|
+
return withPathPrefix(url.pathname || "/", context.i18n);
|
|
183
|
+
}
|
|
184
|
+
return "/";
|
|
185
|
+
}
|
|
186
|
+
function coerceQueryValue(value) {
|
|
187
|
+
if (value === "true") {
|
|
188
|
+
return true;
|
|
189
|
+
}
|
|
190
|
+
if (value === "false") {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
return value;
|
|
194
|
+
}
|
|
195
|
+
function toQueryRecord(searchParams) {
|
|
196
|
+
let queries = {};
|
|
197
|
+
for (let [key, value] of searchParams.entries()) {
|
|
198
|
+
queries[key] = coerceQueryValue(value);
|
|
199
|
+
}
|
|
200
|
+
return queries;
|
|
201
|
+
}
|
|
202
|
+
var TRANSIENT_STUDIO_PARAMS = /* @__PURE__ */ new Set([
|
|
203
|
+
"weaverseDraftItem",
|
|
204
|
+
// Legacy name from the original design-mode draft-item spike. Keep it out of
|
|
205
|
+
// runtime requestInfo too, in case an older Builder bundle is in front of a
|
|
206
|
+
// newer Next storefront.
|
|
207
|
+
"__weaverseDraftItem"
|
|
208
|
+
]);
|
|
209
|
+
function getRequestInfoSearchParams(context) {
|
|
210
|
+
let searchParams = new URLSearchParams(getSearchParamsFromContext(context));
|
|
211
|
+
for (let key of TRANSIENT_STUDIO_PARAMS) {
|
|
212
|
+
searchParams.delete(key);
|
|
213
|
+
}
|
|
214
|
+
return searchParams;
|
|
215
|
+
}
|
|
216
|
+
function buildWeaverseNextRequestInfo(context) {
|
|
217
|
+
let searchParams = getRequestInfoSearchParams(context);
|
|
218
|
+
let search = searchParams.toString();
|
|
219
|
+
return {
|
|
220
|
+
pathname: getPathnameFromContext(context),
|
|
221
|
+
search: search ? `?${search}` : "",
|
|
222
|
+
queries: toQueryRecord(searchParams),
|
|
223
|
+
...context?.i18n ? { i18n: context.i18n } : {},
|
|
224
|
+
...context?.pageType ? { pageType: context.pageType } : {},
|
|
225
|
+
...context?.handle ? { handle: context.handle } : {}
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
|
|
87
229
|
// src/server/normalize-page-url.ts
|
|
88
|
-
var KEPT_PARAM_RE = /^(?:__revisionId|isDesignMode|weaverse)/;
|
|
230
|
+
var KEPT_PARAM_RE = /^(?:__revisionId|__weaverseDraftItem|isDesignMode|weaverse)/;
|
|
89
231
|
var DATA_SUFFIX = ".data";
|
|
90
232
|
function normalizeNextPageUrl(url) {
|
|
91
233
|
let parsed;
|
|
@@ -109,12 +251,49 @@ function normalizeNextPageUrl(url) {
|
|
|
109
251
|
}
|
|
110
252
|
function resolveRequestUrl(context) {
|
|
111
253
|
if (context?.url) {
|
|
112
|
-
|
|
254
|
+
let raw = String(context.url);
|
|
255
|
+
let url = new URL(raw, "http://localhost");
|
|
256
|
+
let pathname2 = withPathPrefix(url.pathname, context.i18n);
|
|
257
|
+
if (pathname2 === url.pathname) {
|
|
258
|
+
return raw;
|
|
259
|
+
}
|
|
260
|
+
url.pathname = pathname2;
|
|
261
|
+
return url.toString();
|
|
113
262
|
}
|
|
114
|
-
let pathname = context?.pathname || "/";
|
|
263
|
+
let pathname = withPathPrefix(context?.pathname || "/", context?.i18n);
|
|
115
264
|
let search = context?.searchParams ? new URLSearchParams(context.searchParams).toString() : "";
|
|
116
265
|
return `http://localhost${pathname}${search ? `?${search}` : ""}`;
|
|
117
266
|
}
|
|
267
|
+
var DENIED_ROUTE_CONTEXT_PARAMS = [
|
|
268
|
+
"weaverseprojectid",
|
|
269
|
+
"weaversehost",
|
|
270
|
+
"weaverseapikey",
|
|
271
|
+
"weaverseapibase",
|
|
272
|
+
"weaversepublicapibase",
|
|
273
|
+
"weaverseversion",
|
|
274
|
+
"projectid",
|
|
275
|
+
"weaversedraftitem",
|
|
276
|
+
"__weaversedraftitem",
|
|
277
|
+
"_rsc"
|
|
278
|
+
];
|
|
279
|
+
var ROUTE_CONTEXT_I18N_KEYS = [
|
|
280
|
+
"country",
|
|
281
|
+
"label",
|
|
282
|
+
"language",
|
|
283
|
+
"locale",
|
|
284
|
+
"pathPrefix"
|
|
285
|
+
];
|
|
286
|
+
function sanitizeRouteContextSearch(search) {
|
|
287
|
+
let params = new URLSearchParams(search);
|
|
288
|
+
let denied = new Set(DENIED_ROUTE_CONTEXT_PARAMS);
|
|
289
|
+
for (let key of [...new Set(params.keys())]) {
|
|
290
|
+
if (denied.has(key.toLowerCase())) {
|
|
291
|
+
params.delete(key);
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
let serialized = params.toString();
|
|
295
|
+
return serialized ? `?${serialized}` : "";
|
|
296
|
+
}
|
|
118
297
|
|
|
119
298
|
// src/utils.ts
|
|
120
299
|
function generateDataFromSchema(schema) {
|
|
@@ -134,6 +313,211 @@ function generateDataFromSchema(schema) {
|
|
|
134
313
|
return data;
|
|
135
314
|
}
|
|
136
315
|
|
|
316
|
+
// src/server/revalidate-handler.ts
|
|
317
|
+
var NO_STORE_HEADERS = {
|
|
318
|
+
"Content-Type": "application/json",
|
|
319
|
+
"Cache-Control": "no-store"
|
|
320
|
+
};
|
|
321
|
+
var STATUS_OK = 200;
|
|
322
|
+
var STATUS_BAD_REQUEST = 400;
|
|
323
|
+
var STATUS_NOT_FOUND = 404;
|
|
324
|
+
var STATUS_UNPROCESSABLE = 422;
|
|
325
|
+
var STATUS_SERVER_ERROR = 500;
|
|
326
|
+
var MAX_PATHNAME_LENGTH = 2048;
|
|
327
|
+
var MAX_SEARCH_LENGTH = 8192;
|
|
328
|
+
var MAX_HANDLE_LENGTH = 512;
|
|
329
|
+
var MAX_I18N_FIELD_LENGTH = 256;
|
|
330
|
+
var CONTROL_CHAR_PATTERN = /[\u0000-\u001F\u007F]/;
|
|
331
|
+
function isValidPathname(pathname) {
|
|
332
|
+
if (!pathname || pathname.length > MAX_PATHNAME_LENGTH) {
|
|
333
|
+
return false;
|
|
334
|
+
}
|
|
335
|
+
if (pathname[0] !== "/" || pathname.startsWith("//")) {
|
|
336
|
+
return false;
|
|
337
|
+
}
|
|
338
|
+
if (pathname.includes("\\") || pathname.includes("?")) {
|
|
339
|
+
return false;
|
|
340
|
+
}
|
|
341
|
+
if (pathname.includes("#") || CONTROL_CHAR_PATTERN.test(pathname)) {
|
|
342
|
+
return false;
|
|
343
|
+
}
|
|
344
|
+
return true;
|
|
345
|
+
}
|
|
346
|
+
function isPlainObject(value) {
|
|
347
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
348
|
+
return false;
|
|
349
|
+
}
|
|
350
|
+
let proto = Object.getPrototypeOf(value);
|
|
351
|
+
return proto === Object.prototype || proto === null;
|
|
352
|
+
}
|
|
353
|
+
function sanitizeRouteContextI18n(input) {
|
|
354
|
+
if (input === void 0) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (!isPlainObject(input)) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
let source = input;
|
|
361
|
+
let allowed = new Set(ROUTE_CONTEXT_I18N_KEYS);
|
|
362
|
+
for (let key of Object.keys(source)) {
|
|
363
|
+
if (!allowed.has(key)) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
let result = {};
|
|
368
|
+
for (let key of ROUTE_CONTEXT_I18N_KEYS) {
|
|
369
|
+
let value = source[key];
|
|
370
|
+
if (value === void 0) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
if (typeof value !== "string" || value.length > MAX_I18N_FIELD_LENGTH) {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
result[key] = value;
|
|
377
|
+
}
|
|
378
|
+
return Object.keys(result).length ? result : void 0;
|
|
379
|
+
}
|
|
380
|
+
function reconstructRouteContext(request, routeContext) {
|
|
381
|
+
if (typeof routeContext !== "object" || routeContext === null || Array.isArray(routeContext)) {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
let { pathname, search, handle, pageType, i18n } = routeContext;
|
|
385
|
+
if (typeof pathname !== "string" || !isValidPathname(pathname)) {
|
|
386
|
+
return null;
|
|
387
|
+
}
|
|
388
|
+
if (typeof search !== "string" || search.length > MAX_SEARCH_LENGTH) {
|
|
389
|
+
return null;
|
|
390
|
+
}
|
|
391
|
+
let rawSearch = search;
|
|
392
|
+
if (rawSearch.length && !rawSearch.startsWith("?")) {
|
|
393
|
+
return null;
|
|
394
|
+
}
|
|
395
|
+
let sanitizedI18n = sanitizeRouteContextI18n(i18n);
|
|
396
|
+
if (sanitizedI18n === null) {
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
let resolvedPageType;
|
|
400
|
+
if (pageType !== void 0) {
|
|
401
|
+
let parsed = schema.PageTypeSchema.safeParse(pageType);
|
|
402
|
+
if (!parsed.success) {
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
resolvedPageType = parsed.data;
|
|
406
|
+
}
|
|
407
|
+
let resolvedHandle;
|
|
408
|
+
if (handle !== void 0) {
|
|
409
|
+
if (typeof handle !== "string" || !handle || handle.length > MAX_HANDLE_LENGTH) {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
resolvedHandle = handle;
|
|
413
|
+
}
|
|
414
|
+
let endpointUrl = new URL(request.url);
|
|
415
|
+
let routeUrl = new URL(endpointUrl.origin);
|
|
416
|
+
routeUrl.pathname = pathname;
|
|
417
|
+
routeUrl.search = sanitizeRouteContextSearch(rawSearch);
|
|
418
|
+
let canonicalPathname = routeUrl.pathname;
|
|
419
|
+
let searchParams = routeUrl.searchParams;
|
|
420
|
+
let lastParam2 = (key) => {
|
|
421
|
+
let values = searchParams.getAll(key);
|
|
422
|
+
return values.length ? values.at(-1) : void 0;
|
|
423
|
+
};
|
|
424
|
+
return {
|
|
425
|
+
pathname: canonicalPathname,
|
|
426
|
+
searchParams,
|
|
427
|
+
url: routeUrl,
|
|
428
|
+
// Headers come from the actual same-origin POST, never its JSON body.
|
|
429
|
+
headers: new Headers(request.headers),
|
|
430
|
+
...sanitizedI18n ? { i18n: sanitizedI18n } : {},
|
|
431
|
+
...resolvedPageType ? { pageType: resolvedPageType } : {},
|
|
432
|
+
...resolvedHandle ? { handle: resolvedHandle } : {},
|
|
433
|
+
isDesignMode: lastParam2("isDesignMode") === "true",
|
|
434
|
+
isPreviewMode: lastParam2("isPreviewMode") === "true",
|
|
435
|
+
isRevisionPreview: searchParams.has("__revisionId"),
|
|
436
|
+
sectionType: lastParam2("sectionType") || void 0
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
function json(body, status) {
|
|
440
|
+
return new Response(JSON.stringify(body), {
|
|
441
|
+
status,
|
|
442
|
+
headers: NO_STORE_HEADERS
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
function parseDraftItem(payload) {
|
|
446
|
+
if (typeof payload !== "object" || payload === null) {
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
let draftItem = payload.draftItem;
|
|
450
|
+
if (typeof draftItem !== "object" || draftItem === null) {
|
|
451
|
+
return null;
|
|
452
|
+
}
|
|
453
|
+
let { id, type } = draftItem;
|
|
454
|
+
if (typeof id !== "string" || !id || typeof type !== "string" || !type) {
|
|
455
|
+
return null;
|
|
456
|
+
}
|
|
457
|
+
return draftItem;
|
|
458
|
+
}
|
|
459
|
+
function createWeaverseNextRevalidateHandler(config) {
|
|
460
|
+
return {
|
|
461
|
+
POST: async (request) => {
|
|
462
|
+
let payload;
|
|
463
|
+
try {
|
|
464
|
+
payload = await request.json();
|
|
465
|
+
} catch {
|
|
466
|
+
return json({ error: "invalid-payload" }, STATUS_BAD_REQUEST);
|
|
467
|
+
}
|
|
468
|
+
let draftItem = parseDraftItem(payload);
|
|
469
|
+
if (!draftItem) {
|
|
470
|
+
return json({ error: "invalid-payload" }, STATUS_BAD_REQUEST);
|
|
471
|
+
}
|
|
472
|
+
let requestContext;
|
|
473
|
+
let body = payload;
|
|
474
|
+
if (Object.hasOwn(body, "routeContext")) {
|
|
475
|
+
let reconstructed = reconstructRouteContext(request, body.routeContext);
|
|
476
|
+
if (!reconstructed) {
|
|
477
|
+
return json({ error: "invalid-route-context" }, STATUS_BAD_REQUEST);
|
|
478
|
+
}
|
|
479
|
+
requestContext = reconstructed;
|
|
480
|
+
}
|
|
481
|
+
let client;
|
|
482
|
+
try {
|
|
483
|
+
client = await config.getClient(request, requestContext);
|
|
484
|
+
} catch (error) {
|
|
485
|
+
console.error("\u274C Revalidate handler getClient failed.", error);
|
|
486
|
+
return json({ error: "client-init-failed" }, STATUS_SERVER_ERROR);
|
|
487
|
+
}
|
|
488
|
+
let component = client.components.find(
|
|
489
|
+
(candidate) => candidate?.schema?.type === draftItem.type
|
|
490
|
+
);
|
|
491
|
+
if (!component) {
|
|
492
|
+
return json({ error: "unknown-component-type" }, STATUS_NOT_FOUND);
|
|
493
|
+
}
|
|
494
|
+
if (typeof component.loader !== "function") {
|
|
495
|
+
return json({ error: "missing-loader" }, STATUS_UNPROCESSABLE);
|
|
496
|
+
}
|
|
497
|
+
try {
|
|
498
|
+
let loaderData = await component.loader({
|
|
499
|
+
data: {
|
|
500
|
+
...generateDataFromSchema(component.schema),
|
|
501
|
+
...draftItem.data
|
|
502
|
+
},
|
|
503
|
+
weaverse: client,
|
|
504
|
+
context: client.requestContext,
|
|
505
|
+
commerce: client.commerce
|
|
506
|
+
});
|
|
507
|
+
return json({ loaderData: loaderData ?? null }, STATUS_OK);
|
|
508
|
+
} catch (error) {
|
|
509
|
+
console.error(
|
|
510
|
+
"\u274C Item loader revalidation failed.",
|
|
511
|
+
draftItem.type,
|
|
512
|
+
draftItem.id,
|
|
513
|
+
error
|
|
514
|
+
);
|
|
515
|
+
return json({ error: "loader-failed" }, STATUS_SERVER_ERROR);
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
|
|
137
521
|
// src/loader.ts
|
|
138
522
|
function isItemNode(node) {
|
|
139
523
|
return typeof node === "object" && node !== null && typeof node.type === "string";
|
|
@@ -211,61 +595,11 @@ async function runWeaverseComponentLoaders(args) {
|
|
|
211
595
|
return data;
|
|
212
596
|
}
|
|
213
597
|
|
|
214
|
-
// src/request-info.ts
|
|
215
|
-
function toUrl2(value) {
|
|
216
|
-
return typeof value === "string" ? new URL(value, "http://localhost") : value;
|
|
217
|
-
}
|
|
218
|
-
function getSearchParamsFromContext(context) {
|
|
219
|
-
if (context?.searchParams) {
|
|
220
|
-
return new URLSearchParams(context.searchParams);
|
|
221
|
-
}
|
|
222
|
-
if (context?.url) {
|
|
223
|
-
let url = toUrl2(context.url);
|
|
224
|
-
return new URLSearchParams(url.searchParams);
|
|
225
|
-
}
|
|
226
|
-
return new URLSearchParams();
|
|
227
|
-
}
|
|
228
|
-
function getPathnameFromContext(context) {
|
|
229
|
-
if (context?.pathname) {
|
|
230
|
-
return context.pathname;
|
|
231
|
-
}
|
|
232
|
-
if (context?.url) {
|
|
233
|
-
let url = toUrl2(context.url);
|
|
234
|
-
return url.pathname || "/";
|
|
235
|
-
}
|
|
236
|
-
return "/";
|
|
237
|
-
}
|
|
238
|
-
function coerceQueryValue(value) {
|
|
239
|
-
if (value === "true") {
|
|
240
|
-
return true;
|
|
241
|
-
}
|
|
242
|
-
if (value === "false") {
|
|
243
|
-
return false;
|
|
244
|
-
}
|
|
245
|
-
return value;
|
|
246
|
-
}
|
|
247
|
-
function toQueryRecord(searchParams) {
|
|
248
|
-
let queries = {};
|
|
249
|
-
for (let [key, value] of searchParams.entries()) {
|
|
250
|
-
queries[key] = coerceQueryValue(value);
|
|
251
|
-
}
|
|
252
|
-
return queries;
|
|
253
|
-
}
|
|
254
|
-
function buildWeaverseNextRequestInfo(context) {
|
|
255
|
-
let searchParams = getSearchParamsFromContext(context);
|
|
256
|
-
let search = searchParams.toString();
|
|
257
|
-
return {
|
|
258
|
-
pathname: getPathnameFromContext(context),
|
|
259
|
-
search: search ? `?${search}` : "",
|
|
260
|
-
queries: toQueryRecord(searchParams),
|
|
261
|
-
...context?.i18n ? { i18n: context.i18n } : {}
|
|
262
|
-
};
|
|
263
|
-
}
|
|
264
|
-
|
|
265
598
|
// src/server/server-client.ts
|
|
266
599
|
var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
|
|
267
600
|
var RANDOM_ID_RADIX = 36;
|
|
268
601
|
var RANDOM_ID_SLICE_START = 2;
|
|
602
|
+
var MAX_CUSTOM_PAGE_PAGES = 100;
|
|
269
603
|
var JSON_HEADERS = {
|
|
270
604
|
"Content-Type": "application/json",
|
|
271
605
|
Accept: "application/json",
|
|
@@ -280,6 +614,25 @@ function generateUuid() {
|
|
|
280
614
|
}
|
|
281
615
|
return `id-${Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START)}`;
|
|
282
616
|
}
|
|
617
|
+
function normalizeWeaverseNextPageAssignment(input) {
|
|
618
|
+
if (!input || typeof input !== "object") {
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
621
|
+
let { projectId, type, handle, locale, meta } = input;
|
|
622
|
+
if (typeof projectId !== "string" || typeof type !== "string" || typeof handle !== "string") {
|
|
623
|
+
return;
|
|
624
|
+
}
|
|
625
|
+
let normalized = {
|
|
626
|
+
projectId,
|
|
627
|
+
type,
|
|
628
|
+
handle,
|
|
629
|
+
locale: typeof locale === "string" ? locale : ""
|
|
630
|
+
};
|
|
631
|
+
if (meta && typeof meta === "object") {
|
|
632
|
+
normalized.meta = meta;
|
|
633
|
+
}
|
|
634
|
+
return normalized;
|
|
635
|
+
}
|
|
283
636
|
var NextServerClient = class {
|
|
284
637
|
components;
|
|
285
638
|
commerce;
|
|
@@ -399,6 +752,59 @@ var NextServerClient = class {
|
|
|
399
752
|
clearTimeout(timeoutId);
|
|
400
753
|
}
|
|
401
754
|
};
|
|
755
|
+
_buildCustomPagesUrl(projectId, options, cursor) {
|
|
756
|
+
let params = new URLSearchParams();
|
|
757
|
+
if (options.locale) {
|
|
758
|
+
params.set("locale", options.locale);
|
|
759
|
+
}
|
|
760
|
+
if (options.limit) {
|
|
761
|
+
params.set("limit", String(options.limit));
|
|
762
|
+
}
|
|
763
|
+
if (cursor) {
|
|
764
|
+
params.set("cursor", cursor);
|
|
765
|
+
}
|
|
766
|
+
let qs = params.toString();
|
|
767
|
+
return `${this._baseConfigs.weaverseApiBase}/api/public/v1/projects/${projectId}/custom-pages${qs ? `?${qs}` : ""}`;
|
|
768
|
+
}
|
|
769
|
+
/**
|
|
770
|
+
* Fetch all published custom pages for sitemap generation. Mirrors Hydrogen's
|
|
771
|
+
* helper but uses Next's fetch cache knobs (`revalidate` / `tags`). It returns
|
|
772
|
+
* accumulated results on partial pagination failure so a single API hiccup
|
|
773
|
+
* does not break sitemap generation entirely.
|
|
774
|
+
*/
|
|
775
|
+
fetchCustomPages = async (options = {}) => {
|
|
776
|
+
let projectId = await this.resolveProjectId();
|
|
777
|
+
let entries = [];
|
|
778
|
+
if (!projectId) {
|
|
779
|
+
console.warn(
|
|
780
|
+
"[WeaverseNext] Failed to fetch custom pages: missing projectId"
|
|
781
|
+
);
|
|
782
|
+
return entries;
|
|
783
|
+
}
|
|
784
|
+
let cursor = null;
|
|
785
|
+
for (let page = 0; page < MAX_CUSTOM_PAGE_PAGES; page += 1) {
|
|
786
|
+
let url = this._buildCustomPagesUrl(projectId, options, cursor);
|
|
787
|
+
try {
|
|
788
|
+
let result = await this.fetchWithCache(url, {
|
|
789
|
+
revalidate: options.revalidate,
|
|
790
|
+
tags: options.tags
|
|
791
|
+
});
|
|
792
|
+
entries.push(...result.data ?? []);
|
|
793
|
+
if (!result.nextCursor) {
|
|
794
|
+
return entries;
|
|
795
|
+
}
|
|
796
|
+
cursor = result.nextCursor;
|
|
797
|
+
} catch (error) {
|
|
798
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
799
|
+
console.warn(
|
|
800
|
+
entries.length === 0 ? `[WeaverseNext] Failed to fetch custom pages: ${message}` : `[WeaverseNext] Custom pages pagination interrupted: ${message}`
|
|
801
|
+
);
|
|
802
|
+
return entries;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
console.warn("[WeaverseNext] Custom pages pagination cap reached");
|
|
806
|
+
return entries;
|
|
807
|
+
};
|
|
402
808
|
_generateFallbackPage(message) {
|
|
403
809
|
let rootId = generateUuid();
|
|
404
810
|
return {
|
|
@@ -526,7 +932,9 @@ var NextServerClient = class {
|
|
|
526
932
|
this._assertNoPageError(payload);
|
|
527
933
|
let page = payload.page;
|
|
528
934
|
let project = payload.project;
|
|
529
|
-
let pageAssignment =
|
|
935
|
+
let pageAssignment = normalizeWeaverseNextPageAssignment(
|
|
936
|
+
payload.pageAssignment
|
|
937
|
+
);
|
|
530
938
|
page ??= this._generateFallbackPage(
|
|
531
939
|
'<div style="text-align: center;">Please add new section to start.</div>'
|
|
532
940
|
);
|
|
@@ -582,12 +990,58 @@ var NextServerClient = class {
|
|
|
582
990
|
return null;
|
|
583
991
|
}
|
|
584
992
|
};
|
|
993
|
+
/**
|
|
994
|
+
* Resolve the request locale (e.g. `fr-ca`) used for merchant overrides.
|
|
995
|
+
* Unlike Hydrogen — which defaults to `en`/`us` because a Hydrogen
|
|
996
|
+
* storefront always has an i18n context — Next apps may not thread one
|
|
997
|
+
* through, so a missing language or country means "no explicit locale" and
|
|
998
|
+
* the translation fetch is skipped rather than guessed.
|
|
999
|
+
*/
|
|
1000
|
+
_resolveOverridesLocale() {
|
|
1001
|
+
let i18n = this.requestContext?.i18n;
|
|
1002
|
+
let language = typeof i18n?.language === "string" ? i18n.language.trim() : "";
|
|
1003
|
+
let country = typeof i18n?.country === "string" ? i18n.country.trim() : "";
|
|
1004
|
+
if (!(language && country)) {
|
|
1005
|
+
return;
|
|
1006
|
+
}
|
|
1007
|
+
return `${language.toLowerCase()}-${country.toLowerCase()}`;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Fetch locale-specific static-text overrides from the translation API.
|
|
1011
|
+
* Ported from Hydrogen's `fetchMerchantOverrides`: skipped entirely when the
|
|
1012
|
+
* theme has no `i18n` schema (nothing translatable) or when the request has
|
|
1013
|
+
* no explicit locale, and never allowed to fail theme settings.
|
|
1014
|
+
*/
|
|
1015
|
+
async _fetchMerchantOverrides(projectId, options) {
|
|
1016
|
+
let { weaverseHost } = this._baseConfigs;
|
|
1017
|
+
if (!(asThemeSchema(this.themeSchema)?.i18n && projectId && weaverseHost)) {
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
let locale = this._resolveOverridesLocale();
|
|
1021
|
+
if (!locale) {
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1024
|
+
let url = `${weaverseHost}/api/translation/static?projectId=${projectId}&locale=${locale}`;
|
|
1025
|
+
try {
|
|
1026
|
+
let overrides = await this.fetchWithCache(url, {
|
|
1027
|
+
method: "GET",
|
|
1028
|
+
headers: { Accept: "application/json" },
|
|
1029
|
+
revalidate: options.revalidate,
|
|
1030
|
+
tags: options.tags
|
|
1031
|
+
});
|
|
1032
|
+
return typeof overrides === "object" && overrides !== null ? overrides : void 0;
|
|
1033
|
+
} catch (error) {
|
|
1034
|
+
console.warn(
|
|
1035
|
+
"[WeaverseNext] Unable to load merchant overrides, using theme defaults:",
|
|
1036
|
+
error instanceof Error ? error.message : String(error)
|
|
1037
|
+
);
|
|
1038
|
+
return;
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
585
1041
|
loadThemeSettings = async (optionsInput = {}) => {
|
|
586
1042
|
let options = optionsInput;
|
|
587
1043
|
let themeSchema = asThemeSchema(this.themeSchema);
|
|
588
|
-
let defaultThemeSettings = generateDataFromSchema(
|
|
589
|
-
this.themeSchema
|
|
590
|
-
);
|
|
1044
|
+
let defaultThemeSettings = generateDataFromSchema(this.themeSchema);
|
|
591
1045
|
let staticContent = themeSchema?.i18n?.staticContent;
|
|
592
1046
|
try {
|
|
593
1047
|
let projectId = await this.resolveProjectId();
|
|
@@ -596,16 +1050,16 @@ var NextServerClient = class {
|
|
|
596
1050
|
}
|
|
597
1051
|
let { isDesignMode } = this._baseConfigs;
|
|
598
1052
|
let url = `${this._baseConfigs.weaverseApiBase}/api/public/project_configs`;
|
|
599
|
-
let result = await
|
|
600
|
-
url,
|
|
601
|
-
{
|
|
1053
|
+
let [result, merchantOverrides] = await Promise.all([
|
|
1054
|
+
this.fetchWithCache(url, {
|
|
602
1055
|
method: "POST",
|
|
603
1056
|
body: JSON.stringify({ projectId, isDesignMode }),
|
|
604
1057
|
headers: JSON_HEADERS,
|
|
605
1058
|
revalidate: options.revalidate,
|
|
606
1059
|
tags: options.tags
|
|
607
|
-
}
|
|
608
|
-
|
|
1060
|
+
}),
|
|
1061
|
+
this._fetchMerchantOverrides(projectId, options)
|
|
1062
|
+
]);
|
|
609
1063
|
if (typeof result !== "object" || result === null) {
|
|
610
1064
|
result = { theme: defaultThemeSettings };
|
|
611
1065
|
}
|
|
@@ -619,21 +1073,25 @@ var NextServerClient = class {
|
|
|
619
1073
|
if (staticContent) {
|
|
620
1074
|
result.staticContent = staticContent;
|
|
621
1075
|
}
|
|
1076
|
+
if (merchantOverrides) {
|
|
1077
|
+
result.merchantOverrides = merchantOverrides;
|
|
1078
|
+
}
|
|
622
1079
|
if (isDesignMode) {
|
|
1080
|
+
let serializableSchema = themeSchema ? {
|
|
1081
|
+
...themeSchema,
|
|
1082
|
+
settings: themeSchema.settings?.map((group) => ({
|
|
1083
|
+
...group,
|
|
1084
|
+
inputs: group?.inputs?.map(
|
|
1085
|
+
(inputItem) => typeof inputItem?.condition === "function" ? {
|
|
1086
|
+
...inputItem,
|
|
1087
|
+
condition: inputItem.condition.toString()
|
|
1088
|
+
} : inputItem
|
|
1089
|
+
)
|
|
1090
|
+
}))
|
|
1091
|
+
} : void 0;
|
|
623
1092
|
result = {
|
|
624
1093
|
...result,
|
|
625
|
-
schema:
|
|
626
|
-
...themeSchema,
|
|
627
|
-
settings: themeSchema.settings?.map((group) => ({
|
|
628
|
-
...group,
|
|
629
|
-
inputs: group?.inputs?.map(
|
|
630
|
-
(inputItem) => typeof inputItem?.condition === "function" ? {
|
|
631
|
-
...inputItem,
|
|
632
|
-
condition: inputItem.condition.toString()
|
|
633
|
-
} : inputItem
|
|
634
|
-
)
|
|
635
|
-
}))
|
|
636
|
-
} : void 0,
|
|
1094
|
+
schema: serializableSchema,
|
|
637
1095
|
publicEnv: this._baseConfigs.publicEnv
|
|
638
1096
|
};
|
|
639
1097
|
}
|
|
@@ -654,8 +1112,11 @@ function createWeaverseNextServerClient(config) {
|
|
|
654
1112
|
return new NextServerClient(config);
|
|
655
1113
|
}
|
|
656
1114
|
|
|
1115
|
+
exports.createWeaverseNextRevalidateHandler = createWeaverseNextRevalidateHandler;
|
|
657
1116
|
exports.createWeaverseNextServerClient = createWeaverseNextServerClient;
|
|
1117
|
+
exports.formatWeaverseNextSeoMetadata = formatWeaverseNextSeoMetadata;
|
|
658
1118
|
exports.getWeaverseNextConfigs = getWeaverseNextConfigs;
|
|
1119
|
+
exports.getWeaverseNextSeoMetadata = getWeaverseNextSeoMetadata;
|
|
659
1120
|
exports.normalizeNextPageUrl = normalizeNextPageUrl;
|
|
660
1121
|
exports.resolveRequestUrl = resolveRequestUrl;
|
|
661
1122
|
//# sourceMappingURL=server.js.map
|