@weaverse/hydrogen 5.9.0 → 5.9.2

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,63 @@ 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) {
344
+ return;
345
+ }
346
+ const currentListeners = Array.from(this.listeners);
347
+ for (const listener of currentListeners) {
348
+ try {
349
+ listener();
350
+ } catch (error) {
351
+ console.error("ThemeSettingsStore: Listener error", error);
352
+ }
353
+ }
354
+ };
355
+ // Method to properly clean up the store
356
+ destroy = () => {
357
+ if (this.isDestroyed) {
358
+ return;
359
+ }
360
+ this.listeners.clear();
361
+ this.isDestroyed = true;
362
+ if (react.isBrowser && window.__weaverseThemeSettingsStore === this) {
363
+ window.__weaverseThemeSettingsStore = void 0;
364
+ }
365
+ };
318
366
  };
319
367
  function useThemeSettingsStore() {
320
- let data = reactRouter.useRouteLoaderData("root");
368
+ const data = reactRouter.useRouteLoaderData("root");
321
369
  if (react.isBrowser && window.__weaverseThemeSettingsStore) {
322
370
  return window.__weaverseThemeSettingsStore;
323
371
  }
@@ -331,10 +379,16 @@ function useStudio(weaverse) {
331
379
  let { pathname, search } = reactRouter.useLocation();
332
380
  let navigate = reactRouter.useNavigate();
333
381
  let themeSettingsStore = useThemeSettingsStore();
334
- let { isDesignMode, weaverseHost, weaverseVersion, isPreviewMode } = weaverse;
382
+ let {
383
+ isDesignMode,
384
+ weaverseHost,
385
+ weaverseVersion,
386
+ isPreviewMode,
387
+ isRevisionPreview
388
+ } = weaverse;
335
389
  react$1.useEffect(() => {
336
390
  if (navigation.state === "idle") {
337
- if (isPreviewMode) {
391
+ if (isRevisionPreview || isPreviewMode) {
338
392
  let previewSrc = `${weaverseHost}/static/studio/hydrogen/preview.js?v=${weaverseVersion}`;
339
393
  react.loadScript(previewSrc).catch(console.error);
340
394
  } else if (isDesignMode) {
@@ -346,7 +400,9 @@ function useStudio(weaverse) {
346
400
  };
347
401
  let studioSrc = `${weaverseHost}/static/studio/hydrogen/index.js?v=${weaverseVersion}`;
348
402
  react.loadScript(studioSrc).then(() => {
349
- window.weaverseStudio?.init(weaverse);
403
+ if (hasWeaverseStudio(window)) {
404
+ window.weaverseStudio.init(weaverse);
405
+ }
350
406
  }).catch(console.error);
351
407
  }
352
408
  }
@@ -391,6 +447,7 @@ var WeaverseHydrogen = class extends react.Weaverse {
391
447
  weaverseVersion;
392
448
  isDesignMode;
393
449
  isPreviewMode;
450
+ isRevisionPreview;
394
451
  sectionType;
395
452
  static itemInstances;
396
453
  static elementRegistry;
@@ -407,6 +464,7 @@ var WeaverseHydrogen = class extends react.Weaverse {
407
464
  this.weaverseVersion = params.weaverseVersion || "";
408
465
  this.isDesignMode = params.isDesignMode ?? false;
409
466
  this.isPreviewMode = params.isPreviewMode ?? false;
467
+ this.isRevisionPreview = params.isRevisionPreview ?? false;
410
468
  this.sectionType = params.sectionType || "";
411
469
  }
412
470
  };
@@ -420,7 +478,9 @@ function createWeaverseInstance(params) {
420
478
  }
421
479
  if (weaverse?.isDesignMode) {
422
480
  weaverse.requestInfo = params.requestInfo;
423
- window.weaverseStudio?.refreshStudio(params);
481
+ if (hasWeaverseStudio(window)) {
482
+ window.weaverseStudio.refreshStudio(params);
483
+ }
424
484
  }
425
485
  return weaverse;
426
486
  }
@@ -459,7 +519,7 @@ function registerComponent(element) {
459
519
  var WeaverseHydrogenRoot = react$1.memo(
460
520
  ({
461
521
  components,
462
- errorComponent: ErrorComponent = ({ error }) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: error?.message || "An unexpected error occurred" })
522
+ errorComponent: ErrorComponent = ({ error }) => /* @__PURE__ */ jsxRuntime.jsx("div", { children: error instanceof Error ? error.message : "An unexpected error occurred" })
463
523
  }) => {
464
524
  const matches = reactRouter.useMatches();
465
525
  const enhancedDataContext = createWeaverseDataContext(matches);
@@ -614,7 +674,9 @@ var WeaverseClient = class {
614
674
  weaverseApiBase: this.configs.weaverseApiBase,
615
675
  weaverseApiKey: this.configs.weaverseApiKey,
616
676
  weaverseVersion: this.configs.weaverseVersion,
617
- isDesignMode: this.configs.isDesignMode
677
+ isDesignMode: this.configs.isDesignMode,
678
+ isPreviewMode: this.configs.isPreviewMode,
679
+ isRevisionPreview: this.configs.isRevisionPreview
618
680
  };
619
681
  this.basePageRequestBody = {
620
682
  isDesignMode: this.configs.isDesignMode,
@@ -856,6 +918,23 @@ var WeaverseClient = class {
856
918
  }
857
919
  return `${weaverseHost}/api/public/${endpoint}`;
858
920
  }
921
+ /**
922
+ * Fetch data with caching support for both design mode and production.
923
+ * Uses direct fetch in design mode, Hydrogen's withCache in production.
924
+ * Automatically includes projectId in cache key for multi-project isolation.
925
+ *
926
+ * @param url - The URL to fetch from
927
+ * @param options - Fetch options including optional cache strategy
928
+ * @returns Promise resolving to the fetched data
929
+ *
930
+ * @example
931
+ * ```typescript
932
+ * const data = await weaverse.fetchWithCache<MyData>(
933
+ * 'https://api.example.com/data',
934
+ * { method: 'POST', body: JSON.stringify({ key: 'value' }) }
935
+ * )
936
+ * ```
937
+ */
859
938
  fetchWithCache = async (url, options = {}) => {
860
939
  const strategy = options.strategy || hydrogen.CacheCustom(DEFAULT_CACHE_STRATEGY);
861
940
  const cacheKey = [
@@ -880,6 +959,19 @@ var WeaverseClient = class {
880
959
  }
881
960
  return result.data;
882
961
  };
962
+ /**
963
+ * Load theme settings from Weaverse API with fallback to schema defaults.
964
+ * Merges remote settings with local theme schema and handles design mode serialization.
965
+ *
966
+ * @param strategy - Optional cache strategy override
967
+ * @returns Promise resolving to theme settings response
968
+ *
969
+ * @example
970
+ * ```typescript
971
+ * const settings = await weaverse.loadThemeSettings()
972
+ * const primaryColor = settings.theme.colors?.primary
973
+ * ```
974
+ */
883
975
  loadThemeSettings = async (strategy) => {
884
976
  const defaultThemeSettings = generateDataFromSchema(this.themeSchema);
885
977
  try {
@@ -955,6 +1047,13 @@ var WeaverseClient = class {
955
1047
  };
956
1048
  }
957
1049
  };
1050
+ /**
1051
+ * Generate fallback page with default structure when page data is unavailable.
1052
+ * Used internally when API returns no page or when page needs default content.
1053
+ *
1054
+ * @param message - Custom message to display in the fallback page
1055
+ * @returns HydrogenPageData with single main component containing the message
1056
+ */
958
1057
  generateFallbackPage = (message) => {
959
1058
  const rootId = crypto.randomUUID();
960
1059
  return {
@@ -970,6 +1069,34 @@ var WeaverseClient = class {
970
1069
  ]
971
1070
  };
972
1071
  };
1072
+ /**
1073
+ * Load page data from Weaverse API with optional route-level project override.
1074
+ * Fetches page content, executes component loaders, and handles empty items fallback.
1075
+ *
1076
+ * @param params - Optional page loading parameters
1077
+ * @param params.type - Page type (HOME, PAGE, PRODUCT, COLLECTION, etc.)
1078
+ * @param params.handle - Page handle for dynamic routes
1079
+ * @param params.locale - Locale override
1080
+ * @param params.projectId - Route-level project ID override (for multi-project)
1081
+ * @param params.strategy - Custom cache strategy override
1082
+ * @returns Promise resolving to page data or null on error
1083
+ *
1084
+ * @example
1085
+ * ```typescript
1086
+ * // Basic usage
1087
+ * const data = await weaverse.loadPage()
1088
+ *
1089
+ * // With page type
1090
+ * const data = await weaverse.loadPage({ type: 'HOME' })
1091
+ *
1092
+ * // Route-level project override
1093
+ * const data = await weaverse.loadPage({
1094
+ * type: 'PAGE',
1095
+ * handle: 'about',
1096
+ * projectId: 'campaign-project-123'
1097
+ * })
1098
+ * ```
1099
+ */
973
1100
  loadPage = async (params = {}) => {
974
1101
  try {
975
1102
  const { request, storefront, basePageRequestBody, basePageConfigs } = this;
@@ -1054,6 +1181,13 @@ var WeaverseClient = class {
1054
1181
  if (!page) {
1055
1182
  page = this.generateFallbackPage("Please add new section to start.");
1056
1183
  }
1184
+ if (page?.items?.length === 0) {
1185
+ page.items.push({
1186
+ type: "main",
1187
+ id: page.rootId || crypto.randomUUID(),
1188
+ data: {}
1189
+ });
1190
+ }
1057
1191
  if (page?.items) {
1058
1192
  const items = page.items;
1059
1193
  page.items = await Promise.all(items.map(this.execComponentLoader));
@@ -1201,6 +1335,7 @@ exports.getRequestQueries = getRequestQueries;
1201
1335
  exports.getSelectedProductOptions = getSelectedProductOptions;
1202
1336
  exports.getWeaverseConfigs = getWeaverseConfigs;
1203
1337
  exports.hasError = hasError;
1338
+ exports.hasWeaverseStudio = hasWeaverseStudio;
1204
1339
  exports.isFetchProjectPayload = isFetchProjectPayload;
1205
1340
  exports.isProjectIdFunction = isProjectIdFunction;
1206
1341
  exports.isThemeSettingsResponse = isThemeSettingsResponse;