@weaverse/next 0.1.0-alpha.1 → 0.1.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { q as WeaverseNextRequestContext, a as WeaverseNextBaseConfigs, v as WeaverseNextServerClientConfig, u as WeaverseNextServerClient } from './types-DvEeLX6L.mjs';
2
- export { b as WeaverseNextCacheConfig, j as WeaverseNextConfigs, k as WeaverseNextFetchOptions, p as WeaverseNextProjectId, w as WeaverseNextServerLoadPageInput, y as WeaverseNextThemeSettingsOptions, z as WeaverseNextThemeSettingsResponse } from './types-DvEeLX6L.mjs';
3
- import '@weaverse/react';
1
+ import { x as WeaverseNextRequestContext, e as WeaverseNextBaseConfigs, C as WeaverseNextServerClient, k as WeaverseNextComponentData, D as WeaverseNextServerClientConfig } from './seo-CgO21rLg.mjs';
2
+ export { f as WeaverseNextCacheConfig, n as WeaverseNextConfigs, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, q as WeaverseNextFetchOptions, w as WeaverseNextProjectId, B as WeaverseNextSeoMetadata, E as WeaverseNextServerLoadPageInput, H as WeaverseNextThemeSettingsOptions, I as WeaverseNextThemeSettingsResponse, Q as formatWeaverseNextSeoMetadata, R as getWeaverseNextSeoMetadata } from './seo-CgO21rLg.mjs';
4
3
  import '@weaverse/schema';
4
+ import '@weaverse/react';
5
5
  import 'react';
6
6
 
