0.22

Every published okengine release, newest first.

all series · 0.21

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 while do runs. Rows live in oke_idempotency on the journal driver until the TTL (default 24h). The client sends one key per non-GET call and surfaces Idempotent-Replayed: true as meta.idempotentReplayed. The key is 21 characters from crypto.getRandomValues through the okid alphabet, so a page on plain HTTP still sends one. If crypto is 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-function fx.store chain alias. liveQuery and applySearchEmbedCdc record 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 to vault.audit.webhookUrl. oke vault audit (list, verify, purge) stays on the SQL hash chain and refuses stdout / webhook.
  • otp({ mode: "provider" }) exposes POST /auth/otp/resend for the same SMS number. The provider issues a new code; resendCooldownMs applies. 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/http static import graph fails CI when zod or 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 retry configured, a call retries when it is GET/QUERY or it carries an idempotency key (automatic on every non-GET call). idempotencyKey: false runs once unless that call passes { retry: true }. A 409 IdempotencyInProgress waits for Retry-After and retries within those attempts.
  • createTestApp enforces Manifest tokens. Inline tests that are not an app pass capability: "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 parameter fx and keep chain aliases in the same function. An explicit effects block must include every effect inference can see. It may add keys. It no longer replaces the inferred set.
  • Store RLS emit calls pgTable.withRLS whenever rls: 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). Drizzle rc5 moves to 1.0.0-rc.5-5935859 for both orm and kit. The SQL condition compiler accepts the new and() / or() wrappers ("((", ") and (").
  • fx.fetch, Meilisearch, and remote Vault HTTP abort with the ambient fx.signal (fx.race / fx.all). An effect that has not started throws AbortError. SQL, Redis, and an in-flight sently Channel send still finish.

Dev, Keel & create-oke

  • Compose pins: Mailpit v1.31.2, PgDog v0.1.59, Meilisearch v1.54. A Meilisearch minor can need a dump and restore. create-oke, templates, and Keel follow the same zod / DuckDB / @clack/prompts bumps, and the same Drizzle rc5 hash.
  • okengine and create-oke are licensed under Apache-2.0.

Docs

  • Docs site dependencies: next 16.3.6, fumadocs 16.15.13 (core and @fumadocs/base-ui paired), fumadocs-mdx 15.4.3, lucide-react ^1.48.0. Tenancy and Reference sidebar icons use Building and BookBookmark (Building2 and BookMarked left 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 stricter AstNode narrowing 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 so Honored / canHonor are not hits. The JSR dry-run uses an installed Deno binary when one is on PATH, 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. out stays on the exposure; the Flow is do.