@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.
- package/dist/index.js +39 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +39 -13
- package/dist/index.mjs.map +1 -1
- package/dist/types/weaverse-client.d.ts +7 -0
- package/dist/types/weaverse-client.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/weaverse-client.ts +88 -16
|
@@ -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;
|
|
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.
|
|
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.
|
|
50
|
-
"@weaverse/schema": "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",
|
package/src/weaverse-client.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|