@weaverse/hydrogen 1.1.17 → 1.1.19

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.mjs CHANGED
@@ -1,13 +1,336 @@
1
- // src/index.tsx
2
- import { Await, useLoaderData } from "@remix-run/react";
1
+ // src/index.ts
2
+ export * from "@weaverse/react";
3
+
4
+ // src/client.ts
5
+ import "@shopify/hydrogen";
6
+
7
+ // package.json
8
+ var package_default = {
9
+ version: "1.1.19",
10
+ license: "MIT",
11
+ main: "dist/index.js",
12
+ typings: "dist/index.d.ts",
13
+ module: "dist/index.mjs",
14
+ publishConfig: {
15
+ access: "public"
16
+ },
17
+ files: [
18
+ "dist/*"
19
+ ],
20
+ engines: {
21
+ node: ">=10"
22
+ },
23
+ scripts: {
24
+ start: "npm run dev",
25
+ dev: "tsup src/index.ts --format esm,cjs --dts --outDir dist --watch --external @remix-run/react,@shopify/hydrogen",
26
+ build: "tsup src/index.ts --format esm,cjs --dts --outDir dist --external @remix-run/react,@shopify/hydrogen",
27
+ clean: "rimraf dist",
28
+ prepublish: "npm run build"
29
+ },
30
+ peerDependencies: {
31
+ react: ">=18",
32
+ "react-dom": ">=18"
33
+ },
34
+ prettier: {
35
+ printWidth: 80,
36
+ semi: false,
37
+ singleQuote: true
38
+ },
39
+ name: "@weaverse/hydrogen",
40
+ author: "Weaverse Team",
41
+ dependencies: {
42
+ "@remix-run/react": "1.19.1",
43
+ "@shopify/hydrogen": "2023.7.7",
44
+ "@weaverse/react": "1.1.19",
45
+ "react-error-boundary": "^4.0.11"
46
+ },
47
+ devDependencies: {
48
+ "@shopify/remix-oxygen": "^1.1.4"
49
+ }
50
+ };
51
+
52
+ // src/utils.ts
53
+ function getRequestQueries(request) {
54
+ let url = new URL(request.url);
55
+ return Array.from(url.searchParams.entries()).reduce(
56
+ (q, [k, v]) => {
57
+ q[k] = v === "true" ? true : v === "false" ? false : v;
58
+ return q;
59
+ },
60
+ {}
61
+ );
62
+ }
63
+ function getWeaverseConfigs(request, env) {
64
+ let queries = getRequestQueries(request);
65
+ let {
66
+ WEAVERSE_PROJECT_ID,
67
+ WEAVERSE_HOST,
68
+ PUBLIC_STORE_DOMAIN,
69
+ PUBLIC_STOREFRONT_API_TOKEN
70
+ } = env || {};
71
+ let { weaverseProjectId, weaverseHost, isDesignMode, weaverseVersion } = queries;
72
+ return {
73
+ projectId: weaverseProjectId || WEAVERSE_PROJECT_ID || "",
74
+ weaverseHost: weaverseHost || WEAVERSE_HOST || "https://weaverse.io",
75
+ weaverseVersion: weaverseVersion || "",
76
+ isDesignMode: isDesignMode || false,
77
+ publicEnv: {
78
+ PUBLIC_STORE_DOMAIN,
79
+ PUBLIC_STOREFRONT_API_TOKEN
80
+ }
81
+ };
82
+ }
83
+ function getWeaverseCsp(request) {
84
+ let url = new URL(request.url);
85
+ let weaverseHost = url.searchParams.get("weaverseHost");
86
+ let weaverseHosts = ["https://*.weaverse.io"];
87
+ if (weaverseHost) {
88
+ weaverseHosts.push(weaverseHost);
89
+ }
90
+ return {
91
+ frameAncestors: weaverseHosts,
92
+ defaultSrc: [
93
+ "'self'",
94
+ "https://cdn.shopify.com",
95
+ "https://shopify.com",
96
+ "https://*.youtube.com",
97
+ ...weaverseHosts
98
+ ],
99
+ styleSrc: [
100
+ "'self'",
101
+ "'unsafe-inline'",
102
+ "https://cdn.shopify.com",
103
+ ...weaverseHosts
104
+ ]
105
+ };
106
+ }
107
+
108
+ // src/client.ts
109
+ var WeaverseClient = class {
110
+ constructor(args) {
111
+ this.API = "api/public/project";
112
+ this.clientVersion = package_default.version;
113
+ this.fetchWithCache = (url, options) => {
114
+ let cacheKey = [url, options.body];
115
+ let { strategy = this.storefront.CacheShort(), ...reqInit } = options;
116
+ let res = this.withCache(cacheKey, strategy, async () => {
117
+ let response = await fetch(url, reqInit);
118
+ if (!response.ok) {
119
+ throw new Error("Something went wrong. Skipping cache.");
120
+ }
121
+ return await response.json();
122
+ });
123
+ return res;
124
+ };
125
+ this.loadThemeSettings = async (strategy) => {
126
+ let { API, configs } = this;
127
+ let { weaverseHost, projectId } = configs;
128
+ let res = await this.fetchWithCache(
129
+ `${weaverseHost}/${API}/${projectId}/configs`,
130
+ { strategy }
131
+ );
132
+ let data = null;
133
+ if (res.ok) {
134
+ data = res.payload;
135
+ if (this.configs.isDesignMode) {
136
+ data = {
137
+ ...data,
138
+ schema: this.themeSchema,
139
+ countries: this.countries,
140
+ publicEnv: this.configs.publicEnv
141
+ };
142
+ }
143
+ }
144
+ return data;
145
+ };
146
+ this.loadPage = async (args, configs = {}) => {
147
+ return new Promise(async (resolve, reject) => {
148
+ try {
149
+ let { request, params } = args;
150
+ let { strategy, ...pageLoadParams } = configs;
151
+ let body = {
152
+ ...this.basePageRequestBody,
153
+ params: pageLoadParams,
154
+ url: request.url
155
+ };
156
+ let reqInit = {
157
+ method: "POST",
158
+ body: JSON.stringify(body)
159
+ };
160
+ let url = `${this.configs.weaverseHost}/api/public/project`;
161
+ let payload;
162
+ if (this.configs.isDesignMode) {
163
+ payload = await fetch(url, reqInit).then((res) => res.json());
164
+ } else {
165
+ payload = await this.fetchWithCache(url, {
166
+ ...reqInit,
167
+ strategy
168
+ });
169
+ }
170
+ let { page, project, pageAssignment } = payload;
171
+ if (!page || !project || !pageAssignment) {
172
+ return reject(
173
+ new Error(
174
+ // @ts-ignore
175
+ payload?.error || "Invalid Weaverse project payload!"
176
+ )
177
+ );
178
+ }
179
+ if (page?.items) {
180
+ let items = page.items;
181
+ page.items = await Promise.all(
182
+ items.map((item) => this.execComponentLoader(item, args))
183
+ );
184
+ }
185
+ let data = {
186
+ page,
187
+ project,
188
+ pageAssignment,
189
+ configs: {
190
+ ...this.basePageConfigs,
191
+ requestInfo: {
192
+ params,
193
+ i18n: this.storefront.i18n,
194
+ queries: getRequestQueries(request),
195
+ pathname: new URL(request.url).pathname,
196
+ search: new URL(request.url).search
197
+ }
198
+ }
199
+ };
200
+ return resolve(data);
201
+ } catch (err) {
202
+ console.log(`\u274C [Weaverse page]`, err);
203
+ reject(err);
204
+ }
205
+ });
206
+ };
207
+ this.execComponentLoader = async (item, args) => {
208
+ let schema = this.components.find(
209
+ ({ schema: schema2 }) => schema2?.type === item.type
210
+ );
211
+ let { loader } = schema || {};
212
+ if (loader && typeof loader === "function") {
213
+ try {
214
+ return {
215
+ ...item,
216
+ loaderData: await loader({
217
+ itemData: item,
218
+ ...args
219
+ })
220
+ };
221
+ } catch (err) {
222
+ console.log(`\u274C [Weaverse item loader]`, item.id, err);
223
+ return item;
224
+ }
225
+ }
226
+ return item;
227
+ };
228
+ let { configs, storefront, components, countries, withCache, themeSchema } = args;
229
+ this.storefront = storefront;
230
+ this.components = components;
231
+ this.countries = countries;
232
+ this.themeSchema = themeSchema;
233
+ this.configs = configs;
234
+ this.withCache = withCache;
235
+ this.basePageConfigs = {
236
+ projectId: configs.projectId,
237
+ weaverseHost: configs.weaverseHost,
238
+ weaverseVersion: configs.weaverseVersion,
239
+ isDesignMode: configs.isDesignMode
240
+ };
241
+ this.basePageRequestBody = {
242
+ countries,
243
+ isDesignMode: this.configs.isDesignMode,
244
+ i18n: storefront.i18n,
245
+ projectId: this.configs.projectId
246
+ };
247
+ }
248
+ };
249
+ function createWeaverseClient(args) {
250
+ return new WeaverseClient(args);
251
+ }
252
+
253
+ // src/hooks/use-theme-settings.ts
254
+ import { useLoaderData } from "@remix-run/react";
255
+ import { isBrowser } from "@weaverse/react";
256
+ import { useEffect, useSyncExternalStore } from "react";
257
+ var settings = null;
258
+ var listeners = [];
259
+ var themeSettingsStore = {
260
+ updateThemeSettings(newSettings) {
261
+ settings = { ...settings, ...newSettings };
262
+ emitChange();
263
+ },
264
+ subscribe(listener) {
265
+ listeners = [...listeners, listener];
266
+ return () => {
267
+ listeners = listeners.filter((l) => l !== listener);
268
+ };
269
+ },
270
+ getSnapshot() {
271
+ return settings;
272
+ },
273
+ getServerSnapshot() {
274
+ return settings;
275
+ }
276
+ };
277
+ function emitChange() {
278
+ for (let listener of listeners) {
279
+ listener();
280
+ }
281
+ }
282
+ if (isBrowser) {
283
+ window.__weaverseThemeSettingsStore = themeSettingsStore;
284
+ }
285
+ function useThemeSettings() {
286
+ let settings2 = useSyncExternalStore(
287
+ themeSettingsStore.subscribe,
288
+ themeSettingsStore.getSnapshot,
289
+ themeSettingsStore.getServerSnapshot
290
+ );
291
+ let { weaverseTheme } = useLoaderData();
292
+ useEffect(() => {
293
+ if (weaverseTheme) {
294
+ let settings3 = weaverseTheme.theme;
295
+ if (settings3) {
296
+ themeSettingsStore.updateThemeSettings(settings3);
297
+ }
298
+ } else {
299
+ console.warn(
300
+ `'weaverseTheme' should be returned from root loader in order to get global settings from 'useThemeSettings'.`
301
+ );
302
+ }
303
+ }, [weaverseTheme]);
304
+ return settings2;
305
+ }
306
+
307
+ // src/wrappers.ts
308
+ import { getSelectedProductOptions as hydrogen_getSelectedProductOptions } from "@shopify/hydrogen";
309
+ import { createContentSecurityPolicy as hydrogen_createContentSecurityPolicy } from "@shopify/hydrogen";
310
+ function getSelectedProductOptions(request) {
311
+ let options = hydrogen_getSelectedProductOptions(request);
312
+ return options.filter(
313
+ ({ name }) => name !== "isDesignMode" && !name.startsWith("weaverse")
314
+ );
315
+ }
316
+ function createContentSecurityPolicy(request, directives) {
317
+ let weaverseDirectives = getWeaverseCsp(request);
318
+ return hydrogen_createContentSecurityPolicy({
319
+ ...directives,
320
+ ...weaverseDirectives
321
+ });
322
+ }
323
+
324
+ // src/WeaverseHydrogenRoot.tsx
325
+ import { Await, useLoaderData as useLoaderData2 } from "@remix-run/react";
3
326
  import { WeaverseRoot } from "@weaverse/react";
