v0.22.0
✨ Added
- HTTP idempotency. A mutating call can send
Idempotency-Key. The server claims it after the gate and validation, replays the stored response, and holds a lease whiledoruns. Rows live inoke_idempotencyon the journal driver until the TTL (default 24h). The client sends one key per non-GET call and surfacesIdempotent-Replayed: trueasmeta.idempotentReplayed. The key is 21 characters fromcrypto.getRandomValuesthrough the okid alphabet, so a page on plain HTTP still sends one. Ifcryptois missing, the call sends no key and runs once. - Client gzip budget is **6 kB** (was 5 kB). The growth is the idempotency feature, not waste: measured client gzip is 5194, which was over 90% of 5120.
- Effect inference follows a project helper whose parameter is named
fx, and a same-functionfx.storechain alias.liveQueryandapplySearchEmbedCdcrecord their effects as package intrinsics. The shorter starter's link flows stamp the SQL, KV, and signal effects those helpers perform. - Vault
audit.sink: "webhook"POSTs each operation as secret-free JSON tovault.audit.webhookUrl.oke vault audit(list, verify, purge) stays on the SQL hash chain and refusesstdout/webhook. otp({ mode: "provider" })exposesPOST /auth/otp/resendfor the same SMS number. The provider issues a new code;resendCooldownMsapplies. Another channel is rejected.- Absolute budget samples that can still double and stay under their cap (cold start, and console initial load while it sits this far under 700 kB) fail CI at 2× the last committed value. The 75 ms cold-start cap stays. The probe keeps the best of five rounds and confirms a failure once, so one noisy run does not fail the build.
- The
okengine/httpstatic import graph fails CI whenzodor the hybrid-search runtime is included. Forbidden modules live in one list, so the next heavy module is a single entry. - Agent skill
oke-perf— before a release, measure budgets, flag drift the gates still allow, bisect to the commit, and fix it with a lazy import,createDebouncedRunner, or a memo (/oke-perf).
💥 Breaking Changes
- With
retryconfigured, a call retries when it is GET/QUERY or it carries an idempotency key (automatic on every non-GET call).idempotencyKey: falseruns once unless that call passes{ retry: true }. A409 IdempotencyInProgresswaits forRetry-Afterand retries within those attempts. createTestAppenforces Manifest tokens. Inline tests that are not an app passcapability: "open". App suites pick the tokens up from the project root.- Code that renames, destructures, or lets
fx(or a chain alias) escape fails extract with **OKE1900**. Name the parameterfxand keep chain aliases in the same function. An expliciteffectsblock must include every effect inference can see. It may add keys. It no longer replaces the inferred set. - Store RLS emit calls
pgTable.withRLSwheneverrls: true. After upgrading, a command without a policy returns zero rows, with no error, and there is no runtime warning. Shorter adds an open SELECT policy in the same change.
♻️ Changed
Runtime
- Dependency refresh: Console and tooling patches and minors (
zod^4.6.5, TanStack Query^5.103.2, Router^1.170.39, oxlint^1.85.0, motion^13.4.2, and the matching CodeMirror, DuckDB, and Happy DOM releases). Drizzlerc5moves to1.0.0-rc.5-5935859for both orm and kit. The SQL condition compiler accepts the newand()/or()wrappers ("((",") and ("). fx.fetch, Meilisearch, and remote Vault HTTP abort with the ambientfx.signal(fx.race/fx.all). An effect that has not started throwsAbortError. SQL, Redis, and an in-flight sently Channel send still finish.
Dev, Keel & create-oke
- Compose pins: Mailpit
v1.31.2, PgDogv0.1.59, Meilisearchv1.54. A Meilisearch minor can need a dump and restore. create-oke, templates, and Keel follow the same zod / DuckDB /@clack/promptsbumps, and the same Drizzlerc5hash. - okengine and create-oke are licensed under Apache-2.0.
Docs
- Docs site dependencies:
next16.3.6, fumadocs16.15.13(core and@fumadocs/base-uipaired),fumadocs-mdx15.4.3,lucide-react^1.48.0. Tenancy and Reference sidebar icons useBuildingandBookBookmark(Building2andBookMarkedleft the Lucide icon map). Recipe and configuration examples use the new Mailpit, PgDog, and Meilisearch pins. - Landing hero rail no longer shows the client gzip cell — cold start and routing p99 stay; package size stays in budgets / CI, not the stage strip.
- [Routing](/docs/understand/routing) moved from Flow into Understand (Architecture → Routing → Try it).
🐛 Fixed
Runtime
- Typecheck stays green on current Bun
fetch(preconnect) and stricterAstNodenarrowing in effect inference, vault audit tests, the idempotency client test, and OTP provider resend. - Scaffold tests expect
@duckdb/node-api^1.5.5-r.5. The competitor-name gate matches the router peer on a word boundary soHonored/canHonorare not hits. The JSR dry-run uses an installed Deno binary when one is onPATH, so the npm wrapper does not stall downloading its own.
Docs
- README quick start puts the health contract on
http.get({ out: HealthOut }), matching the create-oke starter.outstays on the exposure; the Flow isdo.