@weaverse/hydrogen 5.9.0 → 5.9.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/dist/index.js CHANGED
@@ -8,18 +8,7 @@ var reactRouter = require('react-router');
8
8
  var react$1 = require('react');
9
9
  var reactErrorBoundary = require('react-error-boundary');
10
10
 
11
- var __defProp = Object.defineProperty;
12
- var __export = (target, all) => {
13
- for (var name in all)
14
- __defProp(target, name, { get: all[name], enumerable: true });
15
- };
16
-
17
- // src/components/main.tsx
18
- var main_exports = {};
19
- __export(main_exports, {
20
- default: () => main_default,
21
- schema: () => schema
22
- });
11
+ // src/index.ts
23
12
  function Main(props) {
24
13
  let { children, dangerouslySetInnerHTML, ...rest } = props;
25
14
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -38,7 +27,12 @@ var schema = schema$1.createSchema({
38
27
  });
39
28
 
40
29
  // src/components/index.ts
41
- var defaultComponents = [main_exports];
30
+ var defaultComponents = [
31
+ {
32
+ default: main_default,
33
+ schema
34
+ }
35
+ ];
42
36
  function createFlatDataContext(matches) {
43
37
  const context = {};
44
38
  for (const match of matches) {
@@ -92,6 +86,9 @@ function isThemeSettingsResponse(data) {
92
86
  function isValidHydrogenSchema(schema2) {
93
87
  return schema$1.isValidSchema(schema2);
94
88
  }
89
+ function hasWeaverseStudio(window2) {
90
+ return "weaverseStudio" in window2 && typeof window2.weaverseStudio === "object";
91
+ }
95
92
 
96
93
  // src/utils/index.ts
97
94
  var warnedTypes = /* @__PURE__ */ new Set();
@@ -153,6 +150,8 @@ function getWeaverseConfigs(request, env) {
153
150
  weaverseVersion,
154
151
  weaverseApiKey
155
152
  } = queries;
153
+ let url = new URL(request.url);
154
+ let isRevisionPreview = url.searchParams.has("__revisionId");
156
155
  return {
157
156
  projectId: weaverseProjectId || WEAVERSE_PROJECT_ID || envFromProcess.WEAVERSE_PROJECT_ID || "",
158
157
  weaverseHost: weaverseHost || WEAVERSE_HOST || envFromProcess.WEAVERSE_HOST || "https://studio.weaverse.io",
@@ -161,6 +160,7 @@ function getWeaverseConfigs(request, env) {
161
160
  weaverseVersion: weaverseVersion || "",
162
161
  isDesignMode,
163
162
  isPreviewMode,
163
+ isRevisionPreview,
164
164
  sectionType: sectionType || "",
165
165
  publicEnv: {
166
166
  PUBLIC_STORE_DOMAIN: PUBLIC_STORE_DOMAIN || "",
@@ -292,13 +292,15 @@ function getPreviewData(type, components, weaverseHost) {
292
292
  }
293
293
  };
294
294
  }
295
- var ThemeSettingsStore = class extends react.EventEmitter {
295
+ var ThemeSettingsStore = class {
296
296
  settings = {};
297
297
  schema;
298
298
  publicEnv;
299
+ listeners = /* @__PURE__ */ new Set();
300
+ MAX_LISTENERS = 100;
301
+ isDestroyed = false;
299
302
  constructor(data) {
300
- super();
301
- let { theme, schema: schema2, publicEnv } = data || {};
303
+ const { theme, schema: schema2, publicEnv } = data || {};
302
304
  this.settings = { ...theme };
303
305
  this.schema = schema2;
304
306
  this.publicEnv = publicEnv;
@@ -307,17 +309,59 @@ var ThemeSettingsStore = class extends react.EventEmitter {
307
309
  }
308
310
  }
309
311
  updateThemeSettings = (newSettings) => {
312
+ if (this.isDestroyed) {
313
+ console.warn("ThemeSettingsStore: Cannot update destroyed store");
314
+ return;
315
+ }
310
316
  this.settings = {
311
317
  ...this.settings,
312
318
  ...newSettings
313
319
  };
314
- this.emit(this.settings);
320
+ this.emit();
315
321
  };
316
322
  getSnapshot = () => this.settings;
317
323
  getServerSnapshot = () => this.settings;
324
+ subscribe = (callback) => {
325
+ if (this.isDestroyed) {
326
+ console.warn("ThemeSettingsStore: Cannot subscribe to destroyed store");
327
+ return () => {
328
+ };
329
+ }
330
+ if (this.listeners.size >= this.MAX_LISTENERS) {
331
+ console.warn(
332
+ `ThemeSettingsStore: Maximum listeners (${this.MAX_LISTENERS}) exceeded. Possible memory leak detected.`
333
+ );
334
+ return () => {
335
+ };
336
+ }
337
+ this.listeners.add(callback);
338
+ return () => {
339
+ this.listeners.delete(callback);
340
+ };
341
+ };
342
+ emit = () => {
343
+ if (this.isDestroyed) return;
344
+ const currentListeners = Array.from(this.listeners);
345
+ for (const listener of currentListeners) {
346
+ try {
347
+ listener();
348
+ } catch (error) {
349
+ console.error("ThemeSettingsStore: Listener error", error);
350
+ }
351
+ }
352
+ };
353
+ // Method to properly clean up the store
354
+ destroy = () => {
355
+ if (this.isDestroyed) return;
356
+ this.listeners.clear();
357
+ this.isDestroyed = true;
358
+ if (react.isBrowser && window.__weaverseThemeSettingsStore === this) {
359
+ window.__weaverseThemeSettingsStore = void 0;
360
+ }
361
+ };
318
362
  };
319
363
  function useThemeSettingsStore() {
320
- let data = reactRouter.useRouteLoaderData("root");
364
+ const data = reactRouter.useRouteLoaderData("root");
321
365
  if (react.isBrowser && window.__weaverseThemeSettingsStore) {
322
366
  return window.__weaverseThemeSettingsStore;
323
367
  }
@@ -331,10 +375,16 @@ function useStudio(weaverse) {
331
375
  let { pathname, search } = reactRouter.useLocation();
332
376
  let navigate = reactRouter.useNavigate();
333
377
  let themeSettingsStore = useThemeSettingsStore();
334
- let { isDesignMode, weaverseHost, weaverseVersion, isPreviewMode } = weaverse;
378
+ let {
379
+ isDesignMode,
380
+ weaverseHost,
381
+ weaverseVersion,
382
+ isPreviewMode,
383
+ isRevisionPreview
384
+ } = weaverse;
335
385
  react$1.useEffect(() => {
336
386
  if (navigation.state === "idle") {
337
- if (isPreviewMode) {
387
+ if (isRevisionPreview || isPreviewMode) {
338
388
  let previewSrc = `${weaverseHost}/static/studio/hydrogen/preview.js?v=${weaverseVersion}`;
339
389
  react.loadScript(previewSrc).catch(console.error);
340
390
  } else if (isDesignMode) {
@@ -346,7 +396,9 @@ function useStudio(weaverse) {
346
396
  };
347
397
  let studioSrc = `${weaverseHost}/static/studio/hydrogen/index.js?v=${weaverseVersion}`;
348
398
  react.loadScript(studioSrc).then(() => {
349
- window.weaverseStudio?.init(weaverse);
399
+ if (hasWeaverseStudio(window)) {
400
+ window.weaverseStudio.init(weaverse);
401
+ }
350
402
  }).catch(console.error);
351
403
  }
352
404
  }
@@ -391,6 +443,7 @@ var WeaverseHydrogen = class extends react.Weaverse {
391
443
  weaverseVersion;
392
444
  isDesignMode;
393
445
  isPreviewMode;
446
+ isRevisionPreview;
394
447
  sectionType;
395
448
  static itemInstances;
396
449
  static elementRegistry;
@@ -407,6 +460,7 @@ var WeaverseHydrogen = class extends react.Weaverse {
407
460
  this.weaverseVersion = params.weaverseVersion || "";
408
461
  this.isDesignMode = params.isDesignMode ?? false;
409
462
  this.isPreviewMode = params.isPreviewMode ?? false;
463
+ this.isRevisionPreview = params.isRevisionPreview ?? false;
410
464
  this.sectionType = params.sectionType || "";
411
465
  }
412
466
  };
@@ -420,7 +474,9 @@ function createWeaverseInstance(params) {
420
474
  }
421
475
  if (weaverse?.isDesignMode) {
422
476
  weaverse.requestInfo = params.requestInfo;
423
- window.weaverseStudio?.refreshStudio(params);
477
+ if (hasWeaverseStudio(window)) {
478
+ window.weaverseStudio.refreshStudio(params);
479
+ }
424
480
  }
425
481
  return weaverse;
426
482
  }
@@ -459,7 +515,7 @@ function registerComponent(element) {
459
515
  var WeaverseHydrogenRoot = react$1.memo(
460
516
  ({
461
517
  components,
462
- errorComponent: ErrorComponent = ({ error }) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: error?.message || "An unexpected error occurred" })
518
+ errorComponent: ErrorComponent = ({ error }) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: error instanceof Error ? error.message : "An unexpected error occurred" })
463
519
  }) => {
464
520
  const matches = reactRouter.useMatches();
465
521
  const enhancedDataContext = createWeaverseDataContext(matches);
@@ -614,7 +670,9 @@ var WeaverseClient = class {
614
670
  weaverseApiBase: this.configs.weaverseApiBase,
615
671
  weaverseApiKey: this.configs.weaverseApiKey,
616
672
  weaverseVersion: this.configs.weaverseVersion,
617
- isDesignMode: this.configs.isDesignMode
673
+ isDesignMode: this.configs.isDesignMode,
674
+ isPreviewMode: this.configs.isPreviewMode,
675
+ isRevisionPreview: this.configs.isRevisionPreview
618
676
  };
619
677
  this.basePageRequestBody = {
620
678
  isDesignMode: this.configs.isDesignMode,
@@ -856,6 +914,23 @@ var WeaverseClient = class {
856
914
  }
857
915
  return `${weaverseHost}/api/public/${endpoint}`;
858
916
  }
917
+ /**
918
+ * Fetch data with caching support for both design mode and production.
919
+ * Uses direct fetch in design mode, Hydrogen's withCache in production.
920
+ * Automatically includes projectId in cache key for multi-project isolation.
921
+ *
922
+ * @param url - The URL to fetch from
923
+ * @param options - Fetch options including optional cache strategy
924
+ * @returns Promise resolving to the fetched data
925
+ *
926
+ * @example
927
+ * ```typescript
928
+ * const data = await weaverse.fetchWithCache<MyData>(
929
+ * 'https://api.example.com/data',
930
+ * { method: 'POST', body: JSON.stringify({ key: 'value' }) }
931
+ * )
932
+ * ```
933
+ */
859
934
  fetchWithCache = async (url, options = {}) => {
860
935
  const strategy = options.strategy || hydrogen.CacheCustom(DEFAULT_CACHE_STRATEGY);
861
936
  const cacheKey = [
@@ -880,6 +955,19 @@ var WeaverseClient = class {
880
955
  }
881
956
  return result.data;
882
957
  };
958
+ /**
959
+ * Load theme settings from Weaverse API with fallback to schema defaults.
960
+ * Merges remote settings with local theme schema and handles design mode serialization.
961
+ *
962
+ * @param strategy - Optional cache strategy override
963
+ * @returns Promise resolving to theme settings response
964
+ *
965
+ * @example
966
+ * ```typescript
967
+ * const settings = await weaverse.loadThemeSettings()
968
+ * const primaryColor = settings.theme.colors?.primary
969
+ * ```
970
+ */
883
971
  loadThemeSettings = async (strategy) => {
884
972
  const defaultThemeSettings = generateDataFromSchema(this.themeSchema);
885
973
  try {
@@ -955,6 +1043,13 @@ var WeaverseClient = class {
955
1043
  };
956
1044
  }
957
1045
  };
1046
+ /**
1047
+ * Generate fallback page with default structure when page data is unavailable.
1048
+ * Used internally when API returns no page or when page needs default content.
1049
+ *
1050
+ * @param message - Custom message to display in the fallback page
1051
+ * @returns HydrogenPageData with single main component containing the message
1052
+ */
958
1053
  generateFallbackPage = (message) => {
959
1054
  const rootId = crypto.randomUUID();
960
1055
  return {
@@ -970,6 +1065,34 @@ var WeaverseClient = class {
970
1065
  ]
971
1066
  };
972
1067
  };
1068
+ /**
1069
+ * Load page data from Weaverse API with optional route-level project override.
1070
+ * Fetches page content, executes component loaders, and handles empty items fallback.
1071
+ *
1072
+ * @param params - Optional page loading parameters
1073
+ * @param params.type - Page type (HOME, PAGE, PRODUCT, COLLECTION, etc.)
1074
+ * @param params.handle - Page handle for dynamic routes
1075
+ * @param params.locale - Locale override
1076
+ * @param params.projectId - Route-level project ID override (for multi-project)
1077
+ * @param params.strategy - Custom cache strategy override
1078
+ * @returns Promise resolving to page data or null on error
1079
+ *
1080
+ * @example
1081
+ * ```typescript
1082
+ * // Basic usage
1083
+ * const data = await weaverse.loadPage()
1084
+ *
1085
+ * // With page type
1086
+ * const data = await weaverse.loadPage({ type: 'HOME' })
1087
+ *
1088
+ * // Route-level project override
1089
+ * const data = await weaverse.loadPage({
1090
+ * type: 'PAGE',
1091
+ * handle: 'about',
1092
+ * projectId: 'campaign-project-123'
1093
+ * })
1094
+ * ```
1095
+ */
973
1096
  loadPage = async (params = {}) => {
974
1097
  try {
975
1098
  const { request, storefront, basePageRequestBody, basePageConfigs } = this;
@@ -1054,6 +1177,13 @@ var WeaverseClient = class {
1054
1177
  if (!page) {
1055
1178
  page = this.generateFallbackPage("Please add new section to start.");
1056
1179
  }
1180
+ if (page?.items?.length === 0) {
1181
+ page.items.push({
1182
+ type: "main",
1183
+ id: page.rootId || crypto.randomUUID(),
1184
+ data: {}
1185
+ });
1186
+ }
1057
1187
  if (page?.items) {
1058
1188
  const items = page.items;
1059
1189
  page.items = await Promise.all(items.map(this.execComponentLoader));
@@ -1201,6 +1331,7 @@ exports.getRequestQueries = getRequestQueries;
1201
1331
  exports.getSelectedProductOptions = getSelectedProductOptions;
1202
1332
  exports.getWeaverseConfigs = getWeaverseConfigs;
1203
1333
  exports.hasError = hasError;
1334
+ exports.hasWeaverseStudio = hasWeaverseStudio;
1204
1335
  exports.isFetchProjectPayload = isFetchProjectPayload;
1205
1336
  exports.isProjectIdFunction = isProjectIdFunction;
1206
1337
  exports.isThemeSettingsResponse = isThemeSettingsResponse;