4
327
  import React, { Suspense } from "react";
5
328
  import { ErrorBoundary } from "react-error-boundary";
6
329
 
7
330
  // src/context.ts
8
- import { Weaverse, isBrowser } from "@weaverse/react";
331
+ import { Weaverse, isBrowser as isBrowser2 } from "@weaverse/react";
9
332
  function createCachedWeaverseInstance(init) {
10
- if (isBrowser) {
333
+ if (isBrowser2) {
11
334
  window.__weaverses = window.__weaverses || [];
12
335
  let weaverse = window.__weaverses.find((w) => {
13
336
  let { pathname, search } = w.requestInfo;
@@ -44,15 +367,21 @@ function createWeaverseInstance(weaverseData, components) {
44
367
  }
45
368
 
46
369
  // src/hooks/use-studio.ts
47
- import { useNavigate, useRevalidator } from "@remix-run/react";
370
+ import {
371
+ useNavigate,
372
+ useRevalidator,
373
+ useRouteLoaderData
374
+ } from "@remix-run/react";
48
375
  import { isIframe, loadScript } from "@weaverse/react";
49
- import { useEffect } from "react";
50
- function useStudio(weaverse, countries, schema, publicEnv) {
376
+ import { useEffect as useEffect2 } from "react";
377
+ function useStudio(weaverse) {
378
+ let { weaverseTheme } = useRouteLoaderData("root");
51
379
  let navigate = useNavigate();
52
380
  let { revalidate } = useRevalidator();
381
+ let { countries, schema, publicEnv } = weaverseTheme || {};
53
382
  let { isDesignMode, weaverseHost, weaverseVersion } = weaverse;
54
383
  let isStudio = isIframe && isDesignMode && weaverseHost && weaverseVersion;
55
- useEffect(() => {
384
+ useEffect2(() => {
56
385
  if (isStudio) {
57
386
  weaverse.internal = {
58
387
  ...weaverse.internal,
@@ -65,191 +394,27 @@ function useStudio(weaverse, countries, schema, publicEnv) {
65
394
  if (window.weaverseStudio) {
66
395
  window.weaverseStudio.init(weaverse);
67
396
  } else {
68
- loadScript(
69
- `${weaverseHost}/assets/studio/hydrogen/index.js?v=${weaverseVersion}`
70
- );
397
+ let studioSrc = `${weaverseHost}/assets/studio/hydrogen/index.js?v=${weaverseVersion}`;
398
+ loadScript(studioSrc);
71
399
  }
72
400
  }
73
401
  }, [weaverse]);
74
402
  }
75
403
 
76
- // src/index.tsx
77
- export * from "@weaverse/react";
78
-
79
- // src/fetch.ts
80
- import { createWithCache } from "@shopify/hydrogen";
81
- async function fetchWithServerCache(params) {
82
- let { url, options = {}, context } = params;
83
- let { storefront } = context;
84
- let withCache = createWithCache(storefront);
85
- let cacheKey = [url, options.body];
86
- let data = await withCache(cacheKey, storefront.CacheShort(), async () => {
87
- let response = await fetch(url, options);
88
- if (!response.ok)
89
- throw new Error("Something went wrong. Skipping cache.");
90
- return await response.json();
91
- });
92
- return data;
93
- }
94
-
95
- // src/utils.ts
96
- function getRequestQueries(request) {
97
- let url = new URL(request.url);
98
- return Array.from(url.searchParams.entries()).reduce(
99
- (q, [k, v]) => {
100
- q[k] = v === "true" ? true : v === "false" ? false : v;
101
- return q;
102
- },
103
- {}
104
- );
105
- }
106
-
107
- // src/loader.ts
108
- async function weaverseLoader(args, components, countries, loaderConfigs) {
109
- return new Promise(async (resolve, reject) => {
110
- try {
111
- let { request, context, params } = args;
112
- let queries = getRequestQueries(request);
113
- let {
114
- WEAVERSE_PROJECT_ID,
115
- WEAVERSE_HOST,
116
- PUBLIC_STORE_DOMAIN,
117
- PUBLIC_STOREFRONT_API_TOKEN
118
- } = context?.env || {};
119
- let { weaverseProjectId, weaverseHost, isDesignMode, weaverseVersion } = queries;
120
- let projectId = weaverseProjectId || WEAVERSE_PROJECT_ID;
121
- weaverseHost = weaverseHost || WEAVERSE_HOST || "https://weaverse.io";
122
- if (!projectId) {
123
- return reject(
124
- new Error(
125
- `Missing Weaverse project's id. Try adding WEAVERSE_PROJECT_ID to your .env file then restart the server.`
126
- )
127
- );
128
- }
129
- let i18n = context?.storefront?.i18n;
130
- let reqBody = {
131
- isDesignMode,
132
- i18n,
133
- countries,
134
- projectId,
135
- loaderConfigs,
136
- url: request.url
137
- };
138
- let url = `${weaverseHost}/api/public/project`;
139
- let payload;
140
- if (isDesignMode) {
141
- payload = await fetch(url, {
142
- method: "POST",
143
- body: JSON.stringify(reqBody)
144
- }).then((res) => res.json());
145
- } else {
146
- payload = await fetchWithServerCache({
147
- url,
148
- options: { method: "POST", body: JSON.stringify(reqBody) },
149
- context
150
- });
151
- }
152
- let { page, project, pageAssignment } = payload;
153
- if (!page || !project || !pageAssignment) {
154
- return reject(
155
- new Error(
156
- // @ts-ignore
157
- payload?.error || "Invalid Weaverse project payload!"
158
- )
159
- );
160
- }
161
- let configs = {
162
- projectId,
163
- weaverseHost,
164
- weaverseVersion,
165
- isDesignMode,
166
- requestInfo: {
167
- i18n,
168
- params,
169
- queries,
170
- pathname: new URL(request.url).pathname,
171
- search: new URL(request.url).search
172
- }
173
- };
174
- if (page?.items) {
175
- let items = page.items;
176
- page.items = await withLoaderData(items, components, configs, args);
177
- }
178
- if (isDesignMode) {
179
- configs.publicEnv = {
180
- PUBLIC_STORE_DOMAIN,
181
- PUBLIC_STOREFRONT_API_TOKEN
182
- };
183
- }
184
- return resolve({ page, configs, project, pageAssignment });
185
- } catch (err) {
186
- console.log(`\u274C Error fetching project data: ${err?.toString()}`);
187
- reject(err);
188
- }
189
- });
190
- }
191
- async function withLoaderData(items, components, configs, args) {
192
- return await Promise.all(
193
- items.map(async (itemData) => {
194
- let type = itemData.type;
195
- let { loader } = components.find(({ schema }) => schema?.type === type) || {};
196
- if (loader && typeof loader === "function") {
197
- try {
198
- return {
199
- ...itemData,
200
- loaderData: await loader({
201
- itemData,
202
- configs,
203
- ...args
204
- })
205
- };
206
- } catch (err) {
207
- console.log(`\u274C Loader run failed! Item: ${itemData}: ${err}`);
208
- return itemData;
209
- }
210
- }
211
- return itemData;
212
- })
213
- );
214
- }
215
-
216
- // src/hydrogen-wrappers.ts
217
- import { getSelectedProductOptions as hydrogen_getSelectedProductOptions } from "@shopify/hydrogen";
218
- function getSelectedProductOptions(request) {
219
- let options = hydrogen_getSelectedProductOptions(request);
220
- return options.filter(
221
- ({ name }) => name !== "isDesignMode" && !name.startsWith("weaverse")
222
- );
223
- }
224
-
225
- // src/hooks/use-theme-settings.ts
226
- import { useWeaverse } from "@weaverse/react";
227
- function useThemeSettings() {
228
- let weaverse = useWeaverse();
229
- let settings = weaverse?.internal?.project?.config?.theme;
230
- return settings;
231
- }
232
-
233
- // src/index.tsx
404
+ // src/WeaverseHydrogenRoot.tsx
234
405
  function WeaverseHydrogenRoot({
235
406
  errorComponent: ErrorComponent,
236
- ...themeConfigs
407
+ components
237
408
  }) {
238
- let data = useLoaderData();
239
- let weaverseData = data?.weaverseData;
240
- if (weaverseData) {
241
- if (weaverseData instanceof Promise) {
242
- return /* @__PURE__ */ React.createElement(ErrorBoundary, { fallbackRender: ErrorComponent }, /* @__PURE__ */ React.createElement(Suspense, null, /* @__PURE__ */ React.createElement(Await, { resolve: weaverseData }, (resolvedData) => {
243
- return /* @__PURE__ */ React.createElement(
244
- RenderWeaverseRoot,
245
- {
246
- weaverseData: resolvedData,
247
- ...themeConfigs
248
- }
249
- );
409
+ let loaderData = useLoaderData2();
410
+ let data = loaderData?.weaverseData;
411
+ if (data) {
412
+ if (data instanceof Promise) {
413
+ return /* @__PURE__ */ React.createElement(ErrorBoundary, { fallbackRender: ErrorComponent }, /* @__PURE__ */ React.createElement(Suspense, null, /* @__PURE__ */ React.createElement(Await, { resolve: data }, (resolvedData) => {
414
+ return /* @__PURE__ */ React.createElement(RenderRoot, { data: resolvedData, components });
250
415
  })));
251
416
  }
252
- return /* @__PURE__ */ React.createElement(RenderWeaverseRoot, { weaverseData, ...themeConfigs });
417
+ return /* @__PURE__ */ React.createElement(RenderRoot, { data, components });
253
418
  }
254
419
  return /* @__PURE__ */ React.createElement(
255
420
  ErrorComponent,
@@ -258,18 +423,20 @@ function WeaverseHydrogenRoot({
258
423
  }
259
424
  );
260
425
  }
261
- function RenderWeaverseRoot(props) {
262
- let { weaverseData, components, countries, themeSchema } = props;
263
- let weaverse = createWeaverseInstance(weaverseData, components);
264
- let { publicEnv } = weaverseData.configs;
265
- useStudio(weaverse, countries, themeSchema, publicEnv);
426
+ function RenderRoot(props) {
427
+ let { data, components } = props;
428
+ let weaverse = createWeaverseInstance(data, components);
429
+ useStudio(weaverse);
266
430
  return /* @__PURE__ */ React.createElement(WeaverseRoot, { context: weaverse });
267
431
  }
268
432
  export {
433
+ WeaverseClient,
269
434
  WeaverseHydrogenRoot,
270
- fetchWithServerCache,
435
+ createContentSecurityPolicy,
436
+ createWeaverseClient,
271
437
  getRequestQueries,
272
438
  getSelectedProductOptions,
273
- useThemeSettings,
274
- weaverseLoader
439
+ getWeaverseConfigs,
440
+ getWeaverseCsp,
441
+ useThemeSettings
275
442
  };
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.17",
2
+ "version": "1.1.19",
3
3
  "license": "MIT",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
@@ -15,8 +15,8 @@
15
15
  },
16
16
  "scripts": {
17
17
  "start": "npm run dev",
18
- "dev": "tsup src/index.tsx --format esm,cjs --dts --outDir dist --watch --external @remix-run/react,@shopify/hydrogen",
19
- "build": "tsup src/index.tsx --format esm,cjs --dts --outDir dist --external @remix-run/react,@shopify/hydrogen",
18
+ "dev": "tsup src/index.ts --format esm,cjs --dts --outDir dist --watch --external @remix-run/react,@shopify/hydrogen",
19
+ "build": "tsup src/index.ts --format esm,cjs --dts --outDir dist --external @remix-run/react,@shopify/hydrogen",
20
20
  "clean": "rimraf dist",
21
21
  "prepublish": "npm run build"
22
22
  },
@@ -32,9 +32,9 @@
32
32
  "name": "@weaverse/hydrogen",
33
33
  "author": "Weaverse Team",
34
34
  "dependencies": {
35
- "@remix-run/react": "1.19.3",
35
+ "@remix-run/react": "1.19.1",
36
36
  "@shopify/hydrogen": "2023.7.7",
37
- "@weaverse/react": "1.1.17",
37
+ "@weaverse/react": "1.1.19",
38
38
  "react-error-boundary": "^4.0.11"
39
39
  },
40
40
  "devDependencies": {