@weaverse/hydrogen 5.21.1 → 5.22.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.
@@ -159,6 +159,13 @@ export declare class WeaverseClient {
159
159
  * ```
160
160
  */
161
161
  fetchWithCache: <T = unknown>(url: string, options?: WeaverseFetchWithCacheOptions) => Promise<T>;
162
+ /**
163
+ * Safe origin of the incoming storefront request: scheme, host and explicit
164
+ * port. Userinfo, path, query and fragment are dropped, so no customer
165
+ * route or credential-bearing value leaves the storefront. Returns undefined
166
+ * for a non-http(s) request so the field is simply omitted.
167
+ */
168
+ private safeStorefrontOrigin;
162
169
  /**
163
170
  * Load theme settings from Weaverse API with fallback to schema defaults.
164
171
  * Merges remote settings with local theme schema and handles design mode serialization.
@@ -1 +1 @@
1
- {"version":3,"file":"weaverse-client.d.ts","sourceRoot":"","sources":["../../src/weaverse-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,eAAe,EAGhB,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EACV,eAAe,EACf,eAAe,EAEf,uBAAuB,EAEvB,qBAAqB,EACrB,gBAAgB,EAChB,cAAc,EAGd,qBAAqB,EACrB,kBAAkB,EAClB,kBAAkB,EAClB,sBAAsB,EAGvB,MAAM,SAAS,CAAA;AA6EhB,gFAAgF;AAChF,MAAM,MAAM,qBAAqB,GAC7B,cAAc,GACd,oBAAoB,GACpB,SAAS,GACT,gBAAgB,CAAA;AAEpB,uEAAuE;AACvE,MAAM,WAAW,6BAA8B,SAAQ,WAAW;IAChE,0EAA0E;IAC1E,WAAW,CAAC,EAAE,qBAAqB,CAAA;IACnC,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,eAAe,CAAA;CAC3B;AAED,iFAAiF;AACjF,MAAM,WAAW,uBAAuB;IACtC,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,8DAA8D;IAC9D,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAcD;;;;;;GAMG;AACH,qBAAa,cAAc;IACzB,+CAA+C;IAC/C,GAAG,OAAW;IACd,4DAA4D;IAC5D,eAAe,EAAE,IAAI,CAAC,sBAAsB,EAAE,aAAa,CAAC,CAAA;IAC5D,0DAA0D;IAC1D,mBAAmB,EAAE,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAA;IACzD,yDAAyD;IACzD,OAAO,EAAE,sBAAsB,CAAA;IAC/B,4DAA4D;IAC5D,SAAS,EAAE,UAAU,CAAC,OAAO,eAAe,CAAC,CAAA;IAE7C,6DAA6D;IAC7D,OAAO,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAA;IACtC,yDAAyD;IACzD,eAAe,EAAE,kBAAkB,CAAC,iBAAiB,CAAC,CAAA;IACtD,yDAAyD;IACzD,UAAU,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAA;IAC5C,sEAAsE;IACtE,UAAU,EAAE,kBAAkB,CAAC,YAAY,CAAC,CAAA;IAC5C,yDAAyD;IACzD,WAAW,EAAE,kBAAkB,CAAC,aAAa,CAAC,CAAA;IAC9C,8CAA8C;IAC9C,GAAG,EAAE,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAC9B,sDAAsD;IACtD,KAAK,EAAE,kBAAkB,CAAC,OAAO,CAAC,CAAA;IAClC,gEAAgE;IAChE,SAAS,EAAE,kBAAkB,CAAC,WAAW,CAAC,CAAA;IAG1C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAK;IAC/B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAgC;IAGjE,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAQ;IAEvC,qEAAqE;gBACzD,IAAI,EAAE,kBAAkB;IAuBpC;;;OAGG;IACH,OAAO,CAAC,eAAe;IAcvB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAsDzB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,gBAAgB;IA2BxB;;;;;OAKG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;IAoBzB;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IAe5B;;;OAGG;IACH,OAAO,CAAC,sBAAsB;IAK9B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IA4D3B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAwBzB;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAc9B;;;;OAIG;IACH,OAAO,CAAC,QAAQ,CAAC,SAAS,CAsDzB;IAED,OAAO,CAAC,QAAQ,CAAC,WAAW,CAoB3B;IAGD,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,sBAAsB;IAQ9B;;;;;;;;;;;;;;;;OAgBG;IACI,cAAc,GAAU,CAAC,GAAG,OAAO,EACxC,KAAK,MAAM,EACX,UAAS,6BAAkC,KAC1C,OAAO,CAAC,CAAC,CAAC,CAkDZ;IAED;;;;;;;;;;;;OAYG;IACH,iBAAiB,GACf,WAAW,eAAe,KACzB,OAAO,CAAC,qBAAqB,CAAC,CA8GhC;IAED;;;;OAIG;IACH,OAAO,CAAC,sBAAsB,CAqD7B;IAED;;;;;;OAMG;IACH,oBAAoB,GAAI,SAAS,MAAM,KAAG,gBAAgB,CAczD;IAED;;;OAGG;IACG,gBAAgB,CACpB,IAAI,CAAC,EAAE,uBAAuB,GAC7B,OAAO,CAAC,eAAe,EAAE,CAAC;IAmD7B;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,QAAQ,GACN,SAAQ,cAAmB,KAC1B,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CA+KpC;IAED,gFAAgF;IAChF,mBAAmB,GAAU,MAAM,qBAAqB,oCAqBvD;CACF"}
1
+ {"version":3,"file":"weaverse-client.d.ts","sourceRoot":"","sources":["../../src/weaverse-client.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@weaverse/hydrogen",
3
3
  "author": "Weaverse Team",
4
4
  "description": "Components, hooks, and utilities for building Shopify Hydrogen websites with Weaverse",
5
- "version": "5.21.1",
5
+ "version": "5.22.0",
6
6
  "license": "MIT",
7
7
  "main": "dist/index.js",
8
8
  "typings": "dist/types/index.d.ts",
@@ -46,8 +46,8 @@
46
46
  "dependencies": {
47
47
  "@shopify/hydrogen": ">=2025.5",
48
48
  "@shopify/remix-oxygen": "3",
49
- "@weaverse/react": "5.21.1",
50
- "@weaverse/schema": "0.16.0",
49
+ "@weaverse/react": "5.22.0",
50
+ "@weaverse/schema": "0.17.0",
51
51
  "react": ">=19",
52
52
  "react-dom": ">=19",
53
53
  "react-error-boundary": "^6",
@@ -133,6 +133,33 @@ const SMART_CACHE_STRATEGIES: Record<BuilderApiCacheTarget, CachingStrategy> = {
133
133
  },
134
134
  } as const
135
135
 
136
+ /**
137
+ * Options objects created by the internal `project_configs` request whose
138
+ * subrequest cache identity deliberately excludes the body. Theme settings
139
+ * carry the storefront origin so Builder can attribute hostnames; hashing the
140
+ * body would give every domain of one project its own entry.
141
+ *
142
+ * The SUCCESSFUL theme payload is the same for every storefront of a project,
143
+ * which is what makes one shared entry correct. This is not a claim that
144
+ * Builder can never answer differently per host: a hostname-blocked request
145
+ * returns a 403 `{ error }` body, and `shouldCacheResponse` rejects anything
146
+ * `hasError()` matches, so a refusal is never stored under (or served from)
147
+ * the shared entry. If a future response shape ever varies by host WITHOUT an
148
+ * `error` field, this exclusion has to be revisited.
149
+ *
150
+ * Keyed on the exact options object, NOT on `cacheTarget`: `fetchWithCache`
151
+ * is public API, so gating on the target would silently collapse the cache of
152
+ * any consumer who selects `theme-settings` with varying bodies. An outside
153
+ * caller's options object is never in this set and keeps a body-derived key.
154
+ *
155
+ * The WeakSet-membership slot in the cache key (`has(options)`) is the actual
156
+ * discriminator — no caller-supplied value can reach it. The sentinel is not
157
+ * load-bearing for that; it only keeps the omitted body legible in cache
158
+ * debugging instead of a bare `undefined`.
159
+ */
160
+ const bodyFreeCacheRequests = new WeakSet<object>()
161
+ const BODY_FREE_CACHE_SENTINEL = '\u0000weaverse:body-free'
162
+
136
163
  /**
137
164
  * Request-scoped client for loading Weaverse pages and theme settings in Hydrogen.
138
165
  *
@@ -638,21 +665,32 @@ export class WeaverseClient {
638
665
 
639
666
  // Update cache key to include method, body content, and projectId for multi-project isolation
640
667
  // Prefix for easier debugging in cache systems
668
+ //
669
+ // The body is omitted only for options objects marked internally (see
670
+ // `bodyFreeCacheRequests`): the storefront origin must reach Builder for
671
+ // hostname attribution, but two domains of one project have to share one
672
+ // entry. Every other caller keeps a body-derived key.
641
673
  const cacheKey = [
642
674
  'weaverse-fetch',
643
675
  url,
644
676
  options.method || 'GET',
645
- fetchOptions.body,
677
+ bodyFreeCacheRequests.has(options)
678
+ ? BODY_FREE_CACHE_SENTINEL
679
+ : fetchOptions.body,
680
+ // WeakSet-derived discriminator: this slot cannot be produced by any
681
+ // caller-supplied shape, so no external call can reach the marked
682
+ // identity — even one that happens to send the sentinel string as its
683
+ // body.
684
+ bodyFreeCacheRequests.has(options),
646
685
  this.configs.projectId,
647
686
  cacheTarget || 'default',
648
687
  ]
649
-
650
688
  let result: WithCacheFetchResponse<T>
651
689
 
652
690
  // Bypass the shared Hydrogen subrequest cache for design/revision modes
653
691
  // and for the Cloudflare public API proxy. The proxy owns freshness with
654
692
  // versioned cache keys; keeping Hydrogen's URL/body cache in front would
655
- // keep serving a stale response even after Builder bumps api.weaverse.io's
693
+ // keep serving a stale response even after Builder bumps the proxy's
656
694
  // project version.
657
695
  if (
658
696
  this.configs.isDesignMode ||
@@ -678,6 +716,20 @@ export class WeaverseClient {
678
716
  return result.data
679
717
  }
680
718
 
719
+ /**
720
+ * Safe origin of the incoming storefront request: scheme, host and explicit
721
+ * port. Userinfo, path, query and fragment are dropped, so no customer
722
+ * route or credential-bearing value leaves the storefront. Returns undefined
723
+ * for a non-http(s) request so the field is simply omitted.
724
+ */
725
+ private safeStorefrontOrigin(): string | undefined {
726
+ const { protocol, host } = this.parsedUrl
727
+ if (protocol !== 'http:' && protocol !== 'https:') {
728
+ return
729
+ }
730
+ return host ? `${protocol}//${host}` : undefined
731
+ }
732
+
681
733
  /**
682
734
  * Load theme settings from Weaverse API with fallback to schema defaults.
683
735
  * Merges remote settings with local theme schema and handles design mode serialization.
@@ -704,21 +756,41 @@ export class WeaverseClient {
704
756
 
705
757
  const url = this.getApiUrl('project_configs')
706
758
 
707
- const body = JSON.stringify({ isDesignMode, projectId })
759
+ // Theme/config reads carry no route, so Builder could not tell which
760
+ // storefront asked. `storefrontUrl` is the request's safe origin only —
761
+ // scheme, host and explicit port, never a path, query, fragment or
762
+ // userinfo — so hosted-content attribution works without sending
763
+ // customer-visible URL data. Older Builder deployments ignore the extra
764
+ // field. The response does not vary by storefront, so the origin stays
765
+ // out of BOTH cache identities: the edge excludes it from its selectors,
766
+ // and this request is marked in `bodyFreeCacheRequests` so Hydrogen's
767
+ // own subrequest cache key omits the body — hashing it would otherwise
768
+ // give every domain of one project its own entry.
769
+ const body = JSON.stringify({
770
+ isDesignMode,
771
+ projectId,
772
+ storefrontUrl: this.safeStorefrontOrigin(),
773
+ })
774
+
775
+ // Fetch theme settings and merchant overrides in parallel. The options
776
+ // object is registered in `bodyFreeCacheRequests` so `fetchWithCache`
777
+ // keeps the storefront origin out of the subrequest cache identity for
778
+ // exactly this internal request — see the marker's doc comment.
779
+ const themeSettingsOptions: WeaverseFetchWithCacheOptions = {
780
+ method: 'POST',
781
+ cacheTarget: 'theme-settings',
782
+ strategy,
783
+ body,
784
+ headers: {
785
+ 'Content-Type': 'application/json',
786
+ Accept: 'application/json',
787
+ 'Accept-Encoding': 'gzip, deflate, br',
788
+ },
789
+ }
790
+ bodyFreeCacheRequests.add(themeSettingsOptions)
708
791
 
709
- // Fetch theme settings and merchant overrides in parallel
710
792
  const [data, merchantOverrides] = await Promise.all([
711
- this.fetchWithCache<ThemeSettingsResponse>(url, {
712
- method: 'POST',
713
- cacheTarget: 'theme-settings',
714
- strategy,
715
- body,
716
- headers: {
717
- 'Content-Type': 'application/json',
718
- Accept: 'application/json',
719
- 'Accept-Encoding': 'gzip, deflate, br',
720
- },
721
- }),
793
+ this.fetchWithCache<ThemeSettingsResponse>(url, themeSettingsOptions),
722
794
  this.fetchMerchantOverrides(strategy),
723
795
  ])
724
796