@voltro/ui 0.82.0 → 0.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/CHANGELOG.md +286 -0
  2. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -39,6 +39,292 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.83.0] — 2026-10-03
43
+
44
+ ### ⚠ BREAKING
45
+
46
+ - **Aggregate materializations live in declared framework tables** — `@voltro/cli`
47
+
48
+ On a SQL store, `*.aggregate.ts` materializations were kept in `_voltro_aggregate_meta` / `_voltro_aggregate_rows`, created with raw `CREATE TABLE IF NOT EXISTS` at boot and written with raw SQL on a connection pool of their own — outside the declared schema, so no `voltro db plan`, schema fingerprint, backup or transfer saw them. Both are declared framework tables now, part of the schema of every app with an `*.aggregate.ts` file: `voltro db apply` creates them, and the materializer reads and writes them through the app's own store. A commit still replaces a whole generation in one transaction, and a reader still never sees rows of one generation with the meta of another. The columns are named like every other framework table (`aggregateName`, `rowIndex`, `rowData`, `refreshedAt`, …).
49
+
50
+ **`voltro update` carries you across this** — codemod `0.83.0/07_aggregate-tables-are-declared-framework-tables`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
51
+ - **The analytics mirror's tables are declared, never created by the sink** — `@voltro/plugin-analytics-postgres`
52
+
53
+ `postgresAnalytics({ mirrorTables })` created each `_voltro_mirror_<table>` with raw `CREATE TABLE IF NOT EXISTS` on its first write — outside the declared schema, so no `voltro db plan`, fingerprint, backup or transfer saw it. The mirror tables are now part of the sink's `tables`, beside `_voltro_events`, so `voltro db apply` creates them; the sink creates nothing. They keep exactly the shape the sink always created, so a database that already holds mirrored rows plans nothing against them. `postgresAnalyticsTables(options)` returns every table the sink writes; with a separate `sqlClient` database, apply it there — the sink no longer creates mirror tables in that database on first write.
54
+
55
+ **`voltro update` carries you across this** — codemod `0.83.0/08_analytics-mirror-tables-are-declared`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
56
+ - **CMS review decisions follow a persisted sequence** — `@voltro/cms`, `@voltro/cli`
57
+
58
+ CMS review steps now use a persisted sequence and a transactional draft-row lock, so identical timestamps, clock skew, and concurrent decisions cannot select a stale review status. `reviewStatus` adds `ReviewStepRefused` to its Effect error channel, and that error's reason union adds `ambiguousOrder`: widen explicit error annotations and handle this case by offering a new review request, never by assuming approval. Before resuming review writes on all replicas, stop the writers, apply the declared `cms_reviews.sequence` column with `voltro db apply`, and update every writer. Existing rows retain their history at sequence zero; ambiguous latest timestamps refuse decisions until a new review request starts a numbered round. Review writes must use the caller's transaction.
59
+
60
+ **`voltro update` carries you across this** — codemod `0.83.0/04_cms-review-status-failure`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
61
+ - **Update custom dashboard inspection adapters** — `@voltro/cli`, `@voltro/devtools-ui`
62
+
63
+ Custom `buildClusterInspect` callers now supply the effective `coordination` instead of `useClusterCron` and `scheduleCoordChoice`. Pass the initialized `runnerStorage` when it differs from the dialect default, and retain the store's `changeScope`.
64
+
65
+ `WorkflowsPage.useStartRun` returns `WorkflowStartResult`, which also includes confirmed `InspectCommandRejection` outcomes. Narrow with `isInspectCommandRejection` before reading successful-start fields; preserve uncertain delivery as an error. Forward the optional start request identity unchanged. The shipped local and Cloud adapters already use these contracts; the update command prints the required steps for custom hosts.
66
+
67
+ **`voltro update` carries you across this** — codemod `0.83.0/01_dashboard-inspection-contracts`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
68
+ - **Mail's 'postgres' stores are tables of the app's own schema** — `@voltro/plugin-mail`
69
+
70
+ `mailPlugin({ suppression: 'postgres' })` and `idempotency: 'postgres'` created their tables with raw SQL on a connection pool of their own, built from `DB_URL` / `DB_*` / `PG_*` without the URL's `?sslmode=require`. The tables sat outside the declared schema — no `voltro db plan`, no schema fingerprint, no backup or data transfer saw them — and against a database that only accepts TLS the plugin could not activate and the api refused to boot. The plugin now declares `_voltro_mail_suppression` and `_voltro_mail_idempotency` through `extendSchema`, so `voltro db apply` creates and evolves them like every other table, and both stores read and write through the app's own store — any SQL dialect, the app's TLS, credentials and pool, no environment read. `postgresSuppressionStore()` / `postgresIdempotencyStore()` take no options any more (`table`, `maxConnections` are gone), and `SuppressionStore` / `IdempotencyStore` gain an optional `bind(store)` for stores of your own. Idempotency keys are kept 30 days (`VOLTRO_MAIL_IDEMPOTENCY_TTL_HOURS`); suppressions are kept until lifted.
71
+
72
+ **`voltro update` carries you across this** — codemod `0.83.0/05_mail-postgres-stores-use-the-app-connection`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
73
+ - **The rate limiter's shared store is a table of the app's schema** — `@voltro/plugin-ratelimit`
74
+
75
+ `rateLimitPlugin({ store: 'postgres' })` created `_voltro_ratelimit` with raw `CREATE TABLE IF NOT EXISTS` on the app's connection and counted with a postgres advisory lock — outside the declared schema (no `voltro db plan`, no fingerprint, no backup or transfer saw it) and postgres only. The plugin now declares `_voltro_ratelimit` through `extendSchema`, so `voltro db apply` creates and evolves it, and every consume goes through the app's store: the key's row is made to exist (`insertIgnore`), then read `FOR UPDATE` and written in one transaction. The store therefore works on every SQL dialect the app runs on, and a cold-key burst still allows exactly the limit. `postgresStore()` loses its `table` option and is exported from the package root as well; a custom `RateLimitStore` receives the app's store through the optional `bind(store)` that replaces `bindSql(sql)`.
76
+
77
+ **`voltro update` carries you across this** — codemod `0.83.0/06_ratelimit-store-is-a-table-of-the-app-schema`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
78
+ - **The web process's ISR cache and replica tables are api framework tables** — `@voltro/cli`, `@voltro/data-transfer`
79
+
80
+ `voltro start` created `voltro_isr_cache` (`SSR_CACHE=postgres`) and `public._voltro_web_replicas` (`VOLTRO_WEB_REPLICA_GROUP`) with raw `CREATE TABLE IF NOT EXISTS` — outside every declared schema, and in `public` whatever `DB_SCHEMA` said, because the web process's raw client dropped the schema the api's pool pins. Both are framework tables of the api's schema now, `_voltro_isr_cache` and `_voltro_web_replicas`, declared for every app (the switches are runtime env, which may not move the declared set): `voltro db apply` creates them, backups carry them, and data transfers treat them as environment-local. The web process only reads and writes, refuses to boot when one is missing — naming the apply that fixes it — and its PostgreSQL clients (ISR cache, ISR invalidation, revalidation, replica discovery) now honour `DB_SCHEMA` like the api's pool. A cache key is unique through its SHA-256 (`keyHash`), so a URL of any length is cached.
81
+
82
+ **`voltro update` carries you across this** — codemod `0.83.0/09_web-process-tables-are-api-framework-tables`. If you pin versions by hand and never run it, print the notes without changing anything: `voltro update --codemods-only --from <your current version> --dry-run` (this one ships in 0.83.0).
83
+
84
+ ### Added
85
+
86
+ - **VOLTRO_INSPECT_TRUSTED_CLIENTS lends inspect access to named client networks** — `@voltro/cli`
87
+
88
+ A deployed dev environment can name the networks its team connects from in `VOLTRO_INSPECT_TRUSTED_CLIENTS` (addresses, CIDR ranges, or `private`). The web dev server, `voltro start` and the dashboard then lend the inspect credential they hold to a requester from one of those networks without a sign-in — the in-page devtools overlay works there — and refuse everyone else as before (or offer the sign-in form when `VOLTRO_DASHBOARD_TOKEN` is set). Behind an ingress the client address is read from `X-Forwarded-For` (or `VOLTRO_CLIENT_ADDRESS_HEADER`) through `VOLTRO_TRUSTED_PROXIES`, and only when the TCP peer is a proxy declared by address or range — so a visitor cannot claim a listed address in a header, and a request relayed without one identifies nobody. A list that covers every address, or one set beside `VOLTRO_TRUSTED_PROXIES=*` or a hop count, refuses the boot; an active list is printed in the boot log.
89
+ - **Read complete migration history entries on demand** — `@voltro/cli`, `@voltro/devtools-ui`, `@voltro/database`
90
+
91
+ Inspect can read one exact migration history entry with ordinary read authorization in development and production hosts, preserving stored operation JSON and distinguishing squash metadata from schema operations. The shared dashboard loads details when expanded, with explicit loading, retry, keyboard access and app/replica isolation in both local and read-only Cloud providers.
92
+
93
+ Snapshot ownership lookup avoids transferring unrelated operation histories while preserving full-history ambiguity checks and escaped JSON keys. Native JSON detail reads preserve large integer precision across drivers.
94
+ - **Subscribers get ctx.outbox when the app declares an outbox handler** — `@voltro/runtime`, `@voltro/cli`
95
+
96
+ A `*.subscribe.ts` handler now receives the same `ctx.outbox` a mutation does when the app declares at least one `*.outbox.ts` handler, under `voltro dev` and `voltro serve`. `enqueue(effect, payload)` writes a `_voltro_outbox` row with the declared handler's `maxAttempts`, and the delivery worker picks it up from the outbox table's change event. Before, a subscriber that wanted durable delivery had to build a facade by hand. The enqueue is durable from the enqueue on — the triggering change has already committed — so combine it with `once:` or an `idempotencyKey` on more than one replica.
97
+
98
+ ### Changed
99
+
100
+ - **A plugin's raw SqlClient is for declared tables, never for DDL** — `@voltro/protocol`
101
+
102
+ `PluginBindContext.sql` is documented for what it is: the app's own pool, for SQL the bound store cannot express against tables that are declared — through `extendSchema.tables` or the app's schema. A plugin never creates, alters or drops a table through it, and never opens a connection of its own instead; the bound `store` is the first choice, because it works on every dialect.
103
+
104
+ ### Fixed
105
+
106
+ - **The MySQL / MariaDB binlog reader connects with the app's TLS** — `@voltro/sql-mysql`, `@voltro/database`
107
+
108
+ Change capture on MySQL and MariaDB opens a replication connection of its own, and it was built from host, port, user and password only: `?ssl=true` / `?sslmode=require` / `PG_SSL` reached the app's pool but not the reader, so against a server that requires TLS the reader was refused while the app connected fine. The reader now carries the same `ssl` as the pool (`CdcConfig.connection.ssl`, set from the app's resolved connection).
109
+ - **Cluster snapshots reflect current SQL dialect capabilities** — `@voltro/cli`
110
+
111
+ Cluster snapshots now report MySQL's full clustering tier and binlog server ID, SQL Server's Change Tracking source, and advisory-lock scheduling on MySQL, MariaDB and SQL Server. These fields previously described older dialect limitations even though the configured runtime used the supported capabilities. Explicit single coordination and disabled CDC remain unchanged.
112
+
113
+ App manifests and Cluster snapshots now report the initialized native CDC mode, including capture disabled when all application tables opt out. This also corrects MySQL production manifests that previously advertised CDC as off.
114
+ - **Record failed cron seeds as failed scheduler runs** — `@voltro/cli`
115
+
116
+ Report failed cron seeds as failed scheduler runs. Previously the seed status recorded the error while schedule history incorrectly reported success. Later scheduled firings remain eligible to run and recover.
117
+ - **Dashboard shows the effective scheduler coordinator** — `@voltro/cli`
118
+
119
+ Schedules and Cluster inspection now receive the scheduler's effective coordination mode instead of independently guessing it from the dialect. Development advisory coordination is no longer mislabeled as single outside PostgreSQL, including explicitly selected SQLite advisory coordination. Production retains its resolved coordination and fallback behavior.
120
+ - **Bind workflow recovery to its original gateway** — `@voltro/devtools-ui`
121
+
122
+ Workflow recovery journals are now bound to the original app gateway in the local and Cloud dashboard routes. Changing a registered endpoint no longer moves saved start, retry, restart, cancel or resume identities to another server, while replica read selection keeps the same recovery scope.
123
+
124
+ Older records without gateway provenance require an explicit, reviewable association before recovery readers mount. Association preserves originals and existing endpoint records, refuses conflicting data, and remains retryable after storage failures. The shared `WorkflowGatewayBoundary` is available to custom dashboard hosts.
125
+ - **Preserve data-editor drafts and recover linked-row lookups** — `@voltro/devtools-ui`
126
+
127
+ - Keep unfinished field input when filtering record fields. Validation reveals and focuses the first invalid field. - Validate edited fields without rejecting unchanged date values returned by the server. Invalid user input still prevents saving. - Retry failed linked-row lookups without discarding the record draft, restoring keyboard focus to search. Hide previous results while a new search is pending.
128
+ - **Data explorer table inventory recovery** — `@voltro/devtools-ui`
129
+
130
+ - Show table-list loading and errors on mobile as well as desktop. Failed reads no longer imply an empty inventory or ask users to select an unavailable table. Retry the inventory directly without reloading the dashboard.
131
+ - **Keep database status labels readable in both themes** — `@voltro/devtools-ui`
132
+
133
+ Seed lifecycle and result badges, migration status badges, database connection indicators and error details now use appropriate foreground colors in both light and dark themes. Status text and existing actions remain unchanged.
134
+ - **Distinguish database loading and errors from empty results** — `@voltro/devtools-ui`
135
+
136
+ The shared database dashboard no longer reports missing seeds or migrations while its first status request is loading or has failed. Loading and refresh states have accessible status text; read failures are announced as alerts. Empty lists require a successful current snapshot, and retained stale snapshots cannot enable write actions.
137
+ - **A deploy undo keeps half-precision vectors and generated columns** — `@voltro/database`
138
+
139
+ The pre-deploy snapshot a failed `voltro db apply` / `voltro db deploy` plans back to also lost a vector column's half precision and a generated column's expression. An undo touching a table with a `halfvec` column planned it to a full-precision vector, and a generated column it re-created came back as a plain column. Both now survive the way back, like a numeric key.
140
+ - **A deploy undo keeps a numeric primary key numeric** — `@voltro/database`
141
+
142
+ When `voltro db apply` undid a failed deploy, it planned the way back from the database's own pre-deploy snapshot, and that snapshot lost the fact that an `id({ scheme: 'numeric' })` key is a sequence. The undo therefore planned every `BIGINT` key of a table it touched to `VARCHAR(64)` — on MySQL and MariaDB a failed deploy that had converted a character set reported "the undo did not converge" for each such table. The key now stays as it was.
143
+ - **Preserve bigint precision in direct queries and typed joins** — `@voltro/sql-sqlite`, `@voltro/runtime`
144
+
145
+ SQLite SELECT projections now use the table metadata carried by `queryFor(table)` and typed joins, even without global table registration. Large bigint values stay exact strings, joined output aliases retain numeric ordering, and unmatched left joins remain null. Name-only descriptors continue to resolve registered schemas.
146
+
147
+ Verification: real SQLite reads reproduce the former rounding of 9007199254740993 and cover the corrected direct and joined query paths. Decimal storage and aggregate precision are unchanged.
148
+ - **Keep embedded replica snapshots readable during primary outages** — `@voltro/sql-turso`
149
+
150
+ Read transactions on synchronized embedded libSQL replicas now use a scoped local reader with query-only enforcement and the configured encryption key. Snapshot reads no longer open a transaction against an unavailable primary. Ordinary writes retain primary forwarding, and initial synchronization still requires the primary.
151
+
152
+ The embedded syncing client now runs in a scoped child process. Cancellation joins the worker without replaying uncertain operations; subsequent independent operations can initialize a new worker. Native synchronization no longer blocks the application event loop, and shutdown remains bounded during primary outages.
153
+ - **Compare columns explicitly and keep memory joins reactive** — `@voltro/database`, `@voltro/runtime`, `@voltro/voltro`
154
+
155
+ Add explicit `columnRef()` operands for scalar comparisons. SQL and memory preserve NULL semantics under logical composition, while dotted strings remain literal values. The memory store now executes inner/left joins and aliased projections, including transaction-local rows. Reactive joins track both tables and right-hand predicate columns. Default join projections return FROM-side columns, avoiding ambiguous unqualified identifiers. SQLite and MySQL offset-only reads emit the required unlimited LIMIT.
156
+
157
+ Scalar comparison arguments are widened to also accept `ColumnReference`; existing values and return types remain valid. Runtime start options add an optional request ID; the other runtime report changes only reorder excluded internal members. The aggregate exports preserve these compatible signatures.
158
+ - **Full-text indexes no longer keep a plan from reaching zero operations** — `@voltro/database`
159
+
160
+ Since 0.82.0 `voltro dev`, `voltro db apply` and `voltro db deploy` create the objects behind `.fullTextIndex()` after the schema plan. Only postgres's introspection then left them out of the live schema. On MySQL and MariaDB the FULLTEXT index was read back as an undeclared index, so every following plan held a `drop-index` for it, every deploy dropped it and the full-text step re-created it, and the plan never reached 0 operations. On SQLite the FTS5 table and its shadow tables were read as undeclared tables, so every following plan held blocked `drop-table` operations and was refused. The introspection now leaves these objects out on every dialect, as it does on postgres. Removing a `.fullTextIndex()` declaration leaves its objects in place on every dialect.
161
+ - **Exclude copied agent guides from development restart watching** — `@voltro/cli`
162
+
163
+ The agent-guide copy fallback marks its generated directory before writing the topic manifest. Refreshing guides during development boot no longer triggers a restart loop through `_manifest.json`. Copy failures still surface, and obsolete copied modules are still removed on refresh.
164
+ - **Publish usable IPv6 Inspect replica addresses** — `@voltro/cli`, `@voltro/web`
165
+
166
+ API development, API production and web replica discovery now share HTTP authority formatting. Raw IPv6 literals receive the required brackets; already bracketed literals retain one pair. IPv4 and DNS hostnames are unchanged.
167
+
168
+ Verified with declared-address tests and a real IPv6 peer request, including authentication and one-hop routing.
169
+ - **Recover reads from a silent Inspect entry point** — `@voltro/cli`
170
+
171
+ The local dashboard now tries a recently observed, authorized peer when an Inspect GET receives no response headers within two seconds. Only attempts with an available fallback are bounded. Streaming bodies continue after headers, HTTP errors remain authoritative, caller cancellation stops routing, and writes are never retried automatically.
172
+
173
+ Regression tests use real HTTP servers for silent connections, delayed bodies, delayed writes and cancellation.
174
+ - **Embedded libSQL replicas start without an unsupported journal pragma** — `@voltro/sql-turso`
175
+
176
+ Replica startup no longer applies the standalone file client's WAL pragma to synchronized libSQL databases, where it fails with `Sqlite3UnsupportedStatement`. Standalone file clients retain WAL configuration. Initial synchronization and the configured pull-sync interval are unchanged.
177
+ - **Release late libSQL transaction handles after cancellation** — `@voltro/sql-turso`
178
+
179
+ Direct libSQL transaction acquisition and transaction-control waits now support Effect interruption. A transaction handle arriving after cancellation is closed without entering the cancelled body. Interrupted writes are not replayed, and local cancellation does not guarantee that remote processing has already ended.
180
+
181
+ Remote acquisition now waits for cancelled requests and their rollback cleanup to settle before opening another transaction. The caller keeps its interruption deadline while recovery retries no longer accumulate server-side transactions.
182
+ - **Preserve large integers in libSQL results** — `@voltro/sql-turso`
183
+
184
+ Decode libSQL integer results losslessly, including remote HTTP transactions. Safely representable integers remain JavaScript numbers; larger signed 64-bit values remain bigint. This prevents remote workflow journals with large identifiers from failing during result decoding.
185
+ - **Enable journal Timeline capture for libSQL application hosts** — `@voltro/cli`, `@voltro/sql-turso`
186
+
187
+ Remote libSQL and embedded replicas now select the SQLite journal contract for normal migration preparation and Timeline hosts. External writes are captured with persisted privacy masking and coherent source snapshots. Native Turso keeps its separate ring contract.
188
+
189
+ Embedded replicas serialize autocommit statements, write transactions and reserved connections on their single write connection. Independent local read snapshots remain concurrent. Interrupting a queued operation does not terminate the active transaction.
190
+ - **Report migration failures without promising a whole-plan rollback** — `@voltro/database`
191
+
192
+ Migration errors after a completed transactional batch no longer claim that the schema is unchanged. History-write and operation-ledger-cleanup failures identify their stage and direct inspection of durable progress, while accounting for an enclosing deployment transaction.
193
+
194
+ PostgreSQL retries repair an invalid index left by the recorded concurrent build, then re-plan under the migration lock before continuing the original run. Completed transactional operations and soft-drop snapshot ownership remain in the same history entry; valid indexes and unrelated transactional-work guards are preserved.
195
+ - **MySQL declares durable CDC cursor storage** — `@voltro/cli`
196
+
197
+ MySQL migration planning, development and production startup, and schema diagnostics now declare `_voltro_cdc_offsets`, matching the binlog reader's durable cursor storage. MySQL and MariaDB use the same table shape; SQL Server retains its Change Tracking shape. Disabling capture with `CDC=0` does not remove the declared table.
198
+
199
+ Existing MySQL deployments without this table must apply the generated schema migration before starting the new production version.
200
+ - **The devtools overlay asks each inspect source once in a StrictMode app** — `@voltro/devtools`
201
+
202
+ `mount()` renders an app under React's `<StrictMode>`, which in development runs every effect, cleans it up and runs it again. The overlay's polled sources then asked each inspect endpoint twice when the console opened, and the inspect streams opened twice with one cancelled — so a refusing api saw every request doubled. Concurrent reads of one URL now share a single request, and the streams connect one tick late so an immediate cleanup sends nothing. The overlay's hint for an api on another origin also says to whom the web server lends the inspect credential.
203
+ - **A page's meta tag replaces the shell's of the same name** — `@voltro/cli`
204
+
205
+ A page's `<title>` already replaced the generated shell's; a `<meta>` did not. With `pwa` set, the shell's `apple-mobile-web-app-status-bar-style` (`default`) and a page's own (`black-translucent`, say) were both served, the shell's first. Every server render — `voltro dev`, `voltro start`, prerendered and SPA shells — now keeps one element per `name` or `property`: the page's. The client router already updated one element per name.
206
+ - **Published type declarations no longer carry the framework's type tests** — `@voltro/runtime`, `@voltro/cli`
207
+
208
+ The type declarations of `@voltro/runtime` 0.82.0 and `@voltro/cli` 0.82.0 contained `declare module '@voltro/protocol'` blocks from the framework's own type tests. In `@voltro/runtime` the block registered a plugin error whose class was not shipped, so the registered-error union resolved to `any` and `defineExecutor` rejected every executor — even one that cannot fail — with `'${any}' is not in this procedure's wire union`. In `@voltro/cli` the blocks added test table names (`tasks`, `invoices`, …) to `VoltroTableNames` in every program that loads the CLI's types. Both are gone, and a package build now fails when an emitted declaration augments a module with a member no shipped source declares. On 0.82.0, deleting the trailing `declare module '@voltro/protocol'` block from `@voltro/runtime/dist/index.d.ts` (a package patch) restores the check.
209
+ - **Coordinate remote Turso workflow replicas through SQL row leases** — `@voltro/database`, `@voltro/sql-turso`, `@voltro/workflow`, `@voltro/cli`
210
+
211
+ Select shared SQL workflow runners for direct remote Turso primaries in both development and compiled production, using the dialect's resolved connection capability. SQLite-family SQL runners use row leases; local and embedded connections retain their single-process defaults. Remote-primary schedules default to shared advisory claim coordination. Cluster inspection shows the actual runner storage and lock mode, preventing duplicate workflow execution caused by independent memory runners against one remote journal.
212
+
213
+ Stop or drain existing remote Turso memory-runner workers before starting coordinated SQL-runner workers against their journal; mixed ownership modes must not overlap.
214
+ - **Restore drills refuse unreadable migration ledgers** — `@voltro/cli`, `@voltro/sql-mssql`
215
+
216
+ Restore drills now fail when a restored migration ledger exists but its schema baseline cannot be read, instead of treating query failures as an absent ledger. File-migration hashes do not count as schema baselines. PostgreSQL restore and SQL Server boot regressions cover empty, unreadable and file-only ledger histories.
217
+ - **Retain isolated runtime workers and native platform bindings** — `@voltro/cli`
218
+
219
+ Runtime pruning retains the internal libSQL worker entry and installed native binary optional dependencies of reachable packages, including platform bindings selected dynamically by libSQL. Parent framework code remains inlined; unrelated package files are still removed.
220
+
221
+ External package families are discovered through installed production dependency manifests, including nested layouts. Their resolution metadata and both import/require closures survive pruning without retaining the bundled parent implementation.
222
+ - **Prepare schema-change seeds before development auto-migration** — `@voltro/cli`
223
+
224
+ `voltro dev` now discovers event-driven seeds and installs their hooks before applying automatic schema migrations. Matching `onSchemaChange` seeds execute on first creation and later changes to watched tables, with their result visible in the database panel. The later boot lifecycle reuses the discovered seeds; boot seeds and startup tasks still wait for the schema, and serving processes keep their existing no-automatic-boot-seeding policy.
225
+ - **voltro serve boots after a deploy that ends with an after-schema migration** — `@voltro/database`, `@voltro/cli`
226
+
227
+ `voltro serve` compares the declared schema fingerprint with the newest row of `_voltro_migration_plans`. A file migration writes its body hash into the same column, and an `after-schema` file runs after the plan — so after a successful `voltro db deploy` or `db apply --plan` that ran one, the newest row was that file's, and every `voltro serve` refused with `SCHEMA FINGERPRINT MISMATCH`. `voltro dev`'s up-to-date shortcut, `voltro db drift` (and its `--accept`), and the `voltro data restore --drill` ledger check read the same row. All of them now read the newest row that describes the schema; a plan applied from a plan file still counts as one. On 0.82.0, running the plan and apply steps once more after such a deploy writes a schema row last, and `serve` then boots.
228
+ - **Exclude SQL Server system schemas from tenant seed targets** — `@voltro/cli`
229
+
230
+ The database dashboard no longer offers SQL Server's guest and fixed-role schemas as tenant seed targets. The same inventory rejects explicit actions against those targets. User schemas remain available, including names beginning with `db_` and schemas owned by a fixed role. Seed documentation now makes the existing per-process tenant-provisioning behavior explicit: first use after a restart can invoke idempotent tenant seeds again.
231
+ - **Honor explicit SQLite schedule coordination in production** — `@voltro/cli`
232
+
233
+ Honor explicit advisoryLock schedule coordination for SQLite and Turso in compiled production startup, matching development. Both boot paths share the supported claim-store check. Defaults remain single for SQLite-family stores and memory; this does not enable distributed SQLite workflow runners.
234
+ - **voltro start serves the web manifest and common assets with their real type** — `@voltro/cli`
235
+
236
+ `voltro start` answered every file whose extension its short type table did not know with `application/octet-stream` beside `x-content-type-options: nosniff` — including the `manifest.webmanifest` the `pwa` build writes itself, which `voltro dev` serves as `application/manifest+json`. The table now covers the manifest, source maps, WebAssembly, AVIF and GIF images, TTF/OTF fonts, MP4/WebM video, MP3/OGG/WAV audio, PDF, CSV, Markdown, iCalendar and ZIP.
237
+ - **Bound Timeline session operations and lease release** — `@voltro/cli`
238
+
239
+ SQLite-compatible Timeline capture sessions invalidate their recorder before attempting lease release. The release now has an explicitly interruptible one-second deadline, including during masked scope finalization. An unreachable database no longer holds that cleanup indefinitely; an undelivered lease expires normally. This does not enable libSQL capture in ordinary application hosts.
240
+
241
+ Source reads and lease operations now have a five-second interruption deadline, with a separate seven-second reader deadline including semaphore contention. Failed source work invalidates the recorder before recovery. Background renewal and polling begin at their first scheduled interval instead of duplicating activation work immediately.
242
+ - **PostgreSQL Timeline recording no longer starves the connection pool** — `@voltro/cli`
243
+
244
+ With `VOLTRO_TIMELINE` on (the development default) on PostgreSQL, every capture locked each captured table with its own `LOCK TABLE` statement — one round trip per table, every second, on one of the app's pooled connections, whether anything had been written or not. With several hundred tables behind a pooler that held one connection most of the time, and at a small `DB_MAX_CONNECTIONS` the rest of the app failed with `Failed to acquire connection for transaction`. A capture now takes its locks in one statement, so its cost no longer grows with the number of tables; an idle session asks one question per second and captures only when something was written or every ten seconds to renew its lease. Installing and retiring the capture schema check and lock the tables in one statement each too, instead of holding every table's exclusive lock across one round trip per table.
245
+ - **Timeline selection follows available recorded tables** — `@voltro/devtools-ui`
246
+
247
+ The Timeline no longer requests an invisible, previously selected table when the recording or retained table set changes. It selects the first available table and suspends replay when no tables remain. Temporary loading preserves the preferred selection; unavailable frozen positions still require an explicit return to the current recording.
248
+ - **Match the Timeline scrubber to the dashboard theme** — `@voltro/devtools-ui`
249
+
250
+ The Timeline scrubber uses the shared primary accent, visible keyboard focus and consistent disabled styling while retaining native keyboard navigation. Its sequence, event and recovery controls wrap on narrow screens instead of extending the document beyond the viewport.
251
+ - **Native Turso pools start reliably on a shared database file**
252
+
253
+ Coordinate native Turso connection initialization across pools of the same database file to prevent intermittent MVCC startup failures while preserving concurrent queries and transactions.
254
+ - **Finish native Turso statements before interruption cleanup** — `@voltro/sql-turso`
255
+
256
+ Wait for an in-flight native Turso statement to settle before interruption releases its connection, closes its statement or rolls back a transaction. This fixes workflow engine shutdown hanging after a completed parent/child workflow while the storage poller is interrupted. Autocommit writes that already completed are not undone by cancellation.
257
+ - **voltro update lists the reads and rpc-failure renders earlier notes missed** — `@voltro/cli`
258
+
259
+ Three `voltro update` notes listed too little or too much. `0.82.0/22` rewrote every place that SET `anonymousTenantId`, `anonymousTenantRequired` or `anonymousTenantDefault` and said nothing about a line that READ one — a test reading `auth.anonymousTenantId` kept compiling against its own interface and got `undefined`; the rewrite now names each such line, and `0.83.0/02` lists them for anyone who already crossed 0.82.0. `0.82.0/05` looked for `String(error)` only in files importing `@voltro/client`, so a hook or layout that calls `mutateAsync` / `useMutation` through the app's own wrappers was never listed; it now recognises those files, and `0.83.0/03` lists exactly the lines the narrower test missed. `0.81.0/02` no longer lists a `.select('column')` that follows `queryFor(` on the same line — a column projection, never a table.
260
+ - **Preserve workflow start identities across retries and replicas** — `@voltro/runtime`, `@voltro/cli`, `@voltro/devtools-ui`
261
+
262
+ Workflow starts can carry a caller-owned request ID and stable start timestamp. Durable receipt bindings make retries return the original queued or accepted start and reject conflicting reuse, including across replicas and after pending admission is consumed.
263
+
264
+ Switching the inspected app closes its start dialog. Delayed responses remain associated with the original app and cannot close another app's dialog or alter its unsent draft. Returning to the original app observes its saved request without resubmitting it.
265
+
266
+ Multiple unresolved starts can be selected explicitly by request ID and tenant. Continuing preserves the original identity, timestamp and tenant; changing the selection clears the payload draft. Keyboard and mobile layouts support the choices. An acknowledged request closes its recovery dialog rather than silently turning it into a new-start form.
267
+
268
+ The shared dashboard persists this identity before sending a start. Unknown delivery survives reload; explicit retries reuse the same identity. Confirmed initial rejections clear only fresh requests, while network failures, conflicts and server errors retain recovery metadata. Receipt observations recover accepted starts without needing the original response. Browser storage failures prevent unsaved submissions, and journals never store workflow payloads or credentials. The local and Cloud providers preserve the identity and expose typed confirmed rejection results.
269
+
270
+ ### Internal (no consumer-facing effect)
271
+
272
+ - **Keep dashboard acceptance checks executable after integration** — `@voltro/cli`, `@voltro/sql-turso`
273
+
274
+ Refresh framework-table nullability metadata and receipt expectations, load the shared network test harness for Turso, run embedded-replica checks against the standard libSQL test primary instead of skipping them, and preserve empty argument lists in database-tool wrappers on macOS Bash.
275
+
276
+ The SQL Server namespace test uses the standard test-stack credential default and runs without an extra opt-in variable. Changelog package lists use the supported inline format, so release classification includes every affected package.
277
+ - **Re-pin measured server artifacts after dashboard integration** — `@voltro/web`
278
+
279
+ Re-pin the server artifact budget after measuring current upstream growth: the normal API serve bundle is 9,968,903 bytes; matched source-entry builds decrease from 10,274,130 to 10,239,490 bytes with the dashboard integration. Keep the existing 15% artifact headroom and browser payload budgets unchanged.
280
+ - **Prepare exact SQLite decimal reads and comparisons** — `@voltro/database`
281
+
282
+ Extend internal exact-decimal query lowering with inner and left joins, cross-scale column and aggregate comparisons and bound source filters. Exact row projections retain numeric ordering and pagination without numeric coercion. DISTINCT and group-only projections preserve NULL groups, filters and result pagination. Shallow decoding stages avoid libSQL parser-stack limits. Bound arithmetic stages prevent excessive SQLite query-plan expansion. Ordinary application storage and its migration contract remain unchanged.
283
+
284
+ Extend the inactive internal compiler with exact window projections, preserving row identity, NULL partitions, peers and pagination across SQLite-family clients. Share source lowering and flatten materialized arithmetic stages. Use portable rank and shift expressions where native window functions are unavailable. Normal application storage is unchanged; native Turso window performance remains an adoption gate.
285
+
286
+ Reduce internal exact AVG planning depth with five-digit integer long-division blocks, retaining zero padding and explicit rounding. Validate precision and block-boundary rounding against actual SQLite-family clients. Native combined window planning remains a performance limitation before storage adoption.
287
+
288
+ Compute internal window outputs from one materialized source and combine them by its stable row identity. Avoid sequential arithmetic expansion and wide joins; retain duplicate rows, independent orderings and large projection lists.
289
+ - **Add scoped ownership for the internal libSQL worker** — `@voltro/sql-turso`
290
+
291
+ Add an internal Effect-scoped IPC bridge that registers process cleanup before initialization and joins the worker on request interruption. The embedded adapter uses the bridge through a scoped manager that replaces terminated workers only for new operations and keeps transaction handles tied to their original process.
292
+ - **Migration ledger checks share the race-safe source walker** — `@voltro/cli`
293
+
294
+ Use the shared race-safe source walker in the newest-migration-ledger reader guard.
295
+ - **Guard libSQL file timeline snapshot concurrency** — `@voltro/cli`
296
+
297
+ Real-driver tests verify coherent paginated source snapshots during a concurrent peer write and transaction cleanup after a failed source read. This does not enable remote or synchronized libSQL timeline capture.
298
+ - **Guard internal MySQL Timeline frames against physical table replacement** — `@voltro/cli`
299
+
300
+ Add explicitly provisioned, schema-scoped physical-generation reads and frame assertions for MySQL and MariaDB. Detect external TRUNCATE and partition replacement without granting global catalog privileges to serving accounts. Refuse changed helpers, incomplete generation results, nested or autocommit-disabled provisioning, and clean disposable discovery tables on failure. This is an internal prerequisite; ordinary hosts remain unchanged until epoch ownership and lifecycle integration are complete.
301
+ - **Persist MySQL Timeline generation ownership through migration recovery** — `@voltro/cli`
302
+
303
+ Persist helper intent before implicit-commit DDL and bind physical generation fingerprints to capture epochs. Reuse intact installations, invalidate history and observers after table replacement, retire only verified owned helpers, and recover safely after missing provisioning rights or a failed final metadata write. Ordinary hosts remain unchanged while guarded source and observer integration are completed.
304
+ - **Compose a guarded MySQL Timeline source snapshot** — `@voltro/cli`
305
+
306
+ Read journal events and table rows in one pinned, read-only snapshot after validating physical table generation and the observer lease. Recheck expiry after reading rows, reconcile acknowledged retention, and fail closed on unavailable evidence. Establish lease identity and initial journal position in the same pinned snapshot. This internal source does not activate MySQL or MariaDB Timeline in ordinary hosts; observer admission, idle capture gating and recorder integration remain pending.
307
+ - **Prove MySQL and MariaDB Timeline journal lifecycle** — `@voltro/cli`
308
+
309
+ Add the internal migration-lock-owned Timeline capture plan and journal lifecycle for MySQL and MariaDB. Real database tests cover masked row images, rollback, concurrent writers and installers, epoch retirement, interrupted installation, storage drift and the existing MariaDB transaction retry. The lifecycle is not activated in serving; observer leases, retention and source continuity remain required before replacing the change-stream fallback.
310
+ - **Register MySQL Timeline observers behind a bounded writer barrier** — `@voltro/cli`
311
+
312
+ Drain existing trigger writers before creating the initial observer snapshot and commit lease registration atomically. Share connection reservation, relation pins and session cleanup with the read-only source path. Bound admission row-lock waits and restore both pool connections after failure. This internal prerequisite does not yet disable idle capture or activate MySQL/MariaDB Timeline in ordinary hosts.
313
+ - **Prove MySQL and MariaDB Timeline observer retention** — `@voltro/cli`
314
+
315
+ Add internal migration-owned observer leases with exact visible journal IDs, revision-checked acknowledgement and transactional retention. Real MySQL and MariaDB tests verify late commits, expired and lagging observers, independent replicas, collector rollback and IDs beyond JavaScript number precision. Ordinary hosts remain unchanged until guarded source reads and idle capture are complete.
316
+ - **Preserve MySQL Timeline pruning evidence and frame locks** — `@voltro/cli`
317
+
318
+ Persist exact observer pruning receipts with collector deletion, preserve them across frame/acknowledgement races, and reject unexplained missing journal IDs. Add pre-snapshot relation metadata locks with bounded waits and restored pool settings. Real MySQL/MariaDB regressions cover expiry, rollback, large relation sets and concurrent TRUNCATE. Ordinary hosts remain unchanged; physical table replacement between frames still needs a continuity guard before activation.
319
+ - **Prove MySQL and MariaDB Timeline snapshot frames** — `@voltro/cli`
320
+
321
+ Add an internal read-only Timeline frame reader with stable journal/row snapshots, late-commit visibility, exact journal IDs and scoped connection-state restoration. Real MySQL and MariaDB regressions cover commit order, rollback, interruption, read-only and nested-transaction enforcement, guard failure and bounded frames. It is not activated in serving: schema ownership, retention, observer leases and source-continuity guards still have to be implemented before replacing the change-stream fallback.
322
+ - **Run workflow partition checks with the prepared test images** — `@voltro/sql-postgres`
323
+
324
+ Use the standard Toxiproxy image for the isolated workflow partition fixture. Refuse implicit image pulls during setup, bound connection/readiness probes, and fail explicitly when infrastructure is unavailable instead of returning from test bodies without exercising recovery. Both partition takeover and healing assertions run against real replicas.
325
+
326
+ ---
327
+
42
328
  ## [0.82.0] — 2026-10-01
43
329
 
44
330
  ### ⚠ BREAKING
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/ui",
3
- "version": "0.82.0",
3
+ "version": "0.83.0",
4
4
  "description": "Schema-driven React components over Voltro's headless client bindings: AutoForm, DataTable, the widget seam, and live workflow/presence/AI surfaces.",
5
5
  "keywords": [
6
6
  "voltro",
@@ -33,8 +33,8 @@
33
33
  "node": ">=24.0.0"
34
34
  },
35
35
  "dependencies": {
36
- "@voltro/client": "0.82.0",
37
- "@voltro/plugin-comments": "0.82.0"
36
+ "@voltro/client": "0.83.0",
37
+ "@voltro/plugin-comments": "0.83.0"
38
38
  },
39
39
  "peerDependencies": {
40
40
  "effect": "^3.22.2",