Skip to content

v0.9.1

Choose a tag to compare

@github-actions github-actions released this 17 Oct 17:51
· 169 commits to main since this release

πŸ’₯ Breaking Changes

  • Breaking-ish: now refused β€” a backslash in fragment / raw template text is OKM1125. Pass the value as an interpolation (B-01, D287).
  • Breaking-ish: now refused β€” an unknown key on insert, update, upsert / onConflict, or first-or-create is OKM1120 and names the key and the table (B-39, D291).
  • Breaking-ish: now refused β€” a finished statement with more than 65,535 parameters is OKM1126 (count and limit in the message) instead of a retryable unavailable (B-40, D292).
  • Breaking-ish: now refused β€” an unknown CLI flag is an error; okm <command> --help lists that command's flags (B-26, D289).
  • Breaking-ish: now refused β€” an update that would set a tree parent to the row itself or to a descendant is OKM1120 when where is the primary key (B-10, D295).

πŸ”’ Security

  • A backslash in a composed fragment can no longer desync the literal guard and escape a tenant filter (B-01, D287).
  • A unique, foreign-key, or check failure on a table with a sensitive column no longer puts the value in error.cause (detail, parameters, where, and internalQuery stay off). Tables without sensitive columns keep today's cause. includeValues remains the explicit opt-in (B-33, D291).
  • With defineConfig({ roles }), managed functions revoke EXECUTE from PUBLIC and grant it only to the app role, so the reporting role cannot execute them (B-31, D293). Provider-specific role checks (RDS, Cloud SQL, Supabase) follow in M-4.

πŸ› Fixed

dialects

  • filters() OKM1123 uses the calling table's own columns for allow/sort, and replaces per-table hidden marks when the same SQL name is redefined, so a prior .hidden() no longer poisons later suites that reuse tasks.title (and the same pattern for relation targets).

runtime

  • A statement with more than 65,535 parameters fails with OKM1126 (count and limit in the message) instead of a retryable unavailable. The limit is for the whole statement, including filters and inList (B-40, D292). Split from the write-safety work on #339 when the combined change grew the featureless app by more than 100 B.
  • An update that would set a tree parent to the row itself or to a descendant is OKM1120 when where is the primary key (B-10, D295).
  • A throw from a custom routing.select keeps an OkmError's kind; a plain throw becomes kind invalid instead of driver (B-35, D295).

adapters

  • Bun.sql no longer parks a reserved handle for the next checkout, so concurrent scoped units after a backend kill keep separate sessions and tenant settings (B-03, D288).
  • A reset or release failure after a statement or COMMIT completed destroys the connection and does not fail the call on Bun.sql, node-postgres, or Neon, so a committed write is reported as committed and afterCommit still runs (B-04, D288).
  • node-postgres maps Client has encountered a connection error and is not queryable to a lost connection (CONNECTION_CLOSED), matching Bun.sql's message-only closed texts (D288).
  • Bun.sql reserve() stamps code-less closed-socket texts (Connection closed, connection must be a PostgresSQLConnection) with SQLSTATE 08006, so a checkout that fails before the reserved-handle guard classifies as unavailable instead of driver (B-03, D288).
  • postgres.js caps reconnect backoff under 1 s with jitter, defaults timeouts.acquire to 10 s (OKM1846), swallows nextWrite on a null socket (Bun and Node), and rebuilds the pool so a kill storm's first OK read arrives within 3 s (B-02, B-43, D294). Other uncaught exceptions still print and leave a non-zero exit so okm migrate check / apply refusals are not reported as success on Bun.
  • node-postgres defaults timeouts.acquire to 10 s and keeps an idle/checked-out client error listener that logs on the notice path without throwing, so a backend kill of an idle client does not crash Node (B-44, D294).
  • A node-postgres call with timeout or signal removes its checkout error listener, so repeated timed calls do not stack listeners on a pooled client. A call that reaches its deadline while waiting for a connection is refused and does not run. A cancel that does not settle destroys that client, so the pool can serve the next call after a kill storm.

