@stacksjs/defaults 0.75.60 → 0.75.61

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.
@@ -168,10 +168,36 @@ export function responseMayUseCsrfToken(response: Response): boolean {
168
168
  || type.endsWith('+json')
169
169
  }
170
170
 
171
+ /**
172
+ * Whether a response told shared caches they may keep it: its `Cache-Control`
173
+ * says `public` or gives an `s-maxage`, and says neither `private` nor
174
+ * `no-store`.
175
+ *
176
+ * Such a response is, by its own account, the same for everyone, so it must
177
+ * not carry a per-visitor cookie. A CDN refuses to store a response that sets
178
+ * one (Cloudflare answers `cf-cache-status: BYPASS`), so seeding here kept
179
+ * every shareable API read out of the edge; and a cache that stored it anyway
180
+ * would hand one visitor's token to everybody behind it.
181
+ */
182
+ export function responseDeclaresShared(response: Response): boolean {
183
+ const value = (response.headers.get('cache-control') || '').toLowerCase()
184
+ if (!value || /\b(?:private|no-store)\b/.test(value))
185
+ return false
186
+ return /\bpublic\b/.test(value) || /\bs-maxage\s*=/.test(value)
187
+ }
188
+
171
189
  export function seedCsrfCookieIfMissing(req: Request, response: Response, minted?: string, responseHasNoCookies = false): Response {
172
190
  if (!responseMayUseCsrfToken(response))
173
191
  return response
174
192
 
193
+ // Nothing depends on a shareable response seeding the cookie: a page that
194
+ // carries forms is per-visitor and never says `public`, and a client about to
195
+ // submit without a cookie can ask for one from a response that is not shared.
196
+ // This holds for every layer that seeds - the API router, and the page server
197
+ // that proxies `/api` to it - because they all come through here.
198
+ if (responseDeclaresShared(response))
199
+ return response
200
+
175
201
  // A token the router minted before rendering wins over "the header already
176
202
  // has one", because it put that value in the header itself - and the page
177
203
  // has already embedded it in every form it drew. Generating a second token
@@ -2,7 +2,7 @@
2
2
  "publisher": "Stacks",
3
3
  "name": "vscode-stacks",
4
4
  "displayName": "Stacks",
5
- "version": "0.75.60",
5
+ "version": "0.75.61",
6
6
  "description": "Stacks, built into VS Code: stx templates, pickier linting and formatting, encrypted env files, the dev server preview and every buddy command. No other extensions required.",
7
7
  "license": "MIT",
8
8
  "funding": "https://github.com/sponsors/chrisbbreuer",
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@stacksjs/defaults",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "0.75.60",
5
+ "version": "0.75.61",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "git+https://github.com/stacksjs/stacks.git",
@@ -55,7 +55,7 @@
55
55
  "dependencies": {
56
56
  "@iconify-json/f7": "^1.2.2",
57
57
  "@iconify-json/hugeicons": "^1.2.35",
58
- "@stacksjs/mobile": "^0.75.60",
58
+ "@stacksjs/mobile": "^0.75.61",
59
59
  "@stacksjs/sanitizer": "^0.2.348",
60
60
  "ts-qr-codes": "^0.1.8"
61
61
  }