@weaverse/next 0.1.0-alpha.8 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/README.md +155 -73
  2. package/dist/{chunk-6PMZ77RA.mjs → chunk-LH6AAEIK.mjs} +115 -8
  3. package/dist/chunk-LH6AAEIK.mjs.map +1 -0
  4. package/dist/index.js +260 -30
  5. package/dist/index.js.map +1 -1
  6. package/dist/index.mjs +167 -46
  7. package/dist/index.mjs.map +1 -1
  8. package/dist/server.js +321 -91
  9. package/dist/server.js.map +1 -1
  10. package/dist/server.mjs +205 -28
  11. package/dist/server.mjs.map +1 -1
  12. package/dist/types/client.d.ts +16 -0
  13. package/dist/types/client.d.ts.map +1 -0
  14. package/dist/types/hooks.d.ts +20 -0
  15. package/dist/types/hooks.d.ts.map +1 -0
  16. package/dist/types/index.d.ts +34 -0
  17. package/dist/types/index.d.ts.map +1 -0
  18. package/dist/types/item.d.ts +60 -0
  19. package/dist/types/item.d.ts.map +1 -0
  20. package/dist/types/loader.d.ts +25 -0
  21. package/dist/types/loader.d.ts.map +1 -0
  22. package/dist/types/main.d.ts +11 -0
  23. package/dist/types/main.d.ts.map +1 -0
  24. package/dist/types/provider.d.ts +82 -0
  25. package/dist/types/provider.d.ts.map +1 -0
  26. package/dist/types/registry.d.ts +15 -0
  27. package/dist/types/registry.d.ts.map +1 -0
  28. package/dist/types/renderer.d.ts +21 -0
  29. package/dist/types/renderer.d.ts.map +1 -0
  30. package/dist/types/request-info.d.ts +19 -0
  31. package/dist/types/request-info.d.ts.map +1 -0
  32. package/dist/types/revalidate-item.d.ts +82 -0
  33. package/dist/types/revalidate-item.d.ts.map +1 -0
  34. package/dist/types/root-provider.d.ts +62 -0
  35. package/dist/types/root-provider.d.ts.map +1 -0
  36. package/dist/types/runtime.d.ts +113 -0
  37. package/dist/types/runtime.d.ts.map +1 -0
  38. package/dist/types/seo.d.ts +55 -0
  39. package/dist/types/seo.d.ts.map +1 -0
  40. package/dist/types/server/configs.d.ts +27 -0
  41. package/dist/types/server/configs.d.ts.map +1 -0
  42. package/dist/types/server/normalize-page-url.d.ts +19 -0
  43. package/dist/types/server/normalize-page-url.d.ts.map +1 -0
  44. package/dist/types/server/revalidate-handler.d.ts +55 -0
  45. package/dist/types/server/revalidate-handler.d.ts.map +1 -0
  46. package/dist/types/server/server-client.d.ts +21 -0
  47. package/dist/types/server/server-client.d.ts.map +1 -0
  48. package/dist/types/server.d.ts +19 -0
  49. package/dist/types/server.d.ts.map +1 -0
  50. package/dist/types/studio-bridge.d.ts +16 -0
  51. package/dist/types/studio-bridge.d.ts.map +1 -0
  52. package/dist/types/studio-connect.d.ts +27 -0
  53. package/dist/types/studio-connect.d.ts.map +1 -0
  54. package/dist/types/studio-router.d.ts +50 -0
  55. package/dist/types/studio-router.d.ts.map +1 -0
  56. package/dist/types/studio-script-src.d.ts +12 -0
  57. package/dist/types/studio-script-src.d.ts.map +1 -0
  58. package/dist/types/theme-settings-store.d.ts +18 -0
  59. package/dist/types/theme-settings-store.d.ts.map +1 -0
  60. package/dist/types/translation-context.d.ts +156 -0
  61. package/dist/types/translation-context.d.ts.map +1 -0
  62. package/dist/types/translation-store.d.ts +44 -0
  63. package/dist/types/translation-store.d.ts.map +1 -0
  64. package/dist/types/types.d.ts +665 -0
  65. package/dist/types/types.d.ts.map +1 -0
  66. package/dist/types/use-weaverse-next-studio.d.ts +34 -0
  67. package/dist/types/use-weaverse-next-studio.d.ts.map +1 -0
  68. package/dist/types/utils.d.ts +12 -0
  69. package/dist/types/utils.d.ts.map +1 -0
  70. package/package.json +12 -8
  71. package/src/client.ts +102 -0
  72. package/src/hooks.ts +50 -0
  73. package/src/index.ts +153 -0
  74. package/src/item.ts +167 -0
  75. package/src/loader.ts +135 -0
  76. package/src/main.tsx +45 -0
  77. package/src/provider.tsx +225 -0
  78. package/src/registry.ts +63 -0
  79. package/src/renderer.tsx +100 -0
  80. package/src/request-info.ts +124 -0
  81. package/src/revalidate-item.ts +211 -0
  82. package/src/root-provider.tsx +182 -0
  83. package/src/runtime.ts +555 -0
  84. package/src/seo.ts +157 -0
  85. package/src/server/configs.ts +178 -0
  86. package/src/server/normalize-page-url.ts +73 -0
  87. package/src/server/revalidate-handler.ts +357 -0
  88. package/src/server/server-client.ts +728 -0
  89. package/src/server.ts +67 -0
  90. package/src/studio-bridge.tsx +82 -0
  91. package/src/studio-connect.tsx +88 -0
  92. package/src/studio-router.ts +85 -0
  93. package/src/studio-script-src.ts +128 -0
  94. package/src/theme-settings-store.ts +47 -0
  95. package/src/translation-context.tsx +299 -0
  96. package/src/translation-store.ts +69 -0
  97. package/src/types.ts +753 -0
  98. package/src/use-weaverse-next-studio.tsx +106 -0
  99. package/src/utils.ts +37 -0
  100. package/dist/chunk-6PMZ77RA.mjs.map +0 -1
  101. package/dist/index.d.mts +0 -517
  102. package/dist/index.d.ts +0 -517
  103. package/dist/seo-CpN6tC36.d.mts +0 -477
  104. package/dist/seo-CpN6tC36.d.ts +0 -477
  105. package/dist/server.d.mts +0 -99
  106. package/dist/server.d.ts +0 -99