tooling

  • CI copies the milestone from Closes #N onto the pull request before lint / pull request, so agents that cannot PATCH milestones still pass D206.
  • The sticky migrate-plan comment matches the marker and the bot author, so another author's marked comment is not edited (B-22, D295).
  • okm driver test drops leftover okm_* tables after each wire and error case, refuses Bun below 1.4.0, and never reports an unrun case as pass (B-05, B-06, B-42, D295).
  • okmodel/testing factories and isolation() work under compositeTenancy(); concurrent creates no longer false-positive as a factory cycle; matviews are refreshed in isolation() and documented otherwise (B-32, B-28, B-34, D295).
  • The Bun.sql kill-storm test (B-03) retries post-storm scoped reads on unavailable/closed (bounded) so a dying reserved handle after the storm does not fail CI, without relaxing storm short/leaks/readOnly/nested asserts.
  • okm push plans from the live catalog and applies each change under a fresh push-<n> id, so a second push is no longer skipped (B-29, D289).
  • When the schema hash moves with no DDL (an external table the dependent already verified), okm push and okm migrate apply re-stamp okm_meta instead of leaving connect() on OKM1520 (B-21, D289).
  • okm migrate check keeps a trigger's function in the logical namespace, so schemas with timestamps({ enforce: "trigger" }) or hand-written triggers no longer fail OKM1020 (B-24, D289).
  • okm check and okm push reprint domain checks on the connected server before planning, so a non-canonical author check is not permanent live drift (B-36, D289).
  • The guide's roles block applies as a superuser and as a CREATEROLE schema owner: managed roles are created before SET ROLE, schema ownership is transferred when possible, and a failed role unit stays re-runnable with a clear privilege error. On Postgres 15, apply grants itself membership after CREATE ROLE (which leaves none); on Postgres 16+ it grants WITH SET TRUE (B-30, D293).
  • Migrate strips the pgbouncer query parameter before the URL becomes a startup parameter; other pooler hints are not interpreted (B-25, D293). Provider-specific role-admin checks (RDS, Cloud SQL, Supabase) follow in M-4.
  • The pooler pid probe uses eight reads on the apply session (OKM1854 when the backend pid changes). Warm-and-hold for LIFO PgBouncer is kept out of apply/seed so single-connection targets do not hang; URL heuristics still refuse typical pooler hosts and ports (B-41, D293).
  • The type-change recipe's temporary IS NOT NULL validate is no longer OKM1531 (B-37, D289).
  • An unknown CLI flag is an error; okm <command> --help lists that command's flags (B-26, D289).
  • Backfill progress prints a 1-based step index (B-27, D289).
  • okm pull and okm import drizzle write foreign keys with the exported table binding, keep file stems unique on case-insensitive volumes, and never write a Windows-reserved stem (con, aux, nul, com1, …). A column __proto__ is a computed key. Composite primary-key columns stay not null on Drizzle import. Missing oxfmt prints a notice and still writes the report. okm ext scaffold includes composite types (B-14 to B-19, B-38, D290).

docs

  • Tree, testing, driver-test, and Action docs cover cycle refusal, composite factories, minimum Bun, cleanup, and sticky-comment author matching (D295).
  • Known limits record that Bun.sql does not park reserved handles, that a post-commit reset failure does not fail the call, and that a send-without-result is OKM1401 with no afterCommit (D288).
  • okm push docs say it applies the live schema diff as push-<n>, and known-limits cover external re-stamp and domain-check sealing (D289).
  • Sensitive docs cover redaction in logs, errors, cause, and spans; writes docs cover unknown keys (D291).
  • Queries and the error reference document OKM1126 when a finished statement exceeds 65,535 parameters (D292).
  • Guide roles privileges, production.md --target / status / check behavior, and known-limits pooler notes (DM-2, DM-3, D293).
  • Known limits, README, guide, spec, and handbook pages match the code after the 0.9.1 fixes: Temporal polyfill on Node 22/24, okm dev, okmodel/safety, redaction, untyped raw and raw projection (B-07, B-08), minimum Bun, okmodel.config.ts, listen as a driver capability only, catalog export vs describe, backfill step numbering, and a Not tested section (DM-1 to DM-12, D296).