Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion spec/saas-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ The write-space split applies to mutations only (`PUT`, `DELETE`, lock, TTL refr
> [!WARNING]
> **The split covers `ns:`- and `nsapi:`-prefixed cache keys only.** A cache key with neither prefix maps to the tenant's `default` namespace and belongs to a **shared write space**: any key class whose namespace grants include `default` **or are unrestricted** may create, overwrite, delete, or lock it. The split is an intra-tenant guard for namespaced keys, not a general write-isolation guarantee between key classes.

**CORS preflight exception.** `OPTIONS` on any path is answered `204 No Content` before authentication; no `Authorization` or `X-CacheKit-L1-Status` header is required or inspected. Every other `/v1/cache/*` request is authenticated before any other check, and the authentication outcome — `401`, or `503` for a key-store fault while checking the key — precedes every other error. Browser callers are outside this specification's scope, and **no key class is intended for delivery to browser code** — an API key in client-side JavaScript is a tenant-wide credential exposed to every visitor. The deployed CORS policy returns `Access-Control-*` headers only for a closed allowlist of first-party origins; for every other origin the preflight carries none and the browser blocks the request. Even from an allowlisted origin the policy allows `Authorization` but no `X-CacheKit-*` request header and exposes no `X-CacheKit-*` response header, so `ck_sdk_` keys cannot be used cross-origin and freshness headers are unreadable there. This specification governs `/v1/cache/*` only.
**CORS preflight exception.** `OPTIONS` on any path is answered `204 No Content` before authentication; no `Authorization` or `X-CacheKit-L1-Status` header is required or inspected. Every other `/v1/cache/*` request is authenticated before any other check, and the authentication outcome — `401`, or `503` for a key-store fault while checking the key — precedes every other error. Browser callers are outside this specification's scope, and **no key class is intended for delivery to browser code** — an API key in client-side JavaScript is a tenant-wide credential exposed to every visitor. The deployed CORS policy returns `Access-Control-*` headers only for a closed allowlist of first-party origins; for every other origin the preflight carries none and the browser blocks the request. Even from an allowlisted origin the policy allows `Authorization` but no `X-CacheKit-*` request header, and of the `X-CacheKit-*` response headers it exposes only `X-CacheKit-Limiter` and `X-CacheKit-Deny-Reason` — not `X-CacheKit-Freshness` or `X-CacheKit-Fresh-For` — so `ck_sdk_` keys cannot be used cross-origin and freshness headers are unreadable there. This specification governs `/v1/cache/*` only.

**HTTP intermediary caching is prohibited.** Servers MUST<sup id="api-2">API-2</sup> emit `Cache-Control: no-store` and `Vary: Authorization` on every response. The [cache key](cache-key-format.md) carries no tenant component — tenancy rides only in the `Authorization` header — so two tenants using the same namespace, function, and arguments produce byte-identical request paths, and a shared HTTP cache applying heuristic freshness (RFC 9111 §4.2.2) to an unmarked response could serve one tenant's bytes to another. `no-store` forbids storing the response at all; `Vary: Authorization` is the independent second control — a cache that wrongly stores despite `no-store` (or RFC 9111 §3.5's rule for authenticated requests) but honors `Vary` still cannot match tenant A's copy to tenant B's request. Any CacheKit-operated serving tier that caches responses (edge, colo) MUST<sup id="api-3">API-3</sup> partition its internal cache by tenant, never by URL alone; such tiers are part of the server, not HTTP intermediaries, and these headers govern what they emit, not what they may store.

Expand Down
Loading