package/dist/index.js CHANGED
@@ -27,6 +27,24 @@ function generateDataFromSchema(schema) {
27
27
  }
28
28
 
29
29
  // src/item.ts
30
+ function flattenItemData(update) {
31
+ let { data, ...rest } = update;
32
+ if (!(data && typeof data === "object" && !Array.isArray(data))) {
33
+ return rest;
34
+ }
35
+ return { ...data, ...rest };
36
+ }
37
+ var deferredItemUpdates = null;
38
+ function collectDeferredItemUpdates(create) {
39
+ let previousQueue = deferredItemUpdates;
40
+ let queue = /* @__PURE__ */ new Set();
41
+ deferredItemUpdates = queue;
42
+ try {
43
+ return [create(), [...queue]];
44
+ } finally {
45
+ deferredItemUpdates = previousQueue;
46
+ }
47
+ }
30
48
  var WeaverseNextItem = class extends react.WeaverseItemStore {
31
49
  /**
32
50
  * Cached merged snapshot (base `_store` + translations). Reset whenever the
@@ -36,12 +54,47 @@ var WeaverseNextItem = class extends react.WeaverseItemStore {
36
54
  _cachedSnapshot = null;
37
55
  _snapshotStoreRef = null;
38
56
  _snapshotTranslationRef = null;
57
+ /** Create an item store from serialized component data and its runtime. */
39
58
  constructor(initialData, weaverse) {
40
59
  super(initialData, weaverse);
41
- let { data, ...rest } = initialData;
42
60
  let schemaData = generateDataFromSchema(this.Element?.schema);
43
- Object.assign(this._store, schemaData, data, rest);
61
+ Object.assign(this._store, schemaData, flattenItemData(initialData));
44
62
  }
63
+ /**
64
+ * Flatten nested `data` on updates exactly like the constructor does. Core's
65
+ * `initProject()` calls `setData(item)` when a new runtime serves a page
66
+ * whose item instances already exist (e.g. locale/client navigation).
67
+ *
68
+ * A complete serialized item (it carries `id` and `type`; core's
69
+ * `initProject()` always passes one) replaces the store the way the
70
+ * constructor builds it: the schema defaults of the item's own `type` — the
71
+ * Builder can replace a section in place, keeping its id — then the item's
72
+ * settings. A payload omits a setting — or the whole optional `data` — when
73
+ * its value equals the schema default, so merging into the previous store
74
+ * would keep the previous locale's value visible. Partial updates still
75
+ * merge. Either way the `_store` ref changes, which invalidates the memoized
76
+ * snapshot below. The subscriber emit is queued instead of fired when a
77
+ * render-phase deferral is active (see `collectDeferredItemUpdates`).
78
+ */
79
+ setData = (update) => {
80
+ if ("id" in update && "type" in update) {
81
+ let { data, type } = update;
82
+ let schema = this.weaverse.elementRegistry.get(type)?.schema;
83
+ this._store = {
84
+ ...generateDataFromSchema(schema),
85
+ ...data === void 0 ? {} : { data },
86
+ ...flattenItemData(update)
87
+ };
88
+ } else {
89
+ this.data = flattenItemData(update);
90
+ }
91
+ if (deferredItemUpdates) {
92
+ deferredItemUpdates.add(this);
93
+ } else {
94
+ this.triggerUpdate();
95
+ }
96
+ return this.data;
97
+ };
45
98
  /**
46
99
  * Overlay item-level translations onto the base store when the runtime is in
47
100
  * translation mode. Mirrors Hydrogen's `WeaverseHydrogenItem.getSnapShot()`:
@@ -283,18 +336,24 @@ var useThemeText = useTranslation;
283
336
 
284
337
  // src/translation-store.ts
285
338
  var TranslationStore = class {
339
+ /** Current flat translation overrides keyed by dot path. */
286
340
  overrides = {};
287
341
  listeners = /* @__PURE__ */ new Set();
342
+ /** Replace every override and notify subscribers. */
288
343
  setOverrides = (overrides) => {
289
344
  this.overrides = { ...overrides };
290
345
  this.emit();
291
346
  };
347
+ /** Merge changed overrides into the current values and notify subscribers. */
292
348
  updateOverrides = (newOverrides) => {
293
349
  this.overrides = { ...this.overrides, ...newOverrides };
294
350
  this.emit();
295
351
  };
352
+ /** Return the current client-side override snapshot. */
296
353
  getSnapshot = () => this.overrides;
354
+ /** Return the override snapshot used during server rendering. */
297
355
  getServerSnapshot = () => this.overrides;
356
+ /** Subscribe to override changes and return an unsubscribe function. */
298
357
  subscribe = (callback) => {
299
358
  this.listeners.add(callback);
300
359
  return () => {
@@ -565,13 +624,22 @@ function getSearchParamsFromContext(context) {
565
624
  }
566
625
  return new URLSearchParams();
567
626
  }
627
+ function withPathPrefix(pathname, i18n) {
628
+ let raw = typeof i18n?.pathPrefix === "string" ? i18n.pathPrefix : "";
629
+ let segments = raw.split("/").filter(Boolean);
630
+ let prefix = segments.length > 0 ? `/${segments.join("/")}` : "";
631
+ if (prefix === "" || pathname === prefix || pathname.startsWith(`${prefix}/`)) {
632
+ return pathname;
633
+ }
634
+ return pathname === "/" ? prefix : `${prefix}${pathname}`;
635
+ }
568
636
  function getPathnameFromContext(context) {
569
637
  if (context?.pathname) {
570
- return context.pathname;
638
+ return withPathPrefix(context.pathname, context.i18n);
571
639
  }
572
640
  if (context?.url) {
573
641
  let url = toUrl(context.url);
574
- return url.pathname || "/";
642
+ return withPathPrefix(url.pathname || "/", context.i18n);
575
643
  }
576
644
  return "/";
577
645
  }
@@ -612,7 +680,9 @@ function buildWeaverseNextRequestInfo(context) {
612
680
  pathname: getPathnameFromContext(context),
613
681
  search: search ? `?${search}` : "",
614
682
  queries: toQueryRecord(searchParams),
615
- ...context?.i18n ? { i18n: context.i18n } : {}
683
+ ...context?.i18n ? { i18n: context.i18n } : {},
684
+ ...context?.pageType ? { pageType: context.pageType } : {},
685
+ ...context?.handle ? { handle: context.handle } : {}
616
686
  };
617
687
  }
618
688
 
@@ -629,6 +699,12 @@ function getConfigString(configs, key) {
629
699
  let value = configs?.[key];
630
700
  return typeof value === "string" ? value : void 0;
631
701
  }
702
+ function resolveModeFlag(config, key) {
703
+ return config.client?.requestContext?.[key] === true || config.data.configs?.[key] === true;
704
+ }
705
+ function resolveSectionType(config) {
706
+ return config.client?.requestContext?.sectionType || getConfigString(config.data.configs, "sectionType") || void 0;
707
+ }
632
708
  function getRecordString(record, key) {
633
709
  let value = record?.[key];
634
710
  return typeof value === "string" ? value : void 0;
@@ -665,12 +741,30 @@ function registerRuntime(runtime) {
665
741
  runtimeWindow.__weaverses[runtime.pageId] = runtime;
666
742
  runtimeWindow.__weaverse = runtime;
667
743
  }
744
+ function rebindPageItemsToRuntime(runtime) {
745
+ let items = runtime.data?.items;
746
+ if (!items) {
747
+ return;
748
+ }
749
+ for (let { id } of items) {
750
+ let instance = runtime.itemInstances.get(id);
751
+ if (instance && instance.weaverse !== runtime) {
752
+ instance.weaverse = runtime;
753
+ }
754
+ }
755
+ }
668
756
  var WeaverseNextRuntime = class extends react.Weaverse {
757
+ /** Stable ID of the page owned by this runtime. */
669
758
  pageId;
759
+ /** Mutable callbacks and stores consumed by the Studio bridge. */
670
760
  internal;
761
+ /** Path, query, and locale metadata for Studio navigation. */
671
762
  requestInfo;
763
+ /** Whether this runtime renders a component preview. */
672
764
  isPreviewMode;
765
+ /** Whether this runtime renders a saved revision. */
673
766
  isRevisionPreview;
767
+ /** Component type rendered in section preview mode. */
674
768
  sectionType;
675
769
  // ─── Item-level translation sidecar (design mode only) ─────────────
676
770
  /**
@@ -679,29 +773,52 @@ var WeaverseNextRuntime = class extends react.Weaverse {
679
773
  * components, so translations render without mutating the base `_store`.
680
774
  */
681
775
  translationMap = {};
776
+ /** Locale associated with the item-level translation sidecar. */
682
777
  translationLocale = String();
778
+ /** Weaverse language ID used when saving translation changes. */
683
779
  translationLanguageId = String();
780
+ /**
781
+ * Fresh page data captured while React was rendering. Runtime reuse happens
782
+ * inside the renderer's render phase (`useMemo`), where applying it through
783
+ * `setProjectData()` would emit item updates to `useSyncExternalStore`
784
+ * subscribers mid-render. The renderer applies it post-commit via
785
+ * `flushRenderPhaseUpdates()`. Never set on design-mode runtimes — the live
786
+ * Studio tree owns the page data there.
787
+ */
788
+ pendingProjectData;
789
+ /**
790
+ * Reused item instances whose data was refreshed while this runtime was
791
+ * constructed during render (core `initProject()` calls `setData()` on
792
+ * them). Their data is already fresh; only the subscriber notification was
793
+ * deferred to `flushRenderPhaseUpdates()`.
794
+ */
795
+ pendingItemUpdates = [];
796
+ /** Create a browser runtime from a loaded page and its request context. */
684
797
  constructor(config) {
685
798
  let { client, data } = config;
686
799
  let page = getRenderablePage(data);
687
800
  let configs = data.configs;
688
801
  let requestContext = client?.requestContext;
802
+ let isDesignMode = resolveModeFlag(config, "isDesignMode");
803
+ let isPreviewMode = resolveModeFlag(config, "isPreviewMode");
804
+ let isRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
805
+ let sectionType = resolveSectionType(config);
689
806
  let projectId = resolveProjectId(client, data, page.id);
690
807
  ensureNextItemConstructor();
691
808
  super({
692
809
  projectId,
693
810
  data: page,
694
- isDesignMode: requestContext?.isDesignMode ?? false,
811
+ isDesignMode,
695
812
  weaverseHost: getConfigString(configs, "weaverseHost"),
696
813
  weaverseVersion: getConfigString(configs, "weaverseVersion")
697
814
  });
698
815
  this.pageId = page.id;
699
816
  this.dataContext = resolveDataContext(config);
700
817
  this.requestInfo = buildWeaverseNextRequestInfo(requestContext);
701
- this.isDesignMode = requestContext?.isDesignMode ?? false;
702
- this.isPreviewMode = requestContext?.isPreviewMode ?? false;
703
- this.isRevisionPreview = requestContext?.isRevisionPreview ?? false;
704
- this.sectionType = requestContext?.sectionType;
818
+ this.isDesignMode = isDesignMode;
819
+ this.isPreviewMode = isPreviewMode;
820
+ this.isRevisionPreview = isRevisionPreview;
821
+ this.sectionType = sectionType;
705
822
  let translationStore = config.translationStore ?? new TranslationStore();
706
823
  this.internal = {
707
824
  merchantOverrides: config.merchantOverrides,
@@ -804,6 +921,27 @@ var WeaverseNextRuntime = class extends react.Weaverse {
804
921
  this.extractTranslationSidecar();
805
922
  this.initProject();
806
923
  };
924
+ /**
925
+ * Apply updates deferred off the render phase: swap in any pending page data
926
+ * captured on runtime reuse, then notify items whose data was refreshed
927
+ * during construction. The renderer calls this from a layout effect right
928
+ * after commit, so subscribers re-render before paint (no content flash) and
929
+ * without React's setState-in-render warning.
930
+ */
931
+ flushRenderPhaseUpdates = () => {
932
+ let pendingData = this.pendingProjectData;
933
+ if (pendingData) {
934
+ this.pendingProjectData = void 0;
935
+ this.setProjectData(pendingData);
936
+ }
937
+ let pendingItems = this.pendingItemUpdates;
938
+ if (pendingItems.length > 0) {
939
+ this.pendingItemUpdates = [];
940
+ for (let item of pendingItems) {
941
+ item.triggerUpdate();
942
+ }
943
+ }
944
+ };
807
945
  };
808
946
  function createWeaverseNextRuntime(config) {
809
947
  let requestInfo = buildWeaverseNextRequestInfo(config.client?.requestContext);
@@ -812,20 +950,26 @@ function createWeaverseNextRuntime(config) {
812
950
  let existing = runtimeWindow?.__weaverses?.[page.id];
813
951
  let requestKey = getRuntimeKey(page.id, requestInfo);
814
952
  if (existing?.__weaverseNextRequestKey === requestKey) {
815
- let nextIsDesignMode = config.client?.requestContext?.isDesignMode ?? false;
816
- if (!(existing.isDesignMode || nextIsDesignMode)) {
817
- existing.setProjectData(page);
953
+ let configs = config.data.configs;
954
+ let nextIsDesignMode = resolveModeFlag(config, "isDesignMode");
955
+ let nextIsPreviewMode = resolveModeFlag(config, "isPreviewMode");
956
+ let nextIsRevisionPreview = resolveModeFlag(config, "isRevisionPreview");
957
+ let nextSectionType = resolveSectionType(config);
958
+ if (existing.isDesignMode || nextIsDesignMode) {
959
+ existing.pendingProjectData = void 0;
960
+ } else {
961
+ existing.pendingProjectData = page;
818
962
  }
819
963
  existing.__weaverseNextLatestData = page;
820
964
  existing.dataContext = resolveDataContext(config);
821
965
  existing.requestInfo = requestInfo;
822
966
  existing.projectId = resolveProjectId(config.client, config.data, page.id);
823
967
  existing.isDesignMode = nextIsDesignMode;
824
- existing.isPreviewMode = config.client?.requestContext?.isPreviewMode ?? false;
825
- existing.isRevisionPreview = config.client?.requestContext?.isRevisionPreview ?? false;
826
- existing.sectionType = config.client?.requestContext?.sectionType;
827
- existing.weaverseHost = getConfigString(config.data.configs, "weaverseHost") ?? existing.weaverseHost;
828
- existing.weaverseVersion = getConfigString(config.data.configs, "weaverseVersion") ?? existing.weaverseVersion;
968
+ existing.isPreviewMode = nextIsPreviewMode;
969
+ existing.isRevisionPreview = nextIsRevisionPreview;
970
+ existing.sectionType = nextSectionType;
971
+ existing.weaverseHost = getConfigString(configs, "weaverseHost") ?? existing.weaverseHost;
972
+ existing.weaverseVersion = getConfigString(configs, "weaverseVersion") ?? existing.weaverseVersion;
829
973
  existing.internal.pageAssignment = config.data.pageAssignment;
830
974
  existing.internal.project = config.data.project;
831
975
  if (config.navigate) {
@@ -845,7 +989,11 @@ function createWeaverseNextRuntime(config) {
845
989
  registerRuntime(existing);
846
990
  return existing;
847
991
  }
848
- let runtime = new WeaverseNextRuntime(config);
992
+ let [runtime, refreshedItems] = collectDeferredItemUpdates(
993
+ () => new WeaverseNextRuntime(config)
994
+ );
995
+ runtime.pendingItemUpdates = refreshedItems;
996
+ rebindPageItemsToRuntime(runtime);
849
997
  runtime.__weaverseNextRequestKey = requestKey;
850
998
  runtime.__weaverseNextLatestData = page;
851
999
  registerRuntime(runtime);
@@ -860,7 +1008,10 @@ function bindWeaverseNextStudioRuntime(runtime) {
860
1008
  return false;
861
1009
  }
862
1010
  let boundRuntime = runtime;
863
- if (!boundRuntime.__weaverseNextStudioBound) {
1011
+ let activeRuntime = studio.weaverse;
1012
+ let activeRequestInfo = activeRuntime?.requestInfo;
1013
+ let isActiveUrl = !activeRequestInfo || activeRequestInfo.pathname === runtime.requestInfo.pathname && activeRequestInfo.search === runtime.requestInfo.search;
1014
+ if (!(boundRuntime.__weaverseNextStudioBound && isActiveUrl)) {
864
1015
  studio.init?.(runtime);
865
1016
  boundRuntime.__weaverseNextStudioBound = true;
866
1017
  return true;
@@ -872,9 +1023,67 @@ function bindWeaverseNextStudioRuntime(runtime) {
872
1023
  });
873
1024
  return true;
874
1025
  }
875
-
876
- // src/revalidate-item.ts
877
1026
  var DEFAULT_REVALIDATE_ENDPOINT = "/api/weaverse/revalidate";
1027
+ var MAX_ROUTE_CONTEXT_HANDLE_LENGTH = 512;
1028
+ var DENIED_ROUTE_CONTEXT_PARAMS = [
1029
+ "weaverseprojectid",
1030
+ "weaversehost",
1031
+ "weaverseapikey",
1032
+ "weaverseapibase",
1033
+ "weaversepublicapibase",
1034
+ "weaverseversion",
1035
+ "projectid",
1036
+ "weaversedraftitem",
1037
+ "__weaversedraftitem",
1038
+ "_rsc"
1039
+ ];
1040
+ var ROUTE_CONTEXT_I18N_KEYS = [
1041
+ "country",
1042
+ "label",
1043
+ "language",
1044
+ "locale",
1045
+ "pathPrefix"
1046
+ ];
1047
+ function sanitizeRouteContextSearch(search) {
1048
+ let params = new URLSearchParams(search);
1049
+ let denied = new Set(DENIED_ROUTE_CONTEXT_PARAMS);
1050
+ for (let key of [...new Set(params.keys())]) {
1051
+ if (denied.has(key.toLowerCase())) {
1052
+ params.delete(key);
1053
+ }
1054
+ }
1055
+ let serialized = params.toString();
1056
+ return serialized ? `?${serialized}` : "";
1057
+ }
1058
+ function buildWeaverseNextRevalidateRouteContext(requestInfo) {
1059
+ if (!requestInfo || typeof requestInfo.pathname !== "string" || !requestInfo.pathname) {
1060
+ return;
1061
+ }
1062
+ let routeContext = {
1063
+ pathname: requestInfo.pathname,
1064
+ search: sanitizeRouteContextSearch(requestInfo.search ?? "")
1065
+ };
1066
+ let { i18n } = requestInfo;
1067
+ if (i18n && typeof i18n === "object") {
1068
+ let picked = {};
1069
+ for (let key of ROUTE_CONTEXT_I18N_KEYS) {
1070
+ let value = i18n[key];
1071
+ if (typeof value === "string") {
1072
+ picked[key] = value;
1073
+ }
1074
+ }
1075
+ if (Object.keys(picked).length) {
1076
+ routeContext.i18n = picked;
1077
+ }
1078
+ }
1079
+ if (requestInfo.pageType && schema.PageTypeSchema.safeParse(requestInfo.pageType).success) {
1080
+ routeContext.pageType = requestInfo.pageType;
1081
+ }
1082
+ if (typeof requestInfo.handle === "string" && requestInfo.handle && requestInfo.handle.length <= MAX_ROUTE_CONTEXT_HANDLE_LENGTH) {
1083
+ routeContext.handle = requestInfo.handle;
1084
+ }
1085
+ return routeContext;
1086
+ }
878
1087
  async function revalidateWeaverseNextItem(runtime, draftItem, endpoint = DEFAULT_REVALIDATE_ENDPOINT) {
879
1088
  let instance = runtime.itemInstances.get(draftItem.id);
880
1089
  if (!instance) {
@@ -882,10 +1091,14 @@ async function revalidateWeaverseNextItem(runtime, draftItem, endpoint = DEFAULT
882
1091
  `[weaverse-next] No live item instance for "${draftItem.id}".`
883
1092
  );
884
1093
  }
1094
+ let routeContext = buildWeaverseNextRevalidateRouteContext(
1095
+ runtime.requestInfo
1096
+ );
1097
+ let body = routeContext ? { draftItem, routeContext } : { draftItem };
885
1098
  let response = await fetch(endpoint, {
886
1099
  method: "POST",
887
1100
  headers: { "Content-Type": "application/json" },
888
- body: JSON.stringify({ draftItem })
1101
+ body: JSON.stringify(body)
889
1102
  });
890
1103
  if (!response.ok) {
891
1104
  throw new Error(
@@ -998,6 +1211,7 @@ function WeaverseNextStudio(props) {
998
1211
  );
999
1212
  }
1000
1213
  var EMPTY_DATA_CONTEXT = {};
1214
+ var useIsomorphicLayoutEffect = typeof window === "undefined" ? react$1.useEffect : react$1.useLayoutEffect;
1001
1215
  function getRenderablePage2(data) {
1002
1216
  let page = data?.page;
1003
1217
  if (!page) {
@@ -1033,6 +1247,9 @@ var WeaverseNextRenderer = react$1.memo(function WeaverseNextRendererComponent(p
1033
1247
  context?.themeSettingsStore,
1034
1248
  context?.translationStore
1035
1249
  ]);
1250
+ useIsomorphicLayoutEffect(() => {
1251
+ weaverse?.flushRenderPhaseUpdates();
1252
+ }, [weaverse]);
1036
1253
  if (!weaverse) {
1037
1254
  return null;
1038
1255
  }
@@ -1049,6 +1266,15 @@ function hasOpenGraphContent(seo) {
1049
1266
  function hasTwitterContent(seo) {
1050
1267
  return Boolean(seo?.title || seo?.description || seo?.image || seo?.cardType);
1051
1268
  }
1269
+ function normalizeTwitterCard(cardType) {
1270
+ return cardType === "summary_large_image" ? "summary_large_image" : "summary";
1271
+ }
1272
+ function normalizeOpenGraphType(type) {
1273
+ if (type === "article" || type === "profile" || type === "video.other") {
1274
+ return type;
1275
+ }
1276
+ return "website";
1277
+ }
1052
1278
  function formatWeaverseNextSeoMetadata(seo) {
1053
1279
  let index = seo?.robots?.index !== false;
1054
1280
  let follow = seo?.robots?.follow !== false;
@@ -1076,13 +1302,13 @@ function formatWeaverseNextSeoMetadata(seo) {
1076
1302
  title: openGraph?.title,
1077
1303
  description: openGraph?.description,
1078
1304
  images: openGraph?.image ? [openGraph.image] : void 0,
1079
- type: openGraph?.type || "website"
1305
+ type: normalizeOpenGraphType(openGraph?.type)
1080
1306
  };
1081
1307
  }
1082
1308
  let twitter = seo.twitter;
1083
1309
  if (hasTwitterContent(twitter)) {
1084
1310
  metadata.twitter = {
1085
- card: twitter?.cardType || "summary",
1311
+ card: normalizeTwitterCard(twitter?.cardType),
1086
1312
  title: twitter?.title,
1087
1313
  description: twitter?.description,
1088
1314
  images: twitter?.image ? [twitter.image] : void 0
@@ -1161,7 +1387,7 @@ function resolveWeaverseNextStudioScriptSrc(context, options = {}) {
1161
1387
  if (!isTrustedStudioOrigin(origin, storefrontHostname)) {
1162
1388
  return null;
1163
1389
  }
1164
- let bundle = isDesignMode ? "index.js" : "preview.js";
1390
+ let bundle = isPreviewMode || isRevisionPreview ? "preview.js" : "index.js";
1165
1391
  let version = last(searchParams, "weaverseVersion");
1166
1392
  let url = `${origin}/static/studio/next/${bundle}`;
1167
1393
  return version ? `${url}?v=${encodeURIComponent(version)}` : url;
@@ -1235,10 +1461,6 @@ Object.defineProperty(exports, "useWeaverse", {
1235
1461
  enumerable: true,
1236
1462
  get: function () { return react.useWeaverse; }
1237
1463
  });
1238
- Object.defineProperty(exports, "createSchema", {
1239
- enumerable: true,
1240
- get: function () { return schema.createSchema; }
1241
- });
1242
1464
  exports.DEFAULT_REVALIDATE_ENDPOINT = DEFAULT_REVALIDATE_ENDPOINT;
1243
1465
  exports.ThemeTextProvider = ThemeTextProvider;
1244
1466
  exports.ThemeTextStore = ThemeTextStore;
@@ -1253,12 +1475,14 @@ exports.WeaverseNextStudioBridge = WeaverseNextStudioBridge;
1253
1475
  exports.WeaverseNextStudioConnect = WeaverseNextStudioConnect;
1254
1476
  exports.bindWeaverseNextStudioRuntime = bindWeaverseNextStudioRuntime;
1255
1477
  exports.buildWeaverseNextRequestInfo = buildWeaverseNextRequestInfo;
1478
+ exports.buildWeaverseNextRevalidateRouteContext = buildWeaverseNextRevalidateRouteContext;
1256
1479
  exports.createTranslate = createTranslate;
1257
1480
  exports.createWeaverseNextClient = createWeaverseNextClient;
1258
1481
  exports.createWeaverseNextRuntime = createWeaverseNextRuntime;
1259
1482
  exports.createWeaverseNextStudioInternals = createWeaverseNextStudioInternals;
1260
1483
  exports.createWeaverseNextThemeSettingsStore = createWeaverseNextThemeSettingsStore;
1261
1484
  exports.formatWeaverseNextSeoMetadata = formatWeaverseNextSeoMetadata;
1485
+ exports.generateDataFromSchema = generateDataFromSchema;
1262
1486
  exports.getNestedKey = getNestedKey;
1263
1487
  exports.getWeaverseNextSeoMetadata = getWeaverseNextSeoMetadata;
1264
1488
  exports.interpolate = interpolate;
@@ -1273,5 +1497,11 @@ exports.useWeaverseCommerce = useWeaverseCommerce;
1273
1497
  exports.useWeaverseNextStudioInternals = useWeaverseNextStudioInternals;
1274
1498
  exports.useWeaversePageData = useWeaversePageData;
1275
1499
  exports.useWeaverseRootData = useWeaverseRootData;
1500
+ Object.keys(schema).forEach(function (k) {
1501
+ if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
1502
+ enumerable: true,
1503
+ get: function () { return schema[k]; }
1504
+ });
1505
+ });
1276
1506
  //# sourceMappingURL=index.js.map
1277
1507
  //# sourceMappingURL=index.js.map