@spree/docs 0.1.277 → 0.1.279
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/api-reference/store-api/localization.md +10 -0
- package/dist/developer/core-concepts/pricing.md +1 -1
- package/dist/developer/deployment/caching.md +17 -0
- package/dist/developer/deployment/cdn.md +2 -0
- package/dist/developer/how-to/build-a-marketplace.md +8 -1
- package/dist/developer/how-to/custom-delivery-rate-provider.md +12 -6
- package/package.json +1 -1
|
@@ -128,6 +128,16 @@ Each value is resolved in the following order:
|
|
|
128
128
|
|
|
129
129
|
> **NOTE:** The locale and currency must be supported by the current store. If an unsupported value is provided, the API falls back to the store's default.
|
|
130
130
|
|
|
131
|
+
### Caching
|
|
132
|
+
|
|
133
|
+
Cacheable guest responses (products, categories, collections, markets, locales, currencies, policies, sellers) are sent with `Cache-Control: public` and:
|
|
134
|
+
|
|
135
|
+
```
|
|
136
|
+
Vary: Accept, X-Spree-Api-Key, Authorization, X-Spree-Country, X-Spree-Currency, X-Spree-Locale, X-Spree-Channel
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
A CDN or shared cache therefore stores one copy per country, currency, locale and channel, so a visitor in one market never receives another market's prices. The `country`, `currency` and `locale` query parameters are part of the URL, so they are cached separately without needing `Vary`. Responses to signed-in customers are `Cache-Control: private, no-store`.
|
|
140
|
+
|
|
131
141
|
## Translated Content
|
|
132
142
|
|
|
133
143
|
When a locale is set, all translatable fields are returned in the requested language. This includes product names, descriptions, category names, and other content managed through [translations](../../developer/core-concepts/translations.md).
|
|
@@ -220,7 +220,7 @@ When resolving prices, Spree considers the full context of the request:
|
|
|
220
220
|
|
|
221
221
|
The Store API automatically builds this context from the [request headers](../../api-reference/store-api/localization.md) (`X-Spree-Currency`, `X-Spree-Country`) and authentication state. You don't need to construct it manually — just make API requests and the correct price is resolved.
|
|
222
222
|
|
|
223
|
-
> **INFO:** Price resolution runs per request — there is no in-process caching of resolved prices. The Store API instead relies on HTTP/CDN caching, with `Vary` headers keyed on the `X-Spree-
|
|
223
|
+
> **INFO:** Price resolution runs per request — there is no in-process caching of resolved prices. The Store API instead relies on HTTP/CDN caching, with `Vary` headers keyed on every request header that changes the price — `X-Spree-Country` (market), `X-Spree-Currency`, `X-Spree-Locale`, `X-Spree-Channel`, the publishable key and `Authorization` — so each combination is cached separately at the edge. See [HTTP caching](../deployment/caching.md#http-caching-of-store-api-responses).
|
|
224
224
|
|
|
225
225
|
## Time-Based Pricing
|
|
226
226
|
|
|
@@ -23,6 +23,23 @@ config.cache_store = :redis_cache_store, { url: ENV["REDIS_URL"] }
|
|
|
23
23
|
|
|
24
24
|
Works identically with Redis or Valkey (the Linux Foundation fork most hosting platforms now provision).
|
|
25
25
|
|
|
26
|
+
## HTTP caching of Store API responses
|
|
27
|
+
|
|
28
|
+
Read-only Store API endpoints (products, categories, collections, markets, locales, currencies, policies, sellers) are HTTP-cacheable for guests, so a CDN or reverse proxy in front of Spree can serve them from the edge:
|
|
29
|
+
|
|
30
|
+
- **Guests** get `Cache-Control: public, max-age=300` (list endpoints add `stale-while-revalidate=30`) plus an `ETag`, and conditional requests return `304 Not Modified`.
|
|
31
|
+
- **Signed-in customers** (a customer JWT in `Authorization`) get `Cache-Control: private, no-store` — nothing is cached.
|
|
32
|
+
|
|
33
|
+
Guest responses carry this `Vary` header:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
Vary: Accept, X-Spree-Api-Key, Authorization, X-Spree-Country, X-Spree-Currency, X-Spree-Locale, X-Spree-Channel
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Each of these headers changes the response body: the publishable key selects the store, `X-Spree-Country` selects the market (currency, prices, tax display, availability), and `X-Spree-Channel` controls price visibility and which products are listed. `Authorization` keeps a cached guest response from being served to a signed-in customer.
|
|
40
|
+
|
|
41
|
+
> **WARNING:** If your CDN ignores `Vary` or builds its own cache key (for example Cloudflare Cache Rules with a custom cache key), include every header listed above in that key, or it serves one market's or store's prices to another.
|
|
42
|
+
|
|
26
43
|
## Testing Locally
|
|
27
44
|
|
|
28
45
|
To enable caching in the development environment:
|
|
@@ -6,6 +6,8 @@ description: >-
|
|
|
6
6
|
|
|
7
7
|
To improve performance of your Spree application, we recommend using a CDN (Content Delivery Network) to cache images and static files.
|
|
8
8
|
|
|
9
|
+
> **NOTE:** If you also cache Store API responses at the CDN, the cache key must include every header in the response's `Vary` header — see [HTTP caching of Store API responses](caching.md#http-caching-of-store-api-responses).
|
|
10
|
+
|
|
9
11
|
We recommend using [Cloudflare](https://www.cloudflare.com/) as your CDN provider. It's free and simple to set up.
|
|
10
12
|
|
|
11
13
|
After setting up your Cloudflare account and adding your domain name to Cloudflare, you will need to set your cache settings.
|
|
@@ -714,9 +714,16 @@ const tokens = await sellerClient.auth.login({
|
|
|
714
714
|
sellerClient.setToken(tokens.token)
|
|
715
715
|
|
|
716
716
|
// A user who runs several sellers picks which one they are acting as
|
|
717
|
-
sellerClient.
|
|
717
|
+
const { sellers } = await sellerClient.me.get()
|
|
718
|
+
sellerClient.setSeller(sellers[0].id)
|
|
719
|
+
|
|
720
|
+
// The signed-in person edits their own account (name, photo, panel language);
|
|
721
|
+
// the seller business itself is `sellerClient.profile.update(...)`
|
|
722
|
+
await sellerClient.me.update({ first_name: 'Ada', selected_locale: 'de' })
|
|
718
723
|
```
|
|
719
724
|
|
|
725
|
+
> **NOTE:** `sellerClient.me` is an object with `get()` and `update()`. Code written against `@spree/seller-sdk` 1.0.0-beta.1 or beta.2 that calls `sellerClient.me()` directly keeps working, but that form is deprecated and logs a one-time warning — switch to `sellerClient.me.get()`.
|
|
726
|
+
|
|
720
727
|
Authentication is JWT only. **There is deliberately no secret-key equivalent**: a key that acts as a seller without a seller signing in is exactly what the Seller API's design exists to prevent. Sign-in fails for a store staff member who runs no seller, even though staff share the same user class.
|
|
721
728
|
|
|
722
729
|
The chosen seller travels as `X-Spree-Seller-Id`. The store is derived from the seller server-side and never sent alongside, so no header a client can set widens what it reaches.
|
|
@@ -93,13 +93,19 @@ module SpreeAcmeCarrier
|
|
|
93
93
|
# One API call serves every delivery method sharing this provider within
|
|
94
94
|
# a request — carriers return all services in one response, so quoting
|
|
95
95
|
# five methods should not mean five round-trips.
|
|
96
|
+
#
|
|
97
|
+
# Key the cache on everything the request sends, not on the location and
|
|
98
|
+
# order: an order split into several packages from one stock location
|
|
99
|
+
# would otherwise get the first package's rates for every package.
|
|
100
|
+
# Digesting the payload itself keeps the key complete as the request grows.
|
|
96
101
|
def quotes_for(package)
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
)
|
|
102
|
+
request = {
|
|
103
|
+
from: package.stock_location.slice(:address1, :city, :zipcode, :country_id),
|
|
104
|
+
to: package.owner.ship_address.slice(:address1, :city, :zipcode, :country_id),
|
|
105
|
+
parcel: { weight: package.weight.to_f }
|
|
106
|
+
}
|
|
107
|
+
key = [:acme_quotes, store.id, Digest::SHA256.hexdigest(request.to_json)]
|
|
108
|
+
Spree::Current.provider_cache[key] ||= integration.client.rates(**request)
|
|
103
109
|
end
|
|
104
110
|
end
|
|
105
111
|
end
|