Remove CDN Cache-Control headers; fix cross-language sort bug
Mizan's protocol layers (origin Redis cache, Edge Worker) handle caching
autonomously. The origin emits Cache-Control: no-store on ALL responses —
browsers and non-Mizan intermediaries must not cache. The Edge Worker
controls CDN caching via cf object, independent of origin headers.
Also fixes:
- TS localeCompare → byte-order sort (localeCompare is locale-sensitive,
would produce different HMAC keys for non-ASCII params vs Python)
- Python cache_purge: empty {} params no longer treated as falsy
(was inconsistent with JS where {} is truthy)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2
packages/mizan-ts/src/cache/keys.ts
vendored
2
packages/mizan-ts/src/cache/keys.ts
vendored
@@ -40,7 +40,7 @@ export function deriveCacheKey(
|
||||
rev: number = 0,
|
||||
): string {
|
||||
const sortedParams: Record<string, string> = {}
|
||||
for (const [k, v] of Object.entries(params).sort(([a], [b]) => a.localeCompare(b))) {
|
||||
for (const [k, v] of Object.entries(params).sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)) {
|
||||
sortedParams[k] = String(v)
|
||||
}
|
||||
|
||||
|
||||
@@ -60,18 +60,10 @@ export async function handleContextFetch(
|
||||
try {
|
||||
const cached = cacheGet(cacheSecret, cacheBackend, contextName, params, undefined, effectiveRev)
|
||||
if (cached !== null) {
|
||||
// Resolve cache policy for headers
|
||||
let cc: number | boolean = true
|
||||
for (const fn of fnNames) {
|
||||
const e = getFunction(fn)
|
||||
if (e?.cache === false) { cc = false; break }
|
||||
if (typeof e?.cache === 'number') cc = cc === true ? e.cache : Math.min(cc as number, e.cache)
|
||||
}
|
||||
const cacheControl = cc === false ? 'no-store' : typeof cc === 'number' ? `public, max-age=0, s-maxage=${cc}` : 'public, max-age=0, s-maxage=31536000'
|
||||
return {
|
||||
status: 200,
|
||||
body: JSON.parse(cached),
|
||||
headers: { 'Content-Type': 'application/json', 'Cache-Control': cacheControl, 'X-Mizan-Cache': 'HIT' },
|
||||
headers: { 'Content-Type': 'application/json', 'Cache-Control': 'no-store', 'X-Mizan-Cache': 'HIT' },
|
||||
}
|
||||
}
|
||||
} catch { /* cache miss on error */ }
|
||||
@@ -106,7 +98,7 @@ export async function handleContextFetch(
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve effective cache policy (minimum TTL across all functions)
|
||||
// Resolve effective cache policy for origin-side cache decision
|
||||
let effectiveCache: number | boolean = true
|
||||
for (const fnName of fnNames) {
|
||||
const entry = getFunction(fnName)
|
||||
@@ -119,16 +111,7 @@ export async function handleContextFetch(
|
||||
}
|
||||
}
|
||||
|
||||
let cacheControl: string
|
||||
if (effectiveCache === false) {
|
||||
cacheControl = 'no-store'
|
||||
} else if (typeof effectiveCache === 'number') {
|
||||
cacheControl = `public, max-age=0, s-maxage=${effectiveCache}`
|
||||
} else {
|
||||
cacheControl = 'public, max-age=0, s-maxage=31536000'
|
||||
}
|
||||
|
||||
// Store in origin-side cache
|
||||
// Store in origin-side cache (skip if cache=False)
|
||||
if (cacheBackend && cacheSecret && effectiveCache !== false) {
|
||||
try {
|
||||
cachePut(cacheSecret, cacheBackend, contextName, params, JSON.stringify(results), undefined, effectiveRev)
|
||||
@@ -140,7 +123,7 @@ export async function handleContextFetch(
|
||||
body: results,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Cache-Control': cacheControl,
|
||||
'Cache-Control': 'no-store',
|
||||
...(cacheBackend && cacheSecret ? { 'X-Mizan-Cache': 'MISS' } : {}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ export function formatInvalidateHeader(invalidate: InvalidateEntry[]): string {
|
||||
const { context, params } = entry
|
||||
if (params && Object.keys(params).length > 0) {
|
||||
const paramStr = Object.entries(params)
|
||||
.sort(([a], [b]) => a.localeCompare(b))
|
||||
.sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0)
|
||||
.map(([k, v]) => `${encodeURIComponent(String(k))}=${encodeURIComponent(String(v))}`)
|
||||
.join(';')
|
||||
parts.push(`${context};${paramStr}`)
|
||||
|
||||
Reference in New Issue
Block a user