7
7
  interface ResolveConfigsOptions {
@@ -38,6 +38,45 @@ declare function normalizeNextPageUrl(url: string): string;
38
38
  */
39
39
  declare function resolveRequestUrl(context?: WeaverseNextRequestContext): string;
40
40
 
41
+ interface WeaverseNextRevalidateHandlerConfig {
42
+ /**
43
+ * Reuse the app's server-client factory so the loader runs with the same
44
+ * component registry and commerce (storefront) context as page loads.
45
+ */
46
+ getClient: (request: Request) => Promise<WeaverseNextServerClient> | WeaverseNextServerClient;
47
+ }
48
+ /** POST body accepted by the revalidate route. */
49
+ interface WeaverseNextRevalidateRequestBody {
50
+ draftItem: WeaverseNextComponentData;
51
+ }
52
+ /**
53
+ * Create the Studio per-item revalidation route handler.
54
+ *
55
+ * Studio design-mode edits to loader-backed inputs (e.g. resource pickers) need
56
+ * fresh server loader data for a single item. Re-running it through
57
+ * `router.refresh()` re-applies the whole RSC tree — and the draft-item query
58
+ * rewrite changes the App Router page segment key, remounting the page and
59
+ * resetting scroll. This handler runs just the edited component's `loader`
60
+ * with the unsaved draft settings and returns the payload for an in-place
61
+ * client update (see the `2026-07-02--next-item-revalidation` spec).
62
+ *
63
+ * Security: only registered component types are executable, the handler never
64
+ * persists anything, and responses are `no-store`. Exposure is equivalent to
65
+ * the existing `weaverseDraftItem` URL param, which already lets any visitor
66
+ * run design-mode loaders with arbitrary draft settings.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // app/api/weaverse/revalidate/route.ts
71
+ * export const { POST } = createWeaverseNextRevalidateHandler({
72
+ * getClient: () => getWeaverseServerClient(Promise.resolve({})),
73
+ * })
74
+ * ```
75
+ */
76
+ declare function createWeaverseNextRevalidateHandler(config: WeaverseNextRevalidateHandlerConfig): {
77
+ POST: (request: Request) => Promise<Response>;
78
+ };
79
+
41
80
  /**
42
81
  * Create a server-side {@link WeaverseNextServerClient} for Next.js App Router
43
82
  * routes / server components.
@@ -57,4 +96,4 @@ declare function resolveRequestUrl(context?: WeaverseNextRequestContext): string
57
96
  */
58
97
  declare function createWeaverseNextServerClient(config: WeaverseNextServerClientConfig): WeaverseNextServerClient;
59
98
 
60
- export { WeaverseNextBaseConfigs, WeaverseNextServerClient, WeaverseNextServerClientConfig, createWeaverseNextServerClient, getWeaverseNextConfigs, normalizeNextPageUrl, resolveRequestUrl };
99
+ export { WeaverseNextBaseConfigs, type WeaverseNextRevalidateHandlerConfig, type WeaverseNextRevalidateRequestBody, WeaverseNextServerClient, WeaverseNextServerClientConfig, createWeaverseNextRevalidateHandler, createWeaverseNextServerClient, getWeaverseNextConfigs, normalizeNextPageUrl, resolveRequestUrl };
package/dist/server.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { q as WeaverseNextRequestContext, a as WeaverseNextBaseConfigs, v as WeaverseNextServerClientConfig, u as WeaverseNextServerClient } from './types-DvEeLX6L.js';
2
- export { b as WeaverseNextCacheConfig, j as WeaverseNextConfigs, k as WeaverseNextFetchOptions, p as WeaverseNextProjectId, w as WeaverseNextServerLoadPageInput, y as WeaverseNextThemeSettingsOptions, z as WeaverseNextThemeSettingsResponse } from './types-DvEeLX6L.js';
3
- import '@weaverse/react';
1
+ import { x as WeaverseNextRequestContext, e as WeaverseNextBaseConfigs, C as WeaverseNextServerClient, k as WeaverseNextComponentData, D as WeaverseNextServerClientConfig } from './seo-CgO21rLg.js';
2
+ export { f as WeaverseNextCacheConfig, n as WeaverseNextConfigs, o as WeaverseNextCustomPageEntry, p as WeaverseNextFetchCustomPagesOptions, q as WeaverseNextFetchOptions, w as WeaverseNextProjectId, B as WeaverseNextSeoMetadata, E as WeaverseNextServerLoadPageInput, H as WeaverseNextThemeSettingsOptions, I as WeaverseNextThemeSettingsResponse, Q as formatWeaverseNextSeoMetadata, R as getWeaverseNextSeoMetadata } from './seo-CgO21rLg.js';
4
3
  import '@weaverse/schema';
4
+ import '@weaverse/react';
5
5
  import 'react';
6
6
 
7
7
  interface ResolveConfigsOptions {
@@ -38,6 +38,45 @@ declare function normalizeNextPageUrl(url: string): string;
38
38
  */
39
39
  declare function resolveRequestUrl(context?: WeaverseNextRequestContext): string;
40
40
 
41
+ interface WeaverseNextRevalidateHandlerConfig {
42
+ /**
43
+ * Reuse the app's server-client factory so the loader runs with the same
44
+ * component registry and commerce (storefront) context as page loads.
45
+ */
46
+ getClient: (request: Request) => Promise<WeaverseNextServerClient> | WeaverseNextServerClient;
47
+ }
48
+ /** POST body accepted by the revalidate route. */
49
+ interface WeaverseNextRevalidateRequestBody {
50
+ draftItem: WeaverseNextComponentData;
51
+ }
52
+ /**
53
+ * Create the Studio per-item revalidation route handler.
54
+ *
55
+ * Studio design-mode edits to loader-backed inputs (e.g. resource pickers) need
56
+ * fresh server loader data for a single item. Re-running it through
57
+ * `router.refresh()` re-applies the whole RSC tree — and the draft-item query
58
+ * rewrite changes the App Router page segment key, remounting the page and
59
+ * resetting scroll. This handler runs just the edited component's `loader`
60
+ * with the unsaved draft settings and returns the payload for an in-place
61
+ * client update (see the `2026-07-02--next-item-revalidation` spec).
62
+ *
63
+ * Security: only registered component types are executable, the handler never
64
+ * persists anything, and responses are `no-store`. Exposure is equivalent to
65
+ * the existing `weaverseDraftItem` URL param, which already lets any visitor
66
+ * run design-mode loaders with arbitrary draft settings.
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * // app/api/weaverse/revalidate/route.ts
71
+ * export const { POST } = createWeaverseNextRevalidateHandler({
72
+ * getClient: () => getWeaverseServerClient(Promise.resolve({})),
73
+ * })
74
+ * ```
75
+ */
76
+ declare function createWeaverseNextRevalidateHandler(config: WeaverseNextRevalidateHandlerConfig): {
77
+ POST: (request: Request) => Promise<Response>;
78
+ };
79
+
41
80
  /**
42
81
  * Create a server-side {@link WeaverseNextServerClient} for Next.js App Router
43
82
  * routes / server components.
@@ -57,4 +96,4 @@ declare function resolveRequestUrl(context?: WeaverseNextRequestContext): string
57
96
  */
58
97
  declare function createWeaverseNextServerClient(config: WeaverseNextServerClientConfig): WeaverseNextServerClient;
59
98
 
60
- export { WeaverseNextBaseConfigs, WeaverseNextServerClient, WeaverseNextServerClientConfig, createWeaverseNextServerClient, getWeaverseNextConfigs, normalizeNextPageUrl, resolveRequestUrl };
99
+ export { WeaverseNextBaseConfigs, type WeaverseNextRevalidateHandlerConfig, type WeaverseNextRevalidateRequestBody, WeaverseNextServerClient, WeaverseNextServerClientConfig, createWeaverseNextRevalidateHandler, createWeaverseNextServerClient, getWeaverseNextConfigs, normalizeNextPageUrl, resolveRequestUrl };
package/dist/server.js CHANGED
@@ -1,5 +1,61 @@
1
1
  'use strict';
2
2
 
3
+ // src/seo.ts
4
+ function hasOpenGraphContent(seo) {
5
+ return Boolean(seo?.title || seo?.description || seo?.image || seo?.type);
6
+ }
7
+ function hasTwitterContent(seo) {
8
+ return Boolean(seo?.title || seo?.description || seo?.image || seo?.cardType);
9
+ }
10
+ function formatWeaverseNextSeoMetadata(seo) {
11
+ let index = seo?.robots?.index !== false;
12
+ let follow = seo?.robots?.follow !== false;
13
+ let metadata = {
14
+ robots: { index, follow }
15
+ };
16
+ if (!seo) {
17
+ return metadata;
18
+ }
19
+ if (seo.title) {
20
+ metadata.title = seo.title;
21
+ }
22
+ if (seo.description) {
23
+ metadata.description = seo.description;
24
+ }
25
+ if (seo.keywords) {
26
+ metadata.keywords = seo.keywords;
27
+ }
28
+ if (seo.canonicalUrl) {
29
+ metadata.alternates = { canonical: seo.canonicalUrl };
30
+ }
31
+ let openGraph = seo.openGraph;
32
+ if (hasOpenGraphContent(openGraph)) {
33
+ metadata.openGraph = {
34
+ title: openGraph?.title,
35
+ description: openGraph?.description,
36
+ images: openGraph?.image ? [openGraph.image] : void 0,
37
+ type: openGraph?.type || "website"
38
+ };
39
+ }
40
+ let twitter = seo.twitter;
41
+ if (hasTwitterContent(twitter)) {
42
+ metadata.twitter = {
43
+ card: twitter?.cardType || "summary",
44
+ title: twitter?.title,
45
+ description: twitter?.description,
46
+ images: twitter?.image ? [twitter.image] : void 0
47
+ };
48
+ }
49
+ return metadata;
50
+ }
51
+ function getWeaverseNextSeoMetadata(data) {
52
+ if (!data) {
53
+ return formatWeaverseNextSeoMetadata(null);
54
+ }
55
+ let page = "items" in data && "id" in data ? data : data.page ?? null;
56
+ return formatWeaverseNextSeoMetadata(page?.seo ?? null);
57
+ }
58
+
3
59
  // src/server/configs.ts
4
60
  var DEFAULT_WEAVERSE_HOST = "https://studio.weaverse.io";
5
61
  var DEFAULT_WEAVERSE_API_BASE = "https://api.weaverse.io";
@@ -85,7 +141,7 @@ function getWeaverseNextConfigs(context, options = {}) {
85
141
  }
86
142
 
87
143
  // src/server/normalize-page-url.ts
88
- var KEPT_PARAM_RE = /^(?:__revisionId|isDesignMode|weaverse)/;
144
+ var KEPT_PARAM_RE = /^(?:__revisionId|__weaverseDraftItem|isDesignMode|weaverse)/;
89
145
  var DATA_SUFFIX = ".data";
90
146
  function normalizeNextPageUrl(url) {
91
147
  let parsed;
@@ -134,6 +190,89 @@ function generateDataFromSchema(schema) {
134
190
  return data;
135
191
  }
136
192
 
193
+ // src/server/revalidate-handler.ts
194
+ var NO_STORE_HEADERS = {
195
+ "Content-Type": "application/json",
196
+ "Cache-Control": "no-store"
197
+ };
198
+ var STATUS_OK = 200;
199
+ var STATUS_BAD_REQUEST = 400;
200
+ var STATUS_NOT_FOUND = 404;
201
+ var STATUS_UNPROCESSABLE = 422;
202
+ var STATUS_SERVER_ERROR = 500;
203
+ function json(body, status) {
204
+ return new Response(JSON.stringify(body), {
205
+ status,
206
+ headers: NO_STORE_HEADERS
207
+ });
208
+ }
209
+ function parseDraftItem(payload) {
210
+ if (typeof payload !== "object" || payload === null) {
211
+ return null;
212
+ }
213
+ let draftItem = payload.draftItem;
214
+ if (typeof draftItem !== "object" || draftItem === null) {
215
+ return null;
216
+ }
217
+ let { id, type } = draftItem;
218
+ if (typeof id !== "string" || !id || typeof type !== "string" || !type) {
219
+ return null;
220
+ }
221
+ return draftItem;
222
+ }
223
+ function createWeaverseNextRevalidateHandler(config) {
224
+ return {
225
+ POST: async (request) => {
226
+ let payload;
227
+ try {
228
+ payload = await request.json();
229
+ } catch {
230
+ return json({ error: "invalid-payload" }, STATUS_BAD_REQUEST);
231
+ }
232
+ let draftItem = parseDraftItem(payload);
233
+ if (!draftItem) {
234
+ return json({ error: "invalid-payload" }, STATUS_BAD_REQUEST);
235
+ }
236
+ let client;
237
+ try {
238
+ client = await config.getClient(request);
239
+ } catch (error) {
240
+ console.error("\u274C Revalidate handler getClient failed.", error);
241
+ return json({ error: "client-init-failed" }, STATUS_SERVER_ERROR);
242
+ }
243
+ let component = client.components.find(
244
+ (candidate) => candidate?.schema?.type === draftItem.type
245
+ );
246
+ if (!component) {
247
+ return json({ error: "unknown-component-type" }, STATUS_NOT_FOUND);
248
+ }
249
+ if (typeof component.loader !== "function") {
250
+ return json({ error: "missing-loader" }, STATUS_UNPROCESSABLE);
251
+ }
252
+ try {
253
+ let loaderData = await component.loader({
254
+ data: {
255
+ ...generateDataFromSchema(component.schema),
256
+ ...draftItem.data
257
+ },
258
+ weaverse: client,
259
+ context: client.requestContext,
260
+ commerce: client.commerce
261
+ });
262
+ return json({ loaderData: loaderData ?? null }, STATUS_OK);
263
+ } catch (error) {
264
+ console.error(
265
+ "\u274C Item loader revalidation failed.",
266
+ draftItem.type,
267
+ draftItem.id,
268
+ error
269
+ );
270
+ return json({ error: "loader-failed" }, STATUS_SERVER_ERROR);
271
+ }
272
+ }
273
+ };
274
+ }
275
+
137
276
  // src/loader.ts
138
277
  function isItemNode(node) {
139
278
  return typeof node === "object" && node !== null && typeof node.type === "string";
@@ -251,8 +390,22 @@ function toQueryRecord(searchParams) {
251
390
  }
252
391
  return queries;
253
392
  }
393
+ var TRANSIENT_STUDIO_PARAMS = /* @__PURE__ */ new Set([
394
+ "weaverseDraftItem",
395
+ // Legacy name from the original design-mode draft-item spike. Keep it out of
396
+ // runtime requestInfo too, in case an older Builder bundle is in front of a
397
+ // newer Next storefront.
398
+ "__weaverseDraftItem"
399
+ ]);
400
+ function getRequestInfoSearchParams(context) {
401
+ let searchParams = new URLSearchParams(getSearchParamsFromContext(context));
402
+ for (let key of TRANSIENT_STUDIO_PARAMS) {
403
+ searchParams.delete(key);
404
+ }
405
+ return searchParams;
406
+ }
254
407
  function buildWeaverseNextRequestInfo(context) {
255
- let searchParams = getSearchParamsFromContext(context);
408
+ let searchParams = getRequestInfoSearchParams(context);
256
409
  let search = searchParams.toString();
257
410
  return {
258
411
  pathname: getPathnameFromContext(context),
@@ -266,6 +419,7 @@ function buildWeaverseNextRequestInfo(context) {
266
419
  var DEFAULT_FETCH_TIMEOUT_MS = 1e4;
267
420
  var RANDOM_ID_RADIX = 36;
268
421
  var RANDOM_ID_SLICE_START = 2;
422
+ var MAX_CUSTOM_PAGE_PAGES = 100;
269
423
  var JSON_HEADERS = {
270
424
  "Content-Type": "application/json",
271
425
  Accept: "application/json",
@@ -280,6 +434,25 @@ function generateUuid() {
280
434
  }
281
435
  return `id-${Math.random().toString(RANDOM_ID_RADIX).slice(RANDOM_ID_SLICE_START)}`;
282
436
  }
437
+ function normalizeWeaverseNextPageAssignment(input) {
438
+ if (!input || typeof input !== "object") {
439
+ return;
440
+ }
441
+ let { projectId, type, handle, locale, meta } = input;
442
+ if (typeof projectId !== "string" || typeof type !== "string" || typeof handle !== "string") {
443
+ return;
444
+ }
445
+ let normalized = {
446
+ projectId,
447
+ type,
448
+ handle,
449
+ locale: typeof locale === "string" ? locale : ""
450
+ };
451
+ if (meta && typeof meta === "object") {
452
+ normalized.meta = meta;
453
+ }
454
+ return normalized;
455
+ }
283
456
  var NextServerClient = class {
284
457
  components;
285
458
  commerce;
@@ -399,6 +572,59 @@ var NextServerClient = class {
399
572
  clearTimeout(timeoutId);
400
573
  }
401
574
  };
575
+ _buildCustomPagesUrl(projectId, options, cursor) {
576
+ let params = new URLSearchParams();
577
+ if (options.locale) {
578
+ params.set("locale", options.locale);
579
+ }
580
+ if (options.limit) {
581
+ params.set("limit", String(options.limit));
582
+ }
583
+ if (cursor) {
584
+ params.set("cursor", cursor);
585
+ }
586
+ let qs = params.toString();
587
+ return `${this._baseConfigs.weaverseApiBase}/api/public/v1/projects/${projectId}/custom-pages${qs ? `?${qs}` : ""}`;
588
+ }
589
+ /**
590
+ * Fetch all published custom pages for sitemap generation. Mirrors Hydrogen's
591
+ * helper but uses Next's fetch cache knobs (`revalidate` / `tags`). It returns
592
+ * accumulated results on partial pagination failure so a single API hiccup
593
+ * does not break sitemap generation entirely.
594
+ */
595
+ fetchCustomPages = async (options = {}) => {
596
+ let projectId = await this.resolveProjectId();
597
+ let entries = [];
598
+ if (!projectId) {
599
+ console.warn(
600
+ "[WeaverseNext] Failed to fetch custom pages: missing projectId"
601
+ );
602
+ return entries;
603
+ }
604
+ let cursor = null;
605
+ for (let page = 0; page < MAX_CUSTOM_PAGE_PAGES; page += 1) {
606
+ let url = this._buildCustomPagesUrl(projectId, options, cursor);
607
+ try {
608
+ let result = await this.fetchWithCache(url, {
609
+ revalidate: options.revalidate,
610
+ tags: options.tags
611
+ });
612
+ entries.push(...result.data ?? []);
613
+ if (!result.nextCursor) {
614
+ return entries;
615
+ }
616
+ cursor = result.nextCursor;
617
+ } catch (error) {
618
+ let message = error instanceof Error ? error.message : String(error);
619
+ console.warn(
620
+ entries.length === 0 ? `[WeaverseNext] Failed to fetch custom pages: ${message}` : `[WeaverseNext] Custom pages pagination interrupted: ${message}`
621
+ );
622
+ return entries;
623
+ }
624
+ }
625
+ console.warn("[WeaverseNext] Custom pages pagination cap reached");
626
+ return entries;
627
+ };
402
628
  _generateFallbackPage(message) {
403
629
  let rootId = generateUuid();
404
630
  return {
@@ -526,7 +752,9 @@ var NextServerClient = class {
526
752
  this._assertNoPageError(payload);
527
753
  let page = payload.page;
528
754
  let project = payload.project;
529
- let pageAssignment = payload.pageAssignment;
755
+ let pageAssignment = normalizeWeaverseNextPageAssignment(
756
+ payload.pageAssignment
757
+ );
530
758
  page ??= this._generateFallbackPage(
531
759
  '<div style="text-align: center;">Please add new section to start.</div>'
532
760
  );
@@ -585,9 +813,7 @@ var NextServerClient = class {
585
813
  loadThemeSettings = async (optionsInput = {}) => {
586
814
  let options = optionsInput;
587
815
  let themeSchema = asThemeSchema(this.themeSchema);
588
- let defaultThemeSettings = generateDataFromSchema(
589
- this.themeSchema
590
- );
816
+ let defaultThemeSettings = generateDataFromSchema(this.themeSchema);
591
817
  let staticContent = themeSchema?.i18n?.staticContent;
592
818
  try {
593
819
  let projectId = await this.resolveProjectId();
@@ -620,20 +846,21 @@ var NextServerClient = class {
620
846
  result.staticContent = staticContent;
621
847
  }
622
848
  if (isDesignMode) {
849
+ let serializableSchema = themeSchema ? {
850
+ ...themeSchema,
851
+ settings: themeSchema.settings?.map((group) => ({
852
+ ...group,
853
+ inputs: group?.inputs?.map(
854
+ (inputItem) => typeof inputItem?.condition === "function" ? {
855
+ ...inputItem,
856
+ condition: inputItem.condition.toString()
857
+ } : inputItem
858
+ )
859
+ }))
860
+ } : void 0;
623
861
  result = {
624
862
  ...result,
625
- schema: themeSchema ? {
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,
863
+ schema: serializableSchema,
637
864
  publicEnv: this._baseConfigs.publicEnv
638
865
  };
639
866
  }
@@ -654,8 +881,11 @@ function createWeaverseNextServerClient(config) {
654
881
  return new NextServerClient(config);
655
882
  }
656
883
 
884
+ exports.createWeaverseNextRevalidateHandler = createWeaverseNextRevalidateHandler;
657
885
  exports.createWeaverseNextServerClient = createWeaverseNextServerClient;
886
+ exports.formatWeaverseNextSeoMetadata = formatWeaverseNextSeoMetadata;
658
887
  exports.getWeaverseNextConfigs = getWeaverseNextConfigs;
888
+ exports.getWeaverseNextSeoMetadata = getWeaverseNextSeoMetadata;
659
889
  exports.normalizeNextPageUrl = normalizeNextPageUrl;
660
890
  exports.resolveRequestUrl = resolveRequestUrl;
661
891
  //# sourceMappingURL=server.js.map