@decocms/apps-vtex 7.55.2 → 7.56.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/package.json +5 -5
- package/src/middleware.cacheHeaders.test.ts +44 -0
- package/src/mod.ts +18 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@decocms/apps-vtex",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.56.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Deco commerce app: VTEX integration",
|
|
6
6
|
"repository": {
|
|
@@ -51,10 +51,10 @@
|
|
|
51
51
|
"lint:unused": "knip"
|
|
52
52
|
},
|
|
53
53
|
"dependencies": {
|
|
54
|
-
"@decocms/blocks": "7.
|
|
55
|
-
"@decocms/apps-commerce": "7.
|
|
56
|
-
"@decocms/apps-website": "7.
|
|
57
|
-
"@decocms/tanstack": "7.
|
|
54
|
+
"@decocms/blocks": "7.56.0",
|
|
55
|
+
"@decocms/apps-commerce": "7.56.0",
|
|
56
|
+
"@decocms/apps-website": "7.56.0",
|
|
57
|
+
"@decocms/tanstack": "7.56.0"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"@tanstack/react-query": ">=5.0.0",
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { vtexMiddleware } from "./mod";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* The VTEX app middleware wraps the framework's entire edge-cache layer, so it
|
|
6
|
+
* is the last writer of Cache-Control on every response — including cache HITs.
|
|
7
|
+
* These tests pin the two things that made that dangerous.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// A response as the framework's cache layer would hand it over: public headers
|
|
11
|
+
// resolved from the page's cache profile, plus the CDN header.
|
|
12
|
+
function cachedResponse(): Response {
|
|
13
|
+
return new Response("page", {
|
|
14
|
+
headers: {
|
|
15
|
+
"Cache-Control": "public, max-age=120, s-maxage=900, stale-while-revalidate=1800",
|
|
16
|
+
"CDN-Cache-Control": "public, max-age=900",
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const next = async () => cachedResponse();
|
|
22
|
+
|
|
23
|
+
describe("vtexMiddleware cache headers", () => {
|
|
24
|
+
it("leaves the cache layer's headers alone for an anonymous request", async () => {
|
|
25
|
+
const res = await vtexMiddleware(new Request("https://store.com/"), next);
|
|
26
|
+
// Used to be downgraded to vtexCacheControl's generic `s-maxage=60`,
|
|
27
|
+
// throwing away the profile the cache layer had resolved.
|
|
28
|
+
expect(res.headers.get("Cache-Control")).toContain("s-maxage=900");
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it("forces private headers and clears the CDN header when logged in", async () => {
|
|
32
|
+
const req = new Request("https://store.com/", {
|
|
33
|
+
// extractVtexContext treats any VtexIdclientAutCookie* as authenticated.
|
|
34
|
+
headers: { cookie: "VtexIdclientAutCookie_store=abc123" },
|
|
35
|
+
});
|
|
36
|
+
const res = await vtexMiddleware(req, next);
|
|
37
|
+
|
|
38
|
+
expect(res.headers.get("Cache-Control")).toContain("no-store");
|
|
39
|
+
// Cloudflare gives CDN-Cache-Control precedence, so leaving the public
|
|
40
|
+
// value behind would cache a personalized page at the CDN regardless of
|
|
41
|
+
// the private Cache-Control next to it.
|
|
42
|
+
expect(res.headers.get("CDN-Cache-Control")).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
});
|
package/src/mod.ts
CHANGED
|
@@ -96,10 +96,26 @@ export interface VtexState {
|
|
|
96
96
|
// Middleware
|
|
97
97
|
// -------------------------------------------------------------------------
|
|
98
98
|
|
|
99
|
-
const vtexMiddleware: AppMiddleware = async (request, next) => {
|
|
99
|
+
export const vtexMiddleware: AppMiddleware = async (request, next) => {
|
|
100
100
|
const ctx = extractVtexContext(request);
|
|
101
101
|
const response = await next();
|
|
102
|
-
|
|
102
|
+
|
|
103
|
+
// This middleware wraps the framework's whole edge-cache layer, so it is the
|
|
104
|
+
// LAST writer of Cache-Control — including on a cache HIT. It used to
|
|
105
|
+
// overwrite unconditionally, which downgraded a home page the cache layer had
|
|
106
|
+
// resolved as `s-maxage=900` to vtexCacheControl's generic `s-maxage=60`.
|
|
107
|
+
//
|
|
108
|
+
// Now it only speaks up for the case it actually knows better about: a
|
|
109
|
+
// personalized request, which must not be cached anywhere. And when it does,
|
|
110
|
+
// it clears CDN-Cache-Control too — otherwise a response can go out as
|
|
111
|
+
// `Cache-Control: private, no-store` alongside `CDN-Cache-Control: public,
|
|
112
|
+
// max-age=300`, and Cloudflare gives the CDN header precedence. Same pairing
|
|
113
|
+
// the worker's own bypasses use, and utils/proxy.ts's hardenProxyCacheHeaders.
|
|
114
|
+
if (ctx.isLoggedIn || ctx.hasCustomPricing) {
|
|
115
|
+
response.headers.set("Cache-Control", vtexCacheControl(ctx));
|
|
116
|
+
response.headers.delete("CDN-Cache-Control");
|
|
117
|
+
}
|
|
118
|
+
|
|
103
119
|
propagateISCookies(ctx, response);
|
|
104
120
|
return response;
|
|
105
121
|
};
|