@voltro/plugin-comments 0.83.1 → 0.84.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.
- package/CHANGELOG.md +642 -0
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,648 @@ _Changes staged for the next release accumulate here (rolled up from
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## [0.84.0] — 2026-10-07
|
|
43
|
+
|
|
44
|
+
### ⚠ BREAKING
|
|
45
|
+
|
|
46
|
+
- **CRDT documents hard-compact into epochs without losing or doubling edits** — `@voltro/local-first`, `@voltro/runtime`, `@voltro/cli`
|
|
47
|
+
|
|
48
|
+
Past `crdt.rebaseMaxBytes` (default 4 MiB, `0` = never) the write path rewrites a document as a new epoch — same content, no history — after archiving the old lineage as a version. Subscriptions replace the cell instead of sending an increment across epochs, `createSyncClient` and the CRDT hooks replace their local state instead of merging two lineages (`onEpochChange`), and an update made on an archived lineage is carried over for text (`CrdtBackend.translate`) or refused as `crdt.staleLineage` for structured content, never merged into a doubled document. `useCrdtDoc` folds unsent edits restored after a reload into the document it renders. Migration: `rebaseText(state)` is replaced by `rebase(state, epoch)`, and a custom `CrdtBackend` implements `restoreTo`, `rebase`, `epochOf`, `authorsOf`, `translate`, `counterValue` and `counterAdd` (text handles add `undo`/`redo`, doc handles `epoch()`, `schemaVersion()` and `setSchemaVersion(version)`) — the `0.84.0/06_crdt-backend-epochs-and-history` codemod lists the affected files. Env override: `VOLTRO_CRDT_REBASE_MAX_BYTES`.
|
|
49
|
+
- **Last-write-wins orders by hybrid logical clock stamps** — `@voltro/local-first`
|
|
50
|
+
|
|
51
|
+
`createHybridClock({ node })` issues stamps that never run backwards and order a write made after seeing another one after it, even when the two devices' clocks disagree — ordered by wall clocks, the device whose clock runs fast wins every race. `FieldValue.updatedAt` is now `number | HlcStamp`, and `lastWriteWins` compares stamps causally (a plain millisecond epoch still works and compares as that millisecond). `receive(stamp)` folds a remote stamp in; `maxDriftMs` refuses one from a clock too far ahead instead of adopting it. Migration: writing a number still compiles; code that reads `updatedAt` as a number must narrow it — the `0.84.0/05_field-value-updated-at-accepts-hlc-stamps` codemod lists the affected files.
|
|
52
|
+
- **Retry Inspect creation with a stable request identity** — `@voltro/cli`, `@voltro/devtools-ui`
|
|
53
|
+
|
|
54
|
+
Inspect row creation requires a stable `requestId` alongside `table` and `row`. Creation and its receipt commit atomically; retrying unchanged input with the same identity returns the original record identity without inserting again. A changed payload with that identity returns HTTP 409. Responses contain the creation receipt and a current row observation, which can be null if the row was deleted.
|
|
55
|
+
|
|
56
|
+
The shared data explorer retains this identity while its creation dialog stays open, and both dashboard adapters forward it. Custom `DataViewerPage.useInsertRow` providers must forward the supplied identity unchanged. Custom Inspect callers must allocate one identity per intended creation and reuse it on uncertain retries. The shared local and Cloud data explorer now persists metadata-only creation identities across dialog closure and reload, observes without replay, and requires an acknowledged created or withdrawn outcome before another creation in that table. Custom insert providers must return the matching receipt instead of void; connect creationRecovery for persistent recovery. Both hosts wire read-only observations and terminal withdrawal to the same mutation gateway.
|
|
57
|
+
|
|
58
|
+
Development Inspect also exposes read-only creation observations and an authenticated withdrawal endpoint. Withdrawal atomically fences delayed creation when it wins, or reports an already committed record without deleting it. A missing receipt is not treated as proof that no request can still complete.
|
|
59
|
+
|
|
60
|
+
Shared dashboard hosts can validate matching creation observations and derive a mutation-gateway recovery scope through the exported creation contract helpers. The metadata journal persists no row payloads and refuses dispatch when storage or browser locking is unavailable; both hosts connect it to the shared visible recovery actions.
|
|
61
|
+
|
|
62
|
+
**`voltro update` carries you across this** — codemod `0.84.0/02_inspect-creation-intent`. 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.84.0).
|
|
63
|
+
- **outboxPersistence keeps one queue per signed-in subject** — `@voltro/local-first`
|
|
64
|
+
|
|
65
|
+
`outboxPersistence(adapter, now)` is now `outboxPersistence(adapter, { now?, partition? })`. With `partition` (for example a mirror source's `partitionKey`), each queued write is stored under the subject that made it: `load` returns only the current subject's writes and `save` replaces only those, so a write queued before a sign-out is never replayed under the next person's identity and waits for its own subject to sign in again. Saves are serialised. Migration: the `0.84.0/04_outbox-persistence-takes-options` codemod rewrites a positional clock into `{ now }`.
|
|
66
|
+
- **Reject stale release confirmations across replicas** — `@voltro/plugin-releases`, `@voltro/devtools-ui`, `@voltro/cli`
|
|
67
|
+
|
|
68
|
+
Release confirmations carry the exact target ID and observed revision. A stale confirmation is rejected with HTTP 409 even when the dashboard has not received the concurrent change yet. Every management write advances the target revision inside the same transaction as release state and its audit event; rejected transactions leave all three unchanged. Management mutations with an ambiguous app name must select a target instead of silently modifying the first platform.
|
|
69
|
+
|
|
70
|
+
The declarative schema adds a revision column with default zero to existing release targets. Automation can supply `expectedTarget: { id, revision }` from the Inspect overview; single-target calls may omit the expectation.
|
|
71
|
+
|
|
72
|
+
`voltro release` accepts `--target-id` together with `--expected-revision` on management actions. It preserves these values through dry runs and committed requests, refuses partial/invalid expectations before artefact upload, and never refreshes a stale expectation automatically. CLI rollout percentages now match the server's whole-number requirement.
|
|
73
|
+
|
|
74
|
+
Release events identify their platform target and channel in the dashboard. Custom event providers must preserve the nullable `channelId` and `channelName` fields. Missing target or channel metadata remains identifiable by its stored ID.
|
|
75
|
+
|
|
76
|
+
**`voltro update` carries you across this** — codemod `0.84.0/03_release-target-confirmations`. 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.84.0).
|
|
77
|
+
- **SQLite decimal columns use exact fixed-point storage** — `@voltro/database`, `@voltro/cli`
|
|
78
|
+
|
|
79
|
+
`decimal()` and `numeric()` now use exact encoded TEXT storage on SQLite, native Turso and libSQL. Existing NUMERIC columns are refused before application readiness, including when automatic migration is disabled. Migration: stop all readers and writers, back up and review existing values, then publish an explicit offline conversion through the server-only database conversion API and a nontransactional `before-schema` file migration. Review custom SQL and external readers for the physical format change; lost precision in existing NUMERIC data cannot be reconstructed automatically. Native decimal storage on PostgreSQL, MySQL, MariaDB and MSSQL is unchanged.
|
|
80
|
+
|
|
81
|
+
**`voltro update` carries you across this** — codemod `0.84.0/01_sqlite-decimals-use-exact-storage`. 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.84.0).
|
|
82
|
+
- **Direct storage metadata counter rows use decimal strings** — `@voltro/plugin-storage`, `@voltro/cli`
|
|
83
|
+
|
|
84
|
+
The exported `storageObjectLifecycleTables` descriptor now types its shared-object `reservations` counter as a decimal string because the column uses `bigint()`. Review custom framework-metadata reads and writes for exact integer handling; the manual upgrade note identifies direct descriptor and raw-table references. The supported storage service still exposes numeric sizes and usage within `Number.MAX_SAFE_INTEGER`. Reconcile existing framework tables through the normal schema plan/apply workflow; no database changes or source rewrites are performed by the note.
|
|
85
|
+
|
|
86
|
+
**`voltro update` carries you across this** — codemod `0.84.0/03_storage-metadata-bigint`. 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.84.0).
|
|
87
|
+
|
|
88
|
+
### Added
|
|
89
|
+
|
|
90
|
+
- **The query mirror plugs into the api mount and derives what to mirror** — `@voltro/client`, `@voltro/web`, `@voltro/react-native`, `@voltro/cli`, `@voltro/local-first`
|
|
91
|
+
|
|
92
|
+
The local-first query mirror could be built but not handed to the subscription cache, so offline reads and delta-resume after a reload never ran in an app. Declare it on the api in the web app's `app.config.ts` as `apis.<name>.mirror: createMirrorSource({ … })` (on React Native, `mirror` on the `MobileApiBinding`). The runtime resolves the source once per connection generation and hands it the api's descriptors: without `tags`, every query whose `source` tables are all `localFirst()` tables (per the generated `localFirstTables` passed as `metadata`) is mirrored, and a query that also reads a table that did not opt in is not. `remember({ subjectId, tenantId })` after a sign-in stores who is signed in on the device, so a cold start without network still renders that subject's rows; `forget()` on sign-out purges them. `warm: [[tag, input]]` keeps queries subscribed for the whole generation, so they are readable offline before any screen opened them; `warm: 'all'` does that for every query of the sync set whose input accepts `{}`. A source that throws mirrors nothing, the connection still comes up, and the failure is recorded as a `runtime.mirror` client diagnostic. The client-side golden churn is additive: an optional parameter and new optional fields.
|
|
93
|
+
- **queryOnce is importable without the React hooks** — `@voltro/client`, `@voltro/workflow`, `@voltro/database`, `@voltro/cli`
|
|
94
|
+
|
|
95
|
+
`@voltro/client/query` exports `queryOnce` (a query's first value over an api handle) without pulling the package root's React hooks, so a Node or tooling consumer can call it. `@voltro/workflow` now exports `reserveWorkflowRestartInTransaction` beside its sibling `withdrawWorkflowRestartInTransaction`. Internally, tests that reached into sibling packages' source now import their published entry points, which makes the cli and database typechecks clean.
|
|
96
|
+
- **Compose baselines support optional production environment variables** — `@voltro/cli`
|
|
97
|
+
|
|
98
|
+
Declare per-app `optionalProductionEnv` names in `project.json` and run `voltro baseline sync` to pass project-prefixed host variables into production API and web services without requiring them on every deployment. Unset or empty values become empty strings, so a field-encryption previous key can be supplied only during rotation. `productionSecrets` stays required; optional declarations cannot override required or baseline-owned bindings.
|
|
99
|
+
- **A conformance suite makes any CRDT backend a drop-in** — `@voltro/testing`
|
|
100
|
+
|
|
101
|
+
`crdtBackendConformance(name, { backend })` from `@voltro/testing/crdt` registers the executable contract every `CrdtBackend` must meet — merge commutativity, idempotence and identity, collaborative undo, the remote/local fold signal, incremental updates, queued local updates coalescing without loss, compaction keeping mergeability, `restoreTo`, `rebase` with epochs and fresh authors, `translate` across lineages, the content schema version surviving a rebase and commuting counters. The Yjs and Loro backends pass it; an Automerge or in-house backend that passes it plugs into the server merge, the sync client, the hooks, history and counters unchanged.
|
|
102
|
+
- **CRDT documents migrate their content when the editor schema changes** — `@voltro/local-first`, `@voltro/runtime`, `@voltro/cli`
|
|
103
|
+
|
|
104
|
+
`crdt.migrations` in the api's `app.config.ts` declares, per table and CRDT column, versioned `{ version, migrate(doc) }` steps. The write path runs a document's due steps in order inside the same compare-and-swap as the merge, so each document is migrated exactly once however many writes or replicas race, and the migration syncs to clients as an ordinary edit that merges with edits made against the old content. `migrateCrdtColumn(store, { table, column, batchSize? })` from `@voltro/runtime` migrates every document still behind and returns `{ scanned, migrated }`. Each document records its version (`crdtSchemaVersionOf`), which survives hard compaction. `renameEditorNodes(doc, { from, to, field? })` from `@voltro/local-first` (server-safe, no Tiptap) renames an editor node type on Yjs and Loro, keeping attributes and children. On Loro the node keeps its identity; on Yjs, where a node is replaced by a copy, the rename records what replaced what and the write path carries an edit a client made offline against the original — text, deletions, formatting, attributes, new child nodes — into the copy, once (`CrdtBackend.carryReplaced`, optional for custom backends); `applyCrdtMigrations` and `latestCrdtSchemaVersion` are exported for custom tooling.
|
|
105
|
+
- **A CRDT panel shows documents approaching their limits in both dashboards** — `@voltro/cli`, `@voltro/devtools-ui`, `@voltro/runtime`
|
|
106
|
+
|
|
107
|
+
`GET /_voltro/inspect/crdt` (both boot paths, inspect-token protected) reports, per `crdtText()` / `crdtDoc()` / `crdtCounter()` / `crdtSealed()` column, the largest documents with their size, how close each is to the next server limit, their epoch, how many writer sessions their history carries and how many archived versions they keep, plus the limits in force — sizes only, never document content. `@voltro/devtools-ui` renders it as `CrdtPage` (a new `crdt` inspect feature), shown by the local devtools dashboard and the Cloud dashboard. `describeCrdtState` (`@voltro/runtime`) is the size-only reader behind it.
|
|
108
|
+
- **Loro ships as a second CRDT backend** — `@voltro/local-first`, `@voltro/runtime`, `@voltro/cli`, `@voltro/testing`
|
|
109
|
+
|
|
110
|
+
`loroBackend` from `@voltro/local-first/loro` (with `loro-crdt` as an optional peer dependency) is a complete `CrdtBackend` and passes the same conformance suite as Yjs. Select it on both sides: `crdt: { backend: loroBackend }` in the api's `app.config.ts` for the server merge, history, epochs and inspection, and `setDefaultCrdtBackend(loroBackend)` in the client entry. `useCrdtText`, `useCrdtDoc`, `useCrdtCounter`, sealed columns, version history, epochs and content migrations work on it unchanged. The two backends' bytes do not mix: an update from the other backend is refused as `crdt.updateNotDecodable`. A Loro change depends on everything its writer had seen, so client edits travel up as whole document states and an update missing its dependencies is refused instead of being merged without them. The rich-text editor runs on Loro too: `useCrdtEditor` takes a `binding` (`yjsEditorBinding` by default, `loroEditorBinding` from `@voltro/local-first/loro-editor` over `loro-prosemirror`), with carets over the same awareness transport and collaborative undo on both. The Loro binding gives an empty document the schema's skeleton as a change every client writes byte-identically, so two people typing into a new document offline both keep their text. A binding refuses a document of the other backend with an error naming the right one.
|
|
111
|
+
- **crdtSealed() columns keep collaborative content end-to-end encrypted** — `@voltro/database`, `@voltro/runtime`, `@voltro/local-first`
|
|
112
|
+
|
|
113
|
+
A `crdtSealed()` column stores an append-only log of CRDT updates the client encrypted with AES-GCM under a key the server never sees (`generateSealKey` / `importSealKey` / `exportSealKey`). `useCrdtText`, `useCrdtDoc` and `useCrdtCounter` take `seal: { key }`: writes leave the client sealed, delivered logs are opened and merged locally, a frame that does not authenticate reports through `onSealError`, and edits not yet sent are kept sealed in the device's storage too. The clients compact the log, since only they can read it: softly once it outgrows `compactAboveBytes` (a sealed snapshot replacing the frames it covers, keeping every frame appended meanwhile), and hard once the document outgrows `rebaseAboveBytes` (default 4 MiB) — rebased into a new epoch and replacing the whole log, which the server archives as a `rebase` version. Each frame names its lineage epoch in cleartext, so the server appends only frames of the current epoch and refuses older ones as `crdt.staleLineage`; a client that typed offline on the archived lineage carries its edit over itself. A snapshot whose covered bytes changed meanwhile is refused as `crdt.sealedSnapshotStale`, so two clients compacting at once never cut each other's frames. The server checks framing and size limits only, appends with the same compare-and-swap as open folds, and refuses a malformed frame as `crdt.sealedFrameInvalid`; `restoreCrdtVersion` refuses a sealed column as `crdt.sealedRestoreIsClientSide`. `openSealedLog`, `sealUpdate`, `sealSnapshot`, `sealHardCompaction` and the log codec (`applySealedFrame`, `decodeSealedLog`, `sealedLogEpoch`) are exported for custom bindings.
|
|
114
|
+
- **Sealed CRDT versions restore on the client, and the CRDT hooks gain restore()** — `@voltro/runtime`, `@voltro/local-first`
|
|
115
|
+
|
|
116
|
+
`prepareSealedCrdtRestore(store, { versionId })` is the server's half of restoring a `crdtSealed()` cell: it archives the current log as a `restore` version, so the restore stays undoable, and returns the version's ciphertext. The client opens it with `openSealedLog` and passes the plaintext to the new `restore(target)` of `useCrdtText` or `useCrdtDoc`, which writes the restore as an ordinary edit — merged with concurrent edits and sealed like typing. An open column's history bytes never leave the server: `prepareSealedCrdtRestore` refuses one with `crdt.openRestoreIsServerSide`, and `restoreCrdtVersion` restores it on the server as before.
|
|
117
|
+
- **Collaborative undo for useCrdtText and a converging crdtCounter() column** — `@voltro/local-first`, `@voltro/database`
|
|
118
|
+
|
|
119
|
+
`useCrdtText` returns `undo()` / `redo()` / `canUndo` / `canRedo`: they revert this user's own recent edits (typing within `undoCaptureMs` is one step) and never a peer's, and the reverting change syncs like typing. `crdtCounter()` is a column that any number of clients increment and decrement concurrently, offline too, without losing a step — each writer keeps its own tally and the value is the sum — bound with `useCrdtCounter({ cell, remote, push })` (`value`, `add(n)`) and read with `crdtCounterValue(state)`.
|
|
120
|
+
- **CRDT cells keep a version history that can be restored** — `@voltro/runtime`, `@voltro/cli`, `@voltro/local-first`
|
|
121
|
+
|
|
122
|
+
The new framework table `_voltro_crdt_versions` keeps a `crdtText()` / `crdtDoc()` / `crdtCounter()` cell's history: named snapshots (`snapshotCrdt`), the state before every restore, and the lineage every hard compaction archived. `listCrdtVersions` lists them without their bytes, and `restoreCrdtVersion` writes a version's content back as an ordinary CRDT edit (`CrdtBackend.restoreTo`, for text, rich text, maps and arrays) that merges with concurrent edits and is itself undoable. Every function reads the cell's row through the store it is given first, so tenant scope and row filters decide whose history is visible. `crdtCellStats` reports a cell's size, epoch, author count, history length and limits.
|
|
123
|
+
- **The server bounds and validates what a client writes into a CRDT column** — `@voltro/runtime`, `@voltro/cli`, `@voltro/local-first`
|
|
124
|
+
|
|
125
|
+
A CRDT update is the client's own bytes. `crdt.maxUpdateBytes` (default 1 MiB) bounds one incoming update, `crdt.maxDocumentBytes` (default 16 MiB) the merged document after compaction, and `crdt.validate` runs the app's own check of every merged document (return a message key to refuse). Each refusal is a typed `ValidationError` with the column as `field` (`crdt.updateTooLarge`, `crdt.documentTooLarge`, `crdt.updateNotDecodable`, or the app's key); an oversized update inside a transaction is refused before commit. Bytes that are not a CRDT update are now this typed refusal instead of an untyped error. On the client, `createSyncClient` treats a `ValidationError` / `ValidationErrors` / `BusinessRuleViolation` as final (`isRefusal`): the write and the same cell's queued writes are dropped, the cell falls back to the server's state, the unsent copy is discarded, and `onRefused` / `lastRefusal()` / the hooks' `refused` report it — instead of retrying forever. Env overrides: `VOLTRO_CRDT_MAX_UPDATE_BYTES`, `VOLTRO_CRDT_MAX_DOCUMENT_BYTES`.
|
|
126
|
+
- **useLocalQuery filters and sorts the device's replica of a table, offline** — `@voltro/client`, `@voltro/testing`
|
|
127
|
+
|
|
128
|
+
`useLocalQuery(api, table, { where, orderBy, limit })` queries every row of `table` the api's cache holds — from each single-table query, from the durable mirror after an offline reload, and every queued write's preview — instantly and offline, for any filter, without a declared query. It only sees rows the server already sent this subject, so tenant scope and row filters still apply. `SubscriptionCache.rowsOf(table)` / `subscribeAny` are the reads behind it, and `runLocalQuery` is the pure query. The mirror's `warm: 'all'` keeps every local-first list warm, so the replica is the whole readable table.
|
|
129
|
+
- **Use guarded source capture for MySQL and MariaDB Timeline** — `@voltro/cli`
|
|
130
|
+
|
|
131
|
+
MySQL and MariaDB Timeline recording now uses a guarded source journal across connections and replicas instead of local change notifications. Migration setup prepares its contract, schema changes retire old history, and dev/serve hosts share the scoped recorder. Complete frames are acknowledged before publication; missing evidence, expiry or interruption starts a fresh recorder identity. Initial setup requires a suitably privileged migration identity for the fixed-schema generation helper; ordinary serving can use schema-scoped rights without global PROCESS. If optional capture preparation fails, startup warns and continues with history unavailable rather than presenting incomplete replay.
|
|
132
|
+
|
|
133
|
+
Preparation follows the configured workflow runner storage, so the first app start does not invalidate capture by creating missing runtime tables. Create-only migration and schema apply/deploy use the shared SQL-client backend selection.
|
|
134
|
+
- **useOutbox({ api }) is an offline write lane with previews that survive a reload** — `@voltro/client`, `@voltro/testing`
|
|
135
|
+
|
|
136
|
+
`useOutbox` takes `api: '<name>'`. Bound to an api, `send` defaults to that api's own mutation for the entry's tag with the entry id as the idempotency key, so a resend after a lost answer runs the mutation once; every queued write previews through the mutation's declared `targets` on every query of its table — including queries opened later and rows rendered from the mirror after a reload — until it is sent (the server's echo then replaces the preview) or conflicts (reverted); connectivity follows the api's transport; and a sign-in or tenant switch drops the previous subject's queue from memory and loads the next one's. A transiently failed write is now retried after `retryDelay(attempts)` (default `defaultOutboxRetryDelay`) rather than only on the next online edge, which never comes when the server is down and the network is up. `stamp: clock.now` records a hybrid logical clock stamp on each entry. `useApiOnline(name?)` answers whether a write can reach the server: the browser's signal and the api's transport. The HTTP drain (`drainOutboxOverHttp`, the service worker's) now sends the entry id as the idempotency key too. A `navigator` without `onLine` (React Native, Node) no longer reads as offline. The client golden churn is additive: an optional parameter and optional fields.
|
|
137
|
+
- **Expose reviewed offline SQLite decimal conversion** — `@voltro/database`
|
|
138
|
+
|
|
139
|
+
The server-only `@voltro/database/sql` entry point exposes source capture, reviewed staging, publication, rollback and cleanup operations for exact SQLite-family decimal storage, together with their input types and canonical decision identity helper. Repeated migration execution verifies retained artifacts instead of replacing later live writes.
|
|
140
|
+
|
|
141
|
+
Conversion requires stopped application readers and writers and a nontransactional before-schema file migration. It does not automatically convert existing NUMERIC columns or recover precision already lost in a NUMERIC source. The bilingual migration guide documents that boundary and the repeatable review-input contract.
|
|
142
|
+
|
|
143
|
+
### Changed
|
|
144
|
+
|
|
145
|
+
- **CRDT sync retries on its own clock and follows the api's transport** — `@voltro/local-first`
|
|
146
|
+
|
|
147
|
+
`createSyncClient` now retries a failed write after `retryDelay(attempts)`, by default `defaultRetryDelay` (exponential from 1 s, capped at 30 s, jittered), instead of five back-to-back attempts followed by a wait for the next `setOnline(true)` or edit; edits queued while the server was away and the network stayed up used to wait for the user's next keystroke. `maxAttempts` now defaults to unbounded. `useCrdtText` and `useCrdtDoc` follow connectivity by themselves — the browser's `online`/`offline` signal AND the api's own transport, so a server that is down while the network is up holds the queue too (`api: 'app'` names the api; omitted, any mounted api). A changed `online` option is applied to the live client instead of rebuilding it, so an unsent edit is no longer dropped when connectivity flips. `useCrdtDoc` now also shows unsent edits handed over after a reload in the document it renders, instead of only after the server echoed them back. Remove hand-written window listeners that only called `setOnline`, and any retry spacing inside `push`.
|
|
148
|
+
- **CRDT edits upload as increments, so large documents stay editable** — `@voltro/local-first`, `@voltro/runtime`, `@voltro/testing`
|
|
149
|
+
|
|
150
|
+
`useCrdtText`, `useCrdtDoc` and `useCrdtCounter` sent the whole local document on every push, so the upload grew with the document and one larger than `crdt.maxUpdateBytes` (default 1 MiB) could no longer be edited at all. The sync queue still holds whole local states, so offline edits coalesce as before, but a push now sends only their increment over the last state the server delivered — on Yjs and on Loro. An increment over a state the cell no longer holds, for example after a database was restored from an older backup, is refused as `crdt.updateNotDecodable` instead of being stored as changes no reader can see, and the client then sends its whole state. `SyncClient.getRemoteState(cell)` returns the last delivered state; a custom `CrdtBackend` whose `merge` keeps changes with missing dependencies (as Yjs does) implements the optional `missingDependencies(state)`, which the conformance suite checks.
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
|
|
154
|
+
- **Accept final agentic flow results on strict structured-output providers** — `@voltro/plugin-ai-flows`
|
|
155
|
+
|
|
156
|
+
Agentic flow planners now use the same closed structured-output envelope as structured tools for their final result. The engine returns and stores the original deliverable object, and refuses malformed or non-object results.
|
|
157
|
+
- **Commit release state and audit events atomically** — `@voltro/plugin-releases`
|
|
158
|
+
|
|
159
|
+
Release management mutations now share one store transaction across their state, channel pointers, retention changes and audit event in both RPC and Inspect. A failed event write no longer leaves a partially applied rollout or rollback. Inspect reports internal persistence failures as HTTP 500 rather than invalid input.
|
|
160
|
+
|
|
161
|
+
Plugin mutation executors receive the optional request transaction as `PluginRouteContext.mutationStore`. Releases reuses it so later caller failures also roll back release writes; Inspect and direct calls open their own transaction.
|
|
162
|
+
- **Roll back failed SQLite-family table rewrites atomically** — `@voltro/database`, `@voltro/sql-turso`
|
|
163
|
+
|
|
164
|
+
SQLite-family table rewrites now keep copying, replacement and index recreation inside one atomic operation. Failed statements and invalid foreign keys roll back the replacement without losing the original table or cascading child rows. Each rewrite creates a fresh working table and records its atomic execution mode before DDL, preserving unrelated staging-shaped tables on both first execution and retry. Native Turso additionally checks relationships before committing; libSQL uses its atomic migration batch through both direct and supervised worker transports. Rewrites reject enclosing transactions before changing data, because foreign-key settings must be changed before their own transaction starts. Whole migration plans still use the existing resume ledger; this does not enable encoded decimal storage or perform automatic decimal conversion.
|
|
165
|
+
|
|
166
|
+
Atomic rewrites prepare statements afresh, so a retry after resolving a schema conflict does not reuse a cached preparation failure from the rolled-back attempt.
|
|
167
|
+
- **Share binlog CDC control queries and report both owned connections** — `@voltro/sql-mysql`, `@voltro/cli`
|
|
168
|
+
|
|
169
|
+
MySQL and MariaDB CDC share one control connection for metadata, persisted-offset validation and watchdog probes instead of retaining an additional SQL pool. Together with the replication stream, CDC owns two connections outside the primary pool; the boot report now counts both. Recovery awaits the old reader and control connection before replacement, and shutdown cancels retry backoff and releases owned connections. Custom binlog-position resolvers remain supported.
|
|
170
|
+
- **Keep binlog reconnects within their connection budget** — `@voltro/sql-mysql`
|
|
171
|
+
|
|
172
|
+
MySQL and MariaDB CDC reconnects terminate the previous replication thread on the server before attaching its replacement, including after the control connection is lost. Shutdown and reconnect cleanup are serialized, preventing overlapping readers from exceeding the two-connection CDC budget.
|
|
173
|
+
- **SQL readiness answers when connection acquisition stalls** — `@voltro/cli`
|
|
174
|
+
|
|
175
|
+
Bound the SQL readiness ping to ten seconds even when the database driver leaves pool acquisition unbounded. Concurrent and repeated probes share one outstanding ping, return HTTP 503 on timeout, and recover after the pool serves queries again.
|
|
176
|
+
- **Browser loader integration retains callable client declarations** — `@voltro/client`
|
|
177
|
+
|
|
178
|
+
The published client query entry retains its TypeScript declaration for browser loader integration. Application loaders continue to read through `ctx.query`.
|
|
179
|
+
- **Retain browser-loader query declarations** — `@voltro/client`, `@voltro/web`
|
|
180
|
+
|
|
181
|
+
The `@voltro/client/query` entry and the existing Client and Web root exports now retain the browser loader helper in their shipped declarations and API reports. Its release annotation previously removed the exported helper during declaration rollup.
|
|
182
|
+
- **Changelog package filters include every affected package**
|
|
183
|
+
|
|
184
|
+
Release notes retain all affected package labels, including entries with multiple packages. Package filters on the public changelog include these changes consistently.
|
|
185
|
+
- **New string columns respect the store charset before table conversion** — `@voltro/database`
|
|
186
|
+
|
|
187
|
+
MySQL and MariaDB migration plans stamp the declared character set on newly added string columns and backfill enforcement, including columns added before the same table's conversion. A mixed add-and-convert plan converges in one apply.
|
|
188
|
+
- **Foreign-key operations wait for table creation and charset conversion** — `@voltro/database`
|
|
189
|
+
|
|
190
|
+
New foreign-key tables and their descendants wait for their parent's charset conversion even when the same plan changes its columns. Adding a foreign key waits for both endpoints to exist in the target charset, including constraints deferred from cyclic table creation.
|
|
191
|
+
- **Compose baselines support workspaces without a web app** — `@voltro/cli`
|
|
192
|
+
|
|
193
|
+
Generated development and production Compose files omit the web reverse proxy when no web app is declared. API-only workspaces now pass Compose validation instead of failing on an empty reverse-proxy dependency list; each API keeps its own database and sibling API addresses.
|
|
194
|
+
- **Compose dependency volumes remain distinct for every package path** — `@voltro/cli`
|
|
195
|
+
|
|
196
|
+
The `compose` baseline validates discovered workspace package paths before replacing generated files and assigns bounded, deterministic dependency-volume names with a path hash. Distinct valid paths containing dots, underscores or dashes no longer collide. Run `voltro baseline sync` after upgrading; the next startup uses fresh dependency volumes and leaves former dependency volumes unused. Preserve database volumes when cleaning up; `docker compose down -v` would also remove database data.
|
|
197
|
+
- **Compose baselines refuse malformed apps and generated-variable collisions** — `@voltro/cli`
|
|
198
|
+
|
|
199
|
+
`voltro baseline sync` validates app manifest structures before writing generated files and refuses baseline-owned environment names in both `productionSecrets` and `optionalProductionEnv`, including database settings, runtime settings, web origins and sibling API addresses. Invalid declarations now name the manifest field to correct instead of silently omitting an app or producing duplicate YAML keys.
|
|
200
|
+
- **Compose prepares workspace dependencies before development startup** — `@voltro/cli`
|
|
201
|
+
|
|
202
|
+
The `compose` development baseline now runs a frozen install and builds the transitive workspace dependencies of every generated API/web app before migration or app startup. Shared dependencies build once in dependency order; packages without a build script are skipped, while generated apps and the workspace root are excluded. Preparation failures block startup. After upgrading, run `voltro baseline sync`; remove dependency-build replacements from custom overlays while retaining unrelated application settings. Preparation runs at startup and does not watch library sources. The `compose-mariadb` template gains the same preparation barrier for its default app paths; review and back up existing service customizations before reapplying it with `voltro baseline set compose-mariadb`, because its sync command only refreshes Dockerfiles. Both Compose production templates skip source-only dependencies and exclude the root aggregate build.
|
|
203
|
+
- **Resolve content loaders in compiled server bundles** — `@voltro/cli`, `@voltro/content`
|
|
204
|
+
|
|
205
|
+
Compiled web server bundles now include the lazy content rendering pipeline rather than retaining a relative import to an absent server loader. Published content packages use a Node-resolvable JavaScript filename. Browser builds continue to exclude the filesystem, markdown renderer and highlighting pipeline.
|
|
206
|
+
- **CRDT folds stay lossless across replicas** — `@voltro/runtime`, `@voltro/database`
|
|
207
|
+
|
|
208
|
+
A `crdtText()` / `crdtDoc()` write is read, merged and written back. Writers in one process were serialised, but two replicas folding the same row could both merge into the same base, and the later write could drop the earlier edit when the row stayed contended. The write is now a compare-and-swap: it only lands if the stored state is still the one it merged into, otherwise it re-reads and re-merges, and a fold that keeps losing is refused (the client's sync queue retries it) rather than written over another replica's edit. The in-memory store now compares bytes by content in predicates, as SQL does.
|
|
209
|
+
- **Keep CRDT inspection bounded and recover from invalid reads** — `@voltro/cli`, `@voltro/devtools-ui`
|
|
210
|
+
|
|
211
|
+
Validate complete CRDT inspection responses before rendering so malformed nested facts show a recoverable error instead of crashing the dashboard. Count document versions in the store instead of loading every history ID for each displayed document.
|
|
212
|
+
- **Keep CTE references local in tenant namespace queries** — `@voltro/database`
|
|
213
|
+
|
|
214
|
+
SELECT compilation now carries lexical CTE names through joins, compound branches and membership/existence subqueries. Only physical tables receive the tenant namespace qualifier, so a CTE cannot accidentally resolve to a similarly named tenant table. Compound queries also retain their own WITH declarations instead of discarding them.
|
|
215
|
+
- **Refresh dashboard app reachability independently** — `@voltro/cli`
|
|
216
|
+
|
|
217
|
+
Probe discovered and registered dashboard apps independently and refresh their reachability automatically. Preserve healthy peer observations when the registry changes, cancel outdated requests on credential changes or navigation, and label unknown app types without counting them as web apps.
|
|
218
|
+
- **Recover independent app overview observations** — `@voltro/cli`
|
|
219
|
+
|
|
220
|
+
Recover individual app overview observations independently without hiding healthy routes or discarding RPC drafts during metadata outages. Cancel obsolete reads when app credentials change, reject invalid invocation snapshots, and deduplicate live-event replay per process. Show unavailable latency explicitly when counters have no duration measurements.
|
|
221
|
+
|
|
222
|
+
Use the shared labelled event-channel selector with empty-filter recovery, keyboard-expandable payloads and mobile route tabs. Label the actual invocation observation window and remove misleading growth indicators from static inventory counts.
|
|
223
|
+
|
|
224
|
+
Distinguish missing applications from initial discovery and registry failures, with a persistent return link and automatic recovery. Abort shared discovery reads when the last subscriber leaves and reject their late replies.
|
|
225
|
+
|
|
226
|
+
Include SPA in route filters, localize remaining metadata/table labels and make route tooltips and table scroll areas keyboard-accessible.
|
|
227
|
+
- **Preserve RPC drafts during temporary definition read failures** — `@voltro/devtools-ui`
|
|
228
|
+
|
|
229
|
+
Preserve open RPC execution drafts and pending results across temporary definition-read failures while hiding stale controls; inspection-context changes still reset the editor and recovery never repeats an invocation.
|
|
230
|
+
- **Shared table updates observe every known replica** — `@voltro/cli`
|
|
231
|
+
|
|
232
|
+
The local dashboard combines shared-store change feeds from all known app replicas, so writes through another replica update the visible table promptly instead of waiting for the periodic snapshot refresh. Row reads still honor the selected responder and writes execute once. Fleet membership changes update the feeds; missing inventory or disconnected members remain visible as reconnecting.
|
|
233
|
+
- **Dashboard live streams recover through known fleet entry points** — `@voltro/cli`
|
|
234
|
+
|
|
235
|
+
Local dashboard live streams now reuse the authorized fleet routes learned by ordinary reads. When an entry point stops, change notifications can reconnect through a remaining replica instead of waiting for periodic snapshots. Explicit replica selections, credential isolation and target checks remain enforced; unavailable selected processes stay unavailable and failed writes are not replayed.
|
|
236
|
+
- **Unconfirmed data cell saves show recovery context** — `@voltro/devtools-ui`
|
|
237
|
+
|
|
238
|
+
Failed inline saves explain that the change may already be stored, retain the draft, and request a fresh row snapshot. The last observed value and expandable error details help review the outcome. Explicit retries preserve the original compare-and-set expectation.
|
|
239
|
+
|
|
240
|
+
Editor controls wrap within narrow columns instead of being clipped by a fixed editor minimum width.
|
|
241
|
+
- **Data cell save state survives read outages** — `@voltro/devtools-ui`
|
|
242
|
+
|
|
243
|
+
Inline cell edits keep their pending-save lock when a temporary row or schema read failure hides the grid. Returning editors cannot submit a duplicate request, and save errors received while hidden reappear with the original draft.
|
|
244
|
+
- **Local data drafts survive app-metadata outages** — `@voltro/cli`
|
|
245
|
+
|
|
246
|
+
The local data explorer keeps its editor mounted when app-metadata reads fail, including a temporary outage of every API replica. The error stays visible while automatic retries restore the data view and its unfinished cell draft. Changing the app, endpoint or Inspect credentials resets the editor context. Retained routing information does not grant permissions or present failed observations as current data.
|
|
247
|
+
- **Treat database-generated columns as read-only in the data explorer** — `@voltro/cli`, `@voltro/devtools-ui`
|
|
248
|
+
|
|
249
|
+
The shared data explorer preserves generated-column metadata, displays computed values without edit controls, and omits them from row creation. Inspect writes reject generated inputs explicitly instead of relying on silent stripping or database errors.
|
|
250
|
+
- **Inline data drafts survive temporary read failures** — `@voltro/devtools-ui`
|
|
251
|
+
|
|
252
|
+
The data explorer retains an inline cell's draft when a temporary row or table metadata failure rebuilds the grid. Recovery preserves unfinished input without submitting it or resetting it to the database value. Saving still compares against the original value, so external changes remain protected by conflict detection.
|
|
253
|
+
- **Resolve database command roots without treating migration IDs as paths** — `@voltro/cli`
|
|
254
|
+
|
|
255
|
+
Database commands honor an explicit `--root` in either supported spelling. File-migration rollback resolves the app configuration and migration directory from that root, or the current directory when omitted, instead of interpreting the positional migration ID as an app path.
|
|
256
|
+
- **Match decimal relation keys across column scales** — `@voltro/database`
|
|
257
|
+
|
|
258
|
+
The batched eager loader now associates equivalent decimal keys even when related columns return different scales. One, many and junction relationships compare exact decimal values without converting them to floating-point numbers. Returned rows retain their original values, and text keys keep their exact string identity.
|
|
259
|
+
- **Preserve encoded decimal schema identity** — `@voltro/database`
|
|
260
|
+
|
|
261
|
+
Preserve internal SQLite-family decimal encoding, precision and scale through schema introspection and snapshot reconstruction. Block representation or encoded-shape changes that require explicit data conversion instead of treating them as ordinary type casts. Ordinary decimal declarations still use their existing storage.
|
|
262
|
+
- **Failed deploy undo reports every completed schema reversal** — `@voltro/cli`
|
|
263
|
+
|
|
264
|
+
When undo cannot complete, `revertedOperations` retains the schema reversals already performed, including foreign-key removals and completed character-set conversions. The failing operation is excluded, so the report accurately names what was undone and what still needs repair.
|
|
265
|
+
- **Soft-drop deploy undo preserves rows without blocking parent restoration** — `@voltro/cli`
|
|
266
|
+
|
|
267
|
+
On MySQL and MariaDB with `VOLTRO_SOFT_DROP=1`, a failed deploy removes outgoing foreign keys from newly created app tables before retaining them as snapshots, allowing active parent tables to regain their original character sets. The undo verifies baseline columns separately from newly retained snapshot columns and removes newly created framework tables before charset restoration.
|
|
268
|
+
- **Reduce repeated binding resolution in Doctor source scans** — `@voltro/cli`
|
|
269
|
+
|
|
270
|
+
Doctor indexes identifier names per source-file AST and skips form binding resolution when a submit path is absent. Declaration identity, shadowed bindings, complete file lists, and JSON findings remain unchanged.
|
|
271
|
+
- **Reduce overhead for immediate event publication** — `@voltro/runtime`
|
|
272
|
+
|
|
273
|
+
Event publication without a transaction or durable audience avoids an extra Effect generator. Validation and delivery remain lazy until execution; encoded size limits, transaction ordering, durable acknowledgements and both await and yield styles are preserved.
|
|
274
|
+
- **Gateway BYOK costs follow nested routing receipts** — `@voltro/ai`
|
|
275
|
+
|
|
276
|
+
`gatewayCostUsd` reads the final successful provider attempt of the final successful model attempt from `gateway.routing.modelAttempts[].providerAttempts`, so BYOK calls include the reported `marketCost` and gateway-credit fallbacks keep the gateway charge.
|
|
277
|
+
- **Keep global logs stable while pausing and reconnecting** — `@voltro/cli`
|
|
278
|
+
|
|
279
|
+
The local dashboard's global Logs page pauses the display while continuing to receive a bounded buffer. Resuming shows the latest captured entries without reopening streams. Replay identities prevent duplicate records after reconnects, and clearing rows preserves those identities so cleared records stay cleared. Unchanged app subscriptions remain open when another app appears. Connection failures retain captured logs and show automatic recovery status.
|
|
280
|
+
- **Isolate global metrics observations and recover failed sources** — `@voltro/cli`, `@voltro/devtools-ui`
|
|
281
|
+
|
|
282
|
+
Keep global dashboard invocation metrics responsive when another app is slow or newly discovered. Poll each app independently, preserve unchanged observations, and abort requests on app, credential, or navigation changes so late replies cannot replace the current source.
|
|
283
|
+
|
|
284
|
+
Reuse the shared invocation snapshot validator in the global page, reject malformed observations per source, preserve sort focus, and keep mobile tables keyboard-accessible.
|
|
285
|
+
- **Keep inspect creation receipts in their own deployment** — `@voltro/data-transfer`
|
|
286
|
+
|
|
287
|
+
Default logical exports omit inspect creation receipts, and logical imports preserve the destination's own receipts. A creation accepted elsewhere must not suppress or replay a command in the destination. Native disaster-recovery backups retain their existing behavior.
|
|
288
|
+
- **Count inspected rows without loading every matching ID** — `@voltro/cli`
|
|
289
|
+
|
|
290
|
+
Calculate Data explorer totals with a filtered store-side COUNT instead of loading every matching ID. Pagination still reports the complete filtered total, and requests without a count skip the extra query. Invalid count results fail explicitly instead of producing a misleading total.
|
|
291
|
+
|
|
292
|
+
Wire read-only creation-outcome observations in production startup as well, preserving receipt visibility without enabling arbitrary production data writes.
|
|
293
|
+
- **Loro apps run under voltro dev, and the collab template can switch to Loro** — `@voltro/cli`
|
|
294
|
+
|
|
295
|
+
Under `voltro dev` the browser resolved `loro-crdt` to its `bundler` build, which imports its WebAssembly as an ES module Vite cannot load, so every page using the Loro backend failed with "Cannot read properties of undefined (reading 'memory')"; `voltro build` was unaffected. `voltro dev` and `voltro build` now resolve every browser-side import of `loro-crdt` — the app's, `@voltro/local-first/loro`'s and `loro-prosemirror`'s — to its `browser` build, so there is one Loro instance, while server-side code keeps the Node build. The `api-collab` and `frontend-collab` templates choose their CRDT backend in one `lib/crdt.ts` file per app, and their README shows the switch to Loro.
|
|
296
|
+
- **Exact bigint sums and extrema in the memory store** — `@voltro/runtime`
|
|
297
|
+
|
|
298
|
+
The memory store now sums declared `bigint` values without losing decimal-string precision, includes them in floating-point averages, and compares their minimum and maximum numerically. Storage statistics retain their byte totals when metadata uses `bigint`, including inside transactions.
|
|
299
|
+
- **Install SQL Server driver dependencies in standalone workspaces** — `@voltro/cli`
|
|
300
|
+
|
|
301
|
+
`voltro add mssql` declares a missing SQL Server driver at the running CLI's lockstep version so an ordinary app can install it without local framework packages. Existing driver ranges are preserved. The completion message describes both shipped SQL Server patches.
|
|
302
|
+
- **Stop reporting SQL Server CDC retries after reader shutdown** — `@voltro/sql-mssql`
|
|
303
|
+
|
|
304
|
+
A stopped Change Tracking reader no longer reports a late in-flight poll failure as a retry or calls its error consumer. Active reader failures continue to be reported.
|
|
305
|
+
- **SQL Server deploy prepares workflow storage before serving** — `@voltro/cli`
|
|
306
|
+
|
|
307
|
+
SQL Server schema apply and deploy now prepare runtime-owned workflow storage before Timeline capture activation, allowing an already provisioned app to start with automatic migrations disabled and a serving identity without schema DDL rights. Timeline cleanup waits for in-flight SQL before rollback, preventing interrupted observers from leaving leases behind during shutdown.
|
|
308
|
+
- **Preserve exact SQL Server decimal row values** — `@voltro/sql-mssql`, `@voltro/database`
|
|
309
|
+
|
|
310
|
+
Preserve exact DECIMAL and NUMERIC strings in SQL Server mutation results and bulk change-event row images. Conversion occurs only when returning captured write results, retaining numeric storage and SQL arithmetic, NULL values, trigger compatibility, and MERGE action metadata.
|
|
311
|
+
|
|
312
|
+
Change Tracking reads use the same lossless final projection, including decimal columns added while the reader is running. Typed row SELECT projections also preserve declared decimal fields, including aliases and DISTINCT pagination, while filtering, ordering and nested SQL calculations remain numeric. Raw SQL, direct aggregate results, set operations and eager JSON projections remain outside this conversion boundary.
|
|
313
|
+
- **Await SQL Server cancellation before pooled connection reuse** — `@voltro/sql-mssql`, `@voltro/cli`
|
|
314
|
+
|
|
315
|
+
Interrupted SQL Server queries and procedures cancel their request and await its completion before pooled reuse or transaction rollback. Normal SQL failures still propagate, and cancellation does not wait for the query's full duration. The CLI ships the driver patch alongside the cluster patch. Existing SQL Server projects must rerun `voltro add mssql` and `pnpm install` at their pnpm workspace root to receive it; `voltro update` includes these migration steps.
|
|
316
|
+
- **Use native SQL Server renames for retained schema snapshots** — `@voltro/database`
|
|
317
|
+
|
|
318
|
+
SQL Server soft-drop now reuses the native table and column rename paths instead of emitting unsupported ALTER TABLE RENAME syntax. Checked columns retain their rewritten constraints and state. Recorded snapshots restore original table/column names and retained values through the existing restoration path.
|
|
319
|
+
- **Retire SQL Server Timeline capture within atomic schema deployments** — `@voltro/cli`
|
|
320
|
+
|
|
321
|
+
SQL Server Timeline retirement now joins an existing atomic schema-migration transaction, so real schema changes and soft-drop snapshots no longer fail the independent read-frame guard. Rollback restores capture ownership, triggers and application schema together. Serving replay frames continue to require a fresh transaction.
|
|
322
|
+
- **Reject orphan Timeline capture before SQL Server migrations** — `@voltro/cli`
|
|
323
|
+
|
|
324
|
+
SQL Server migration preparation detects leftover Timeline capture triggers even when private capture tables are missing and the serving schema resolves application tables through dbo fallback. Inconsistent ownership blocks application DDL; unrelated triggers on shadowed tables remain untouched.
|
|
325
|
+
- **SQL Server writes work with Timeline capture triggers** — `@voltro/sql-mssql`
|
|
326
|
+
|
|
327
|
+
SQL Server writes now capture returned row images with OUTPUT INTO, preserving normal writes, generated values, bulk rollback and MERGE upserts when Timeline or other DML triggers are enabled.
|
|
328
|
+
- **Read MySQL bulk inserts back through explicit primary keys** — `@voltro/sql-mysql`
|
|
329
|
+
|
|
330
|
+
MySQL `insertMany` now uses declared named and composite primary keys instead of assuming that a missing `id` means AUTO_INCREMENT. Batched readback preserves input order and database defaults, including keys whose database formatting differs from the input. All insert chunks and their readback share one transaction, and change events are emitted only after the complete operation succeeds. Missing explicit key components are rejected before writing. Ordinary `id` recovery and MariaDB's native RETURNING path retain their existing behavior.
|
|
331
|
+
- **Recover single MySQL inserts by their declared primary key** — `@voltro/sql-mysql`
|
|
332
|
+
|
|
333
|
+
Single MySQL inserts now share explicit-key readback with bulk inserts. A previous AUTO_INCREMENT operation on the connection can no longer select a stale `id`, and an ordinary non-key `id` column cannot cause the wrong row to be returned. Named and composite keys identify the persisted row independently of nullable non-key values; database defaults and namespace isolation are preserved. Ordinary AUTO_INCREMENT recovery and MariaDB RETURNING retain their existing behavior.
|
|
334
|
+
- **An empty agent inventory disables planner delegation** — `@voltro/plugin-ai-flows`
|
|
335
|
+
|
|
336
|
+
An explicit empty `EngineDeps.listAgents` result removes `run_agent` from planner tools. Failed listing refuses planning without widening allowed refs, and reserved tool names remain protected. An absent callback retains the plan-ref fallback.
|
|
337
|
+
- **Keep workspace Radix hooks on one React instance during prerender** — `@voltro/cli`
|
|
338
|
+
|
|
339
|
+
The build-time prerender and source middleware loaders now resolve Radix primitives through the same React deduplication as development. Building a dashboard that imports UI primitives from another workspace installation no longer fails with a null React hook dispatcher during static rendering.
|
|
340
|
+
- **Distinguish uncertain record saves and deletions** — `@voltro/devtools-ui`
|
|
341
|
+
|
|
342
|
+
Record dialogs now explain when a save or deletion was not confirmed, retain the draft and original compare-and-set expectations, and refresh the table observation after an uncertain response. Closing the dialog does not undo a committed write. Retries continue to reject intervening changes instead of adopting refreshed values as their expectation.
|
|
343
|
+
|
|
344
|
+
Late record and bulk-delete completions no longer close a newer dialog or clear a newer selection after a view change. Bulk deletion now explains unconfirmed outcomes and preserves original retry expectations. A successful batch retires only the submitted selection.
|
|
345
|
+
- **Reject mismatched decimal storage in typed readers** — `@voltro/database`
|
|
346
|
+
|
|
347
|
+
SQLite-family typed decimal reads now reject physical encoded keys when the application schema does not describe that representation, rather than expose those keys as decimal values. Explicitly encoded row decoding and logical query results retain their existing behavior. This check does not replace coordinated reader/writer exclusion during a storage migration or activate encoded storage.
|
|
348
|
+
- **Recheck observed release channel state before confirmation** — `@voltro/devtools-ui`
|
|
349
|
+
|
|
350
|
+
An open rollout, rollback or policy confirmation now becomes unavailable when the dashboard observes a changed channel state. The draft remains visible with an explanation; cancel and reopen the action to review the current target. Identical polling snapshots keep confirmations usable. This UI check does not provide server-side compare-and-swap semantics.
|
|
351
|
+
- **Validate release forms and isolate pending target actions** — `@voltro/devtools-ui`
|
|
352
|
+
|
|
353
|
+
The shared Releases dashboard rejects empty percentages and values outside 0–100 before submitting a rollout. Empty input is no longer converted to zero. An inline message explains the permitted range; explicit whole values, including zero and 100 remain supported. Pending actions lock their draft and prevent rapid duplicate submissions. A failed request preserves the draft for review and an explicit retry.
|
|
354
|
+
|
|
355
|
+
The canonical promote/rollout input schemas now reject fractional percentages before storage, matching the integer rollout column. Inspect reports HTTP 400 instead of a PostgreSQL persistence error for these invalid inputs.
|
|
356
|
+
- **Validate release inspect actions before execution** — `@voltro/plugin-releases`
|
|
357
|
+
|
|
358
|
+
Release inspect write endpoints now decode inputs through the corresponding RPC descriptor schemas. Malformed field types return HTTP 400 before changing release state or writing audit events, instead of reaching the executor unchecked.
|
|
359
|
+
- **Rendered-page styles, font caching and accessible code content** — `@voltro/cli`, `@voltro/content`, `@voltro/ui-shadcn`
|
|
360
|
+
|
|
361
|
+
Rendered pages include their static CSS dependencies before hydration, including locale variants and SSR/ISR shells. Fingerprinted generated fonts receive immutable caching. Markdown heading permalinks remain keyboard-accessible with meaningful names, and offscreen code blocks defer optional highlighting with corrected light-theme syntax contrast.
|
|
362
|
+
|
|
363
|
+
Islands entry shells also retain generated font definitions and preloads, so SSR sign-in pages use the configured fonts before hydration.
|
|
364
|
+
|
|
365
|
+
Production SSR streams negotiate Brotli/Gzip with per-chunk flushes, preserving initial-shell and deferred-boundary delivery without buffering the complete document.
|
|
366
|
+
|
|
367
|
+
Shared code CSS preserves light-theme inline colors alongside variable-based output, with dark-theme overrides retained.
|
|
368
|
+
- **Wake queued schedules when completion arrives during a turn check** — `@voltro/runtime`
|
|
369
|
+
|
|
370
|
+
Queued schedules retain run-ledger notifications received while reading a blocker and immediately re-check before waiting. A completion arriving at that boundary no longer adds a full polling interval; ordering, conditional turn-taking and the polling fallback remain enforced.
|
|
371
|
+
- **Expand integer columns without destructive migration authorization** — `@voltro/database`
|
|
372
|
+
|
|
373
|
+
Changing an `integer()` column to `bigint()` now plans a safe, value-preserving schema expansion. Existing rows and defaults are retained. SQLite and Turso already store integers in 64 bits, so this declaration change needs no DDL there. Reducing a `bigint()` column to `integer()` still requires explicit migration authorization.
|
|
374
|
+
|
|
375
|
+
SQL Server integer-range migrations preserve named defaults, CHECK trust and enabled state, and ordinary row-store index definitions inside the schema transaction. Foreign keys, schema-bound expressions, user-created statistics, and unsupported partitioned, compressed or non-row-store indexes are refused before removing any dependency and require a reviewed file migration. Explicit SQL Server `USING` transforms are refused instead of being silently ignored; PostgreSQL continues to apply the declared expression.
|
|
376
|
+
- **Require patched image processing dependencies** — `@voltro/cli`, `@voltro/plugin-storage`
|
|
377
|
+
|
|
378
|
+
Require sharp 0.35.5 or later for image processing to resolve the high-severity librsvg dependency advisory GHSA-wq5f-xc86-pv6w.
|
|
379
|
+
- **Scope SQL callback upserts to their complete conflict keys** — `@voltro/sql-postgres`, `@voltro/sql-mysql`, `@voltro/sql-mssql`
|
|
380
|
+
|
|
381
|
+
Postgres, MySQL, MariaDB and SQL Server now update the existing row through all declared conflict columns instead of assuming a text `id`. This fixes explicit and composite keys and prevents numeric IDs from producing an unfiltered update. The same key handling covers MySQL/MariaDB partial-insert fallbacks and SQL Server recovery when another writer wins an insert race. Existing transaction and concurrency contracts are unchanged.
|
|
382
|
+
- **SQL Server accepts Uint8Array binary parameters without conversion errors** — `@voltro/sql-mssql`
|
|
383
|
+
|
|
384
|
+
SQL Server now binds plain `Uint8Array` values as binary parameters, including subarrays, empty bytes, and payloads larger than 8,000 bytes. The adapter preserves each view's offset and length, retains existing `Buffer` support, and applies the same conversion to store writes and raw SQL instead of rejecting valid byte values with `EPARAM`.
|
|
385
|
+
- **Connect SQL Server Timeline to shared capture hosts and migrations** — `@voltro/cli`
|
|
386
|
+
|
|
387
|
+
Select coherent SQL Server source capture at the shared Timeline host boundary. Schema preparation installs its persisted capture contract; schema maintenance retires it before application DDL. Serving reads existing activation and can recover after later provisioning without installing schema objects itself.
|
|
388
|
+
|
|
389
|
+
Missing database Change Tracking or capture permissions leave Timeline unavailable while optional preparation reports a warning and application startup continues. Document the prerequisites, namespace resolution and bounded replay contract in English and German and regenerate shipped agent guidance.
|
|
390
|
+
- **Reuse prepared SQL Server Timeline contracts without schema DDL rights** — `@voltro/cli`
|
|
391
|
+
|
|
392
|
+
Validate an existing ready capture contract before entering migration-side ownership checks. An unchanged contract can be reused with the serving account's object permissions, without schema-wide VIEW DEFINITION or DDL rights. Changed or unavailable contracts still require the migration identity for repair.
|
|
393
|
+
- **Scope SQLite callback upserts to their conflict keys** — `@voltro/sql-sqlite`
|
|
394
|
+
|
|
395
|
+
SQLite-family callback upserts now address the existing row through every declared conflict column rather than assuming a text `id`. This supports explicit and composite keys and prevents numeric IDs from producing an unfiltered update. Key values continue through the registered column codecs, including decimals.
|
|
396
|
+
- **Execute recursive tree queries on SQLite and libSQL** — `@voltro/database`
|
|
397
|
+
|
|
398
|
+
Recursive SQLite compound terms now reference the recursive relation directly instead of wrapping it in a derived table that the engine rejects as circular. Nonrecursive anchor pagination, compound limits and outer pagination remain supported. Recursive branch-local ordering or pagination fails explicitly instead of changing meaning. The bilingual guide now selects the CTE result and identifies native Turso's unsupported recursive capability.
|
|
399
|
+
- **Match SQLite write conditions and keys to their column codecs** — `@voltro/database`, `@voltro/sql-sqlite`
|
|
400
|
+
|
|
401
|
+
Encode SQLite-family row keys and conflict lookup values consistently with inserts, including timestamp keys used by updates, JSON patches, deletes and insert-ignore. Schema-aware bulk predicates also support internally marked exact decimal storage without changing ordinary decimal schema emission.
|
|
402
|
+
- **SQLite set operations preserve branch queries and pagination** — `@voltro/database`
|
|
403
|
+
|
|
404
|
+
SQLite-family UNION, UNION ALL, INTERSECT and EXCEPT now compile executable compound queries. Input filters, ordering and pagination remain scoped to each branch, including nested operations. An outer offset without a limit also compiles correctly.
|
|
405
|
+
- **SQLite replica rebalancing keeps database traffic responsive** — `@voltro/workflow`
|
|
406
|
+
|
|
407
|
+
SQLite-backed workflow runners now admit individual shard releases one at a time, avoiding a burst of lock-row deletes when replicas join or restart. This prevents shard-release fan-out from delaying dashboard live refreshes and application writes over remote libSQL. Waiting releases remain cancellable, and release failures do not block later releases.
|
|
408
|
+
- **Answer missing enumerated static paths with 404** — `@voltro/cli`
|
|
409
|
+
|
|
410
|
+
Production web serving now returns the scoped not-found page with HTTP 404 when a static route exports `getStaticPaths` but the requested document was not generated. Published paths still serve their built HTML, and dynamic static routes without enumeration retain client-side fallback.
|
|
411
|
+
- **Storage metadata supports files and tenant usage beyond 2 GiB** — `@voltro/plugin-storage`
|
|
412
|
+
|
|
413
|
+
Storage reference sizes, database blob sizes, tenant byte/count counters, and shared-object reservation counters now use 64-bit SQL integers. Existing framework tables widen through schema reconciliation while the storage API retains exact JavaScript numbers up to `Number.MAX_SAFE_INTEGER`; reservations beyond that ceiling are rejected without consuming quota. Metadata failures retain the operation phase, safe database error codes, and retry classification without exposing SQL or row contents, so numeric overflow can be distinguished from a recoverable provider acknowledgement loss.
|
|
414
|
+
- **Explain storage encoding changes in rollout guidance** — `@voltro/database`
|
|
415
|
+
|
|
416
|
+
Clarify that a storage change with an unchanged logical column type can change read semantics, not only column bounds. Rollout guidance now distinguishes parameter changes from encoding changes and requires verified conversion with compatible readers/writers or a deployment without overlap.
|
|
417
|
+
- **Storage statistics preserve tenant and visibility groups on SQL stores** — `@voltro/plugin-storage`
|
|
418
|
+
|
|
419
|
+
Storage inventory statistics now retain tenant and visibility keys alongside SQL aggregates, so each tenant receives its own byte/count totals and public/private counts remain accurate. Totals that exceed the exact JavaScript number range fail with a typed `StorageError` instead of reporting rounded values.
|
|
420
|
+
- **Preserve native timestamp precision in predicate bindings** — `@voltro/database`
|
|
421
|
+
|
|
422
|
+
Temporal predicate strings with more than three fractional digits stay exact during SQL binding instead of passing through a millisecond Date. Guarded migration rewrites can compare unchanged imported timestamps without false contention and still reject competing sub-millisecond changes. Ordinary epoch-millisecond and ISO instant coercion remains unchanged.
|
|
423
|
+
- **Release native libSQL locks after failed statements** — `@voltro/sql-turso`
|
|
424
|
+
|
|
425
|
+
The libSQL backend now receives a temporary stable-driver patch through its SDK dependency. Failed native statements release their locks without reopening the connection or discarding session state. Application imports and configuration remain unchanged, including embedded replicas; no consumer override is required.
|
|
426
|
+
|
|
427
|
+
The SDK implementation is unchanged. Its package metadata selects the patched native driver, tested across all nine upstream platform targets. This temporary distribution will be removed once an official compatible release passes the SDK, embedded-replica, lock-recovery and clean-installation checks. The separate local Turso Rust engine is unaffected.
|
|
428
|
+
- **Keep decimal parity checks aligned with the migrated schema** — `@voltro/testing`
|
|
429
|
+
|
|
430
|
+
Keep the dialect parity schema-evolution fixture's registered descriptors in sync with each accepted migration, so typed decimal writes use the correct physical encoding. Verify that SQLite-family precision changes require explicit conversion, preserve the existing schema and exact values, and continue checking later enum, backfill and constraint migrations.
|
|
431
|
+
- **Carry the declared store charset into Timeline cluster preparation** — `@voltro/cli`
|
|
432
|
+
|
|
433
|
+
Timeline preparation during schema apply, create-only migration and development boot now passes the store's declared MySQL-family charset to the shared cluster migration gate. Newly created workflow storage uses that charset without changing the database default or rewriting existing storage during serving boot.
|
|
434
|
+
- **Keep Timeline data visible on narrow screens** — `@voltro/devtools-ui`
|
|
435
|
+
|
|
436
|
+
Timeline uses a compact table selector on narrow screens and keeps sequence navigation together above the data. Large table names no longer wrap into multiple rows of buttons on mobile; desktop table buttons and full event details remain available.
|
|
437
|
+
- **Keep native Timeline restores inside their target database** — `@voltro/cli`
|
|
438
|
+
|
|
439
|
+
MySQL/MariaDB Timeline triggers restore into the selected target without retaining source-schema references. Migration phases verify their connection context before changing objects, and rebuilding copied generation intents retires only matching target helpers while preserving the source contract.
|
|
440
|
+
- **Timeline explains protected values and adapts event colors to the theme** — `@voltro/devtools-ui`
|
|
441
|
+
|
|
442
|
+
Timeline cells explain server-only, encrypted and sensitive masking in English and German instead of displaying internal marker objects. Operation badges use readable text colors in light and dark themes.
|
|
443
|
+
|
|
444
|
+
Table selection and the scrubber share a compact control area so reconstructed rows appear sooner on narrow screens. Long table lists stay scrollable and selected table controls expose their state to assistive technology.
|
|
445
|
+
- **Share native Turso namespace attachments across pool connections** — `@voltro/sql-turso`
|
|
446
|
+
|
|
447
|
+
Keep native Turso tenant attachments consistent across the connection pool. Store and migration ATTACH statements now publish the engine-resolved file mapping; stale and newly constructed connections synchronize before subsequent queries. DETACH and reattachment invalidate cached statements. Failed provisioning preserves existing mappings, and private in-memory attachments are rejected on multi-connection pools instead of silently splitting tenant data across independent databases.
|
|
448
|
+
- **Enable supported generated columns on Turso backends** — `@voltro/database`, `@voltro/sql-turso`
|
|
449
|
+
|
|
450
|
+
Native Turso now enables VIRTUAL generated columns with MVCC. The schema emitter no longer rejects generated columns for every Turso backend, allowing VIRTUAL columns locally and both STORED and VIRTUAL columns through libSQL. The native engine still rejects STORED generated columns; the requested storage mode is never silently changed.
|
|
451
|
+
- **Manual upgrade notes include tracked SQL scripts** — `@voltro/cli`
|
|
452
|
+
|
|
453
|
+
Manual upgrade checks now scan tracked `.sql` files alongside source, shell scripts, configuration and runbooks. Direct database references in SQL scripts are located for review instead of silently missing an applicable upgrade note; scripts are never rewritten by these checks.
|
|
454
|
+
- **Verify physical decimal compatibility independently of automatic migration** — `@voltro/database`, `@voltro/cli`
|
|
455
|
+
|
|
456
|
+
SQLite-family applications now verify physical decimal markers before accepting schema compatibility, even with a matching recorded fingerprint or automatic migration disabled. Mismatched representation, precision or scale is rejected for empty tables as well as populated ones. Development, source serve and compiled serve share the read-only check; disabling migration still prevents automatic schema changes. This does not update already-running binaries, perform conversion or activate encoded decimal storage.
|
|
457
|
+
|
|
458
|
+
### Internal (no consumer-facing effect)
|
|
459
|
+
|
|
460
|
+
- **Declare the SQLite dependency of the media replay fixture**
|
|
461
|
+
|
|
462
|
+
The process-restart fixture resolves its SQLite driver through an explicit test dependency instead of assuming a neighboring package has already been built. This keeps clean-checkout typechecking independent of stale local build output.
|
|
463
|
+
- **Numeric formatting bounds excessive precision**
|
|
464
|
+
|
|
465
|
+
Project-owned dependency installations cap numeric formatting precision at the supported ECMAScript range, preserving normal CLI help and SQL Server diagnostic formatting. Patch integrity and installed formatter behavior are verified before a patched advisory is classified as remediated.
|
|
466
|
+
- **Verify completed client mounting and offline transport loss** — `@voltro/cli`
|
|
467
|
+
|
|
468
|
+
Browser validation waits for the completed client mount and verifies offline navigation after the test origin becomes unreachable, including service-worker requests that a page's emulated offline state may leave connected. Background Sync validation observes either the queued tag or its actual worker delivery.
|
|
469
|
+
- **Normalize generated Atom headline whitespace** — `@voltro/cli`
|
|
470
|
+
|
|
471
|
+
Generated release-feed headlines trim trailing whitespace after fallback-body truncation, with artifact-level regressions for XML escaping and truncation.
|
|
472
|
+
- **Classify owned migration and statement-local DDL sites** — `@voltro/cli`
|
|
473
|
+
|
|
474
|
+
The derived DDL-site guard records the existing decimal migration machinery, SQL Server capture migration pipeline and statement-local tempdb output collector with explicit ownership reasons. Unknown sites and stale entries remain failures.
|
|
475
|
+
- **Preserve CLI resource isolation during development** — `@voltro/cli`
|
|
476
|
+
|
|
477
|
+
Internal validation scheduling now isolates sustained CLI and database workloads. Published behavior is unchanged.
|
|
478
|
+
- **Align codemod metadata with the complete registry** — `@voltro/cli`
|
|
479
|
+
|
|
480
|
+
Regenerate the package manifest from the current codemod registry so release validation includes every registered migration.
|
|
481
|
+
- **Keep cold-start reference measurements separate** — `@voltro/cli`
|
|
482
|
+
|
|
483
|
+
Structural cold-start measurements can be refreshed without replacing the recorded latency measurement or its reference machine.
|
|
484
|
+
- **Preserve collection runner diagnostics and isolate process checks** — `@voltro/cli`
|
|
485
|
+
|
|
486
|
+
Collection verification retains runner startup errors and configured writable caches. Checks that launch real application processes execute serially while preserving their lifecycle and connection-budget assertions.
|
|
487
|
+
- **Acquire the Compose env audit image when missing** — `@voltro/cli`
|
|
488
|
+
|
|
489
|
+
The real Compose environment byte-preservation fixture pulls its declared Node image when absent instead of requiring an undocumented preloaded image. Existing cached images are reused and all actual container assertions remain unchanged.
|
|
490
|
+
- **Keep CRDT replica test workers outside shipped-source coverage** — `@voltro/integration-harness`
|
|
491
|
+
|
|
492
|
+
Place the process-backed CRDT replica helper in the existing test-fixture directory and update its integration-test launcher. Coverage continues to reject newly shipped source in suite-only packages while measuring the actual library packages.
|
|
493
|
+
- **Validate exact decimal conversion sources** — `@voltro/database`
|
|
494
|
+
|
|
495
|
+
Add an internal exact-decimal conversion boundary that validates shape changes without rounding and requires an explicit source-value decision for NUMERIC data that may already have lost precision. Ordinary storage and migration activation remain unchanged.
|
|
496
|
+
|
|
497
|
+
The internal owned conversion lifecycle now publishes a reviewed stage and can atomically restore original declared values while the published rows remain unchanged. It verifies retained artifacts, preserves later writes on completed-operation retries, and refuses stale rollback after external data changes. Explicit finalization atomically removes verified retained artifacts, closes the rollback window for published conversions, and preserves the completion receipt so retries cannot delete newly reused artifact names. Public conversion activation remains pending.
|
|
498
|
+
|
|
499
|
+
Retained copies and conversion stages preserve accessible implicit rowids without narrowing them through JavaScript numbers. Conversion and rollback retain AUTOINCREMENT high-water marks, including native Turso sequence allocation, and refuse rollback when row identity or allocation state has advanced.
|
|
500
|
+
- **Preserve ungrouped aliased rows in exact decimal queries** — `@voltro/database`
|
|
501
|
+
|
|
502
|
+
Use the row-preserving projection pipeline for explicitly encoded decimal queries containing only aliased columns. Preserve duplicates, exact ordering, filtering, DISTINCT and pagination without requiring GROUP BY. Ordinary schema emission is unchanged; this does not enable encoded decimal storage by default.
|
|
503
|
+
- **Route encoded decimal eager reads through schema-aware queries** — `@voltro/database`
|
|
504
|
+
|
|
505
|
+
Keep the SQLite JSON eager-load optimization off for explicitly encoded decimal sources, nested relation targets and junction tables. The existing batched relation loader applies exact predicates and logical row decoding through ordinary store queries. Ordinary decimal schema emission and other dialects are unchanged.
|
|
506
|
+
- **Bound exact decimal result decoding plans** — `@voltro/database`
|
|
507
|
+
|
|
508
|
+
Decode explicitly encoded row and window results through parallel relational stages in their enclosing SQL scope. Reuse exact sign and shape validation, preserve physical sort keys and bound parameter order, and avoid correlated result subqueries that multiply native Turso preparation memory. Do not carry unused or duplicate window ordering keys. Ordinary decimal schema emission and storage activation remain unchanged.
|
|
509
|
+
- **Route explicitly encoded SQLite decimal query results** — `@voltro/database`, `@voltro/sql-sqlite`, `@voltro/voltro`
|
|
510
|
+
|
|
511
|
+
Connect explicitly marked decimal schemas to exact SELECT lowering and projection-aware decoding, preserving ordinary NUMERIC columns, aggregate result types and namespace/CTE scope. Ordinary decimal schema emission remains unchanged pending complete storage adoption.
|
|
512
|
+
|
|
513
|
+
The optional query descriptor added to `decodeRowsFromSchema` preserves existing three-argument callers. Other API report changes are documentation and formatting only.
|
|
514
|
+
- **Connect physical decimal metadata to SQLite row codecs** — `@voltro/database`, `@voltro/sql-sqlite`
|
|
515
|
+
|
|
516
|
+
Encode and strictly decode explicitly marked internal decimal columns at the SQLite-family row boundary. Ordinary decimal storage remains unchanged; general query and migration activation remain pending.
|
|
517
|
+
- **Flatten exact decimal window CTE composition** — `@voltro/database`
|
|
518
|
+
|
|
519
|
+
Compose window calculation stages in their parent CTE scope and keep decimal window outputs physically encoded across that boundary. This avoids repeated encoding and reduces native Turso statement preparation cost. Isolate generated stage names case-insensitively and preserve bound parameter order. Ordinary decimal schema emission remains unchanged.
|
|
520
|
+
- **Compose exact decimal queries through derived CTE sources** — `@voltro/database`
|
|
521
|
+
|
|
522
|
+
The internal exact-decimal compiler preserves multiple decimal columns and ordinary fields through nonrecursive CTE declarations, including forward references, joins, membership queries, aggregates and set operations. Dependency-driven query-local output metadata and unique lexical names preserve nested scope without changing the table registry. Nonrecursive dependency cycles fail explicitly. Flat encoding stages avoid native Turso and libSQL nested-CTE failures. Recursive composition and ordinary storage adoption remain separate work.
|
|
523
|
+
- **Preserve exact decimal values at derived source boundaries** — `@voltro/database`
|
|
524
|
+
|
|
525
|
+
Add SQL encoding for logical decimal result sources without floating-point conversion. Source-local stages work across SQLite, native Turso and libSQL, preserve nulls and reject malformed values, overflow and nonzero excess fractional digits. This is an internal boundary for subsequent CTE integration; ordinary decimal storage is unchanged.
|
|
526
|
+
- **Verify an exact SQLite decimal physical schema and validation boundary** — `@voltro/database`
|
|
527
|
+
|
|
528
|
+
Add internal physical type, default and CHECK helpers for the candidate sortable decimal representation. Precision and scale live in the TEXT-affinity type name because native Turso omits custom type arguments from schema introspection. Constraints reject malformed keys, numeric writes, out-of-range values and NUL suffixes. Normal schema generation, store encoding and migration behavior remain unchanged until the complete storage contract is integrated.
|
|
529
|
+
- **Compose exact decimal compound queries across SQLite clients** — `@voltro/database`
|
|
530
|
+
|
|
531
|
+
The internal exact-decimal query compiler now composes set operations across different decimal scales without floating-point conversion. Numeric deduplication, ordering, branch pagination and aggregate results retain exact values. Flatter result stages avoid libSQL parser stack exhaustion. Ordinary decimal storage remains unchanged pending the complete migration and storage contract.
|
|
532
|
+
- **Compose exact decimal membership and existence subqueries** — `@voltro/database`
|
|
533
|
+
|
|
534
|
+
The internal exact-decimal query compiler supports non-correlated IN, NOT IN, EXISTS and NOT EXISTS in source predicates and aggregate filters. Shared output metadata preserves cross-scale membership and SQL NULL semantics without numeric casts. Shallower column decoding avoids libSQL parser stack exhaustion. Ordinary storage remains unchanged pending full adoption.
|
|
535
|
+
- **Keep framework table metadata bound to first-party source** — `@voltro/cli`
|
|
536
|
+
|
|
537
|
+
Framework table nullability metadata stays tied to first-party source declarations. Compiled native database workers retain their existing relocation and exact-value guarantees.
|
|
538
|
+
- **Execute real Helm chart rendering in CI** — `@voltro/cli`
|
|
539
|
+
|
|
540
|
+
Install pinned Helm in CI so Kubernetes chart rendering tests execute against the real tool instead of reporting an unavailable-tool diagnostic.
|
|
541
|
+
- **Verify media prompt changes across process restart** — `@voltro/ai`
|
|
542
|
+
|
|
543
|
+
Add a persistent SQL regression that kills the original media workflow process and resumes its journaled enqueue in a fresh process with a corrected prompt, with an offline provider and a new-execution control.
|
|
544
|
+
- **Resolve Timeline tests from their dedicated SQL Server fixture** — `@voltro/cli`
|
|
545
|
+
|
|
546
|
+
SQL Server Timeline integration tests reuse the dedicated test stack credential when no explicit test override is configured. No copied credential, runtime authentication change or availability skip is introduced.
|
|
547
|
+
- **Native restore coverage shares SQL Server fixture configuration** — `@voltro/cli`
|
|
548
|
+
|
|
549
|
+
Native SQL restore coverage reads the shared SQL Server fixture configuration consistently with the other integration checks.
|
|
550
|
+
- **Run native SQL tests with the declared fixture and capability lanes** — `@voltro/sql-mssql`, `@voltro/sql-turso`
|
|
551
|
+
|
|
552
|
+
SQL Server row-image, decimal-query and Change Tracking regressions borrow the shared test-stack credential instead of skipping when its optional environment override is absent. Decimal conversion registers only applicable native Turso schemas; existing real-engine rejection suites retain the unsupported syntax checks. The skipped-test gate remains unchanged.
|
|
553
|
+
- **Preserve scheduled validation evidence across concurrent updates** — `@voltro/cli`
|
|
554
|
+
|
|
555
|
+
Scheduled validation runs retain their results while newer updates are checked independently. Superseded ordinary checks still cancel within their event lane.
|
|
556
|
+
- **Match the production deploy fixture pool to SQL workflow startup** — `@voltro/cli`
|
|
557
|
+
|
|
558
|
+
Run the production deploy integration fixture with the three connections required by SQL workflow startup, preserving the real production storage and deploy assertions.
|
|
559
|
+
- **Protect retained decimal-conversion witnesses** — `@voltro/database`
|
|
560
|
+
|
|
561
|
+
Internal conversion source, stage and publication snapshots refuse row writes and retain their exact protection schema. Staging, retries, rollback and cleanup verify artifact protection. Cutover and rollback compare live values and rowids directly against protected snapshots, retaining allocation-watermark guards.
|
|
562
|
+
|
|
563
|
+
Content and physical-identity capture are paged. Durable identity and validated conversion-decision receipts store counts and digests rather than row arrays. Staging, publication, rollback and cleanup bind protected-source validation to the schema epoch inside the write transaction, preserving exact artifact ownership and late-change refusal without row-sized snapshot predicates. Initial source capture validates and copies through one pinned transaction, avoiding a row-sized SQL predicate between separate preflight and write phases. Stage validation balances conjunctions so larger reviewed sets do not exceed native Turso's expression-depth limit. Stage protection is removed only inside the guarded publication transaction; failed publication restores it and successful publication leaves the live table writable. Older mutable internal stages are refused rather than reused for image receipt capture.
|
|
564
|
+
|
|
565
|
+
Publication carries the schema epoch captured before complete protected-source and stage validation. It no longer repeats every reviewed row predicate in its write batch, and never resets the epoch after validation. The replaced row-literal guard builders and their whole-row collection branches are removed; snapshot verification uses the current paged digest readers.
|
|
566
|
+
|
|
567
|
+
Public conversion activation remains pending. Per-row stage statements and in-memory conversion-review/staging payloads still require bounded representation work.
|
|
568
|
+
|
|
569
|
+
Stage content checks now group at most 32 predicates per SQL statement, including all groups during creation and reuse. This bounds expression growth with row count; total staging arrays and individual wide keys remain separate limits.
|
|
570
|
+
|
|
571
|
+
Stage row decisions and grouped validations are generated incrementally from the sorted review instead of retaining duplicate full-table maps and SQL arrays. The reviewed cells remain materialized.
|
|
572
|
+
|
|
573
|
+
Stage creation now executes generated statements incrementally on one pinned transaction connection. Failure rolls back rows, schema, protection and ownership together; the foreign-key checks remain inside that transaction. The reviewed-cell input remains materialized.
|
|
574
|
+
|
|
575
|
+
Decimal source observations use bounded keyset pages with an overlap row, preserving exact typed composite identities and rejecting duplicates at page boundaries. Returned reviewed-cell arrays still require bounded storage work.
|
|
576
|
+
|
|
577
|
+
Retained-source coverage consumes observation pages directly and aborts before fetching later pages when validation fails. Explicit reviewed decisions remain indexed until complete coverage is proven; no full observed-cell list or separate observed-identity set is retained by this path.
|
|
578
|
+
|
|
579
|
+
Decision normalization is shared per cell, and witnesses can consume validated decisions incrementally while preserving the existing digest. Duplicate or unordered streamed identities invalidate the witness instead of accepting a partial prefix.
|
|
580
|
+
|
|
581
|
+
An internal transaction-owned review importer stores individually normalized decisions under an exact canonical index, hashes bounded pages, rejects duplicate imports and seals accepted rows against DML. Integration with source/stage lifecycle and ordinary migrations remains pending.
|
|
582
|
+
|
|
583
|
+
Stored-review verification checks the exact ownership receipt, both schemas and protection sets, canonical row keys/observations, bounded content hash and a stable schema epoch. Empty forged sort keys cannot hide before the first page. Ownership rows receive their own DML protection.
|
|
584
|
+
|
|
585
|
+
The internal stored-review verifier can now match retained-source observations through indexed batches of at most 128 decisions. It verifies the persisted receipt before coverage and rejects missing, extra, stale, shape-mismatched or ambiguous source decisions, plus schema changes during coverage. This prerequisite does not yet replace the normal conversion path’s in-memory review arrays.
|
|
586
|
+
|
|
587
|
+
Stored decisions can also be consumed as complete rows across page boundaries using the same canonical scanner. Consumers run inside the pinned transaction, preserve callback errors, and reject schema changes during consumption; stage lifecycle adoption remains pending.
|
|
588
|
+
|
|
589
|
+
Review stores can be reopened from the reviewed owner and witness after closing and recreating the client. Reopening verifies known complete table/index/protection definitions, including native Turso’s canonical trigger spelling, instead of accepting the schema claimed by a mutable receipt. Normal migration lifecycle adoption remains pending.
|
|
590
|
+
|
|
591
|
+
Retained decimal sources now create or reopen a deterministically owned review store inside source preparation’s transaction and use its bounded source-coverage verifier. The source receipt binds the review artifact identity. Publication artifact catalogs and atomic cleanup include both review tables. Stage array consumption and later publication-resume content verification are still being completed.
|
|
592
|
+
|
|
593
|
+
Decimal stage insertion and row validation now consume the retained source’s persisted review directly, including complete rows spanning decision pages. Stage manifests use that accepted witness, final validation uses a pinned transaction, and the obsolete array-row generator is removed.
|
|
594
|
+
|
|
595
|
+
Publication retry, rollback and cleanup now verify persisted review contents against the submitted review witness, not only artifact catalogs. Verification shares the protected-snapshot connection and pre-write schema epoch. Native Turso’s known trigger serialization after table rename is recognized independently from the original stored schema receipt; arbitrary catalog changes remain rejected.
|
|
596
|
+
|
|
597
|
+
Internal decimal migration reviews now accept repeatable iterables in unique canonical decision order. Source retry and publication identities hash normalized decisions incrementally rather than creating sorted arrays. Initial import verifies that its second read matches the first witness and rolls back one-shot or unstable input; ordinary file-migration wiring remains pending.
|
|
598
|
+
|
|
599
|
+
Removed the superseded in-memory review coverage map and array normalizer. Composite-key coverage regressions now execute the persisted-store verifier against real adapters; cell normalization and streaming witness tests remain.
|
|
600
|
+
|
|
601
|
+
An internally reviewed SQLite decimal publication can be applied again after a completed rollback. The previous owned receipt and retained artifacts are checked and retired before a fresh source capture. Reapplication validates the current source against the reviewed cells, preserves intervening unrelated field updates, and refuses stale conversion decisions without overwriting live values.
|
|
602
|
+
|
|
603
|
+
Internal retained decimal source and review artifacts use the reserved framework table namespace. Ordinary schema planning therefore keeps the recovery receipts and snapshots instead of treating them as undeclared application tables to drop.
|
|
604
|
+
- **Share dedicated SQL Server test fixture credentials** — `@voltro/database`, `@voltro/cli`
|
|
605
|
+
|
|
606
|
+
Share dedicated SQL Server fixture credentials across integration suites and execute soft-drop restoration whenever the test service is reachable; retain explicit connection overrides through Turbo.
|
|
607
|
+
- **Indexed source maps use bounded section offsets**
|
|
608
|
+
|
|
609
|
+
Source-map processing uses the repaired dependency version that rejects invalid indexed section offsets instead of blocking the event loop.
|
|
610
|
+
- **Prepare a bounded SQL Server Timeline capture plan** — `@voltro/cli`
|
|
611
|
+
|
|
612
|
+
Generate schema-aware transactional capture triggers gated by owned, ready metadata and a matching live observer window. Apply the image budget to the complete before/after pair after privacy masking; incomplete events retain neither image. Real SQL Server tests cover bulk writes, rollback, identity changes and composed Inspect replay using the generated plan and decoder. Guarded installation, continuity checks and ordinary host activation remain separate work; no serving path installs this plan automatically.
|
|
613
|
+
- **Prepare SQL Server Timeline physical catalog validation** — `@voltro/cli`
|
|
614
|
+
|
|
615
|
+
Add a schema-scoped catalog fingerprint for application and capture tables. Record column shape, defaults, computed expressions, indexes, constraints and trigger definitions without incorporating mutable data or identity counters. Reject missing tables and opaque metadata. Object-scoped VIEW DEFINITION is required for this reader. Ownership validation, installation and serving activation remain separate prerequisites.
|
|
616
|
+
- **Fence SQL Server Timeline reads against concurrent table resets** — `@voltro/cli`
|
|
617
|
+
|
|
618
|
+
Add an internal generation guard around unpublished coherent reads. Reject stale generations and concurrent table or journal resets. Refuse admission until a committed tracking version is later than every tracked table's start version: freshly enabled Change Tracking alone cannot distinguish all resets. Real SQL Server tests cover concurrent truncation, tracking interruption and table replacement. Migration preparation and serving activation remain pending.
|
|
619
|
+
- **Prepare SQL Server Timeline continuity checks** — `@voltro/cli`
|
|
620
|
+
|
|
621
|
+
Add a read-only internal generation reader combining tracked-table identity and Change Tracking start version with the database recovery fork. Missing or invisible metadata cannot establish continuity. Native SQL Server probes verify ordinary writes, TRUNCATE, tracking gaps, table replacement and full backup restoration. Permission checks, migration-owned preparation and guarded serving activation remain separate work; this does not enable a serving capture path.
|
|
622
|
+
- **Prepare guarded SQL Server Timeline source reads** — `@voltro/cli`
|
|
623
|
+
|
|
624
|
+
Read journal events and snapshot rows through one transaction-bound reader. Check the observer contract, catalog, generation and live pruning receipts on both sides of the snapshot, rejecting expiry during a row read. Failed reads do not acknowledge or consume events. Recorder session publication and ordinary backend activation remain pending.
|
|
625
|
+
- **Compose SQL Server Timeline installation and namespace discovery** — `@voltro/cli`
|
|
626
|
+
|
|
627
|
+
Compose owned capture retirement, preparation and persisted activation under the caller's migration coordinator. Reuse a valid active contract without resetting its observers; retire stale capture before rebuilding. Resolve physical table schemas through SQL Server object lookup, including default-schema fallback, and reject mixed or unavailable namespaces.
|
|
628
|
+
|
|
629
|
+
Ordinary migration and serving backend selection remain unchanged.
|
|
630
|
+
- **Prepare SQL Server Timeline journal frames** — `@voltro/cli`
|
|
631
|
+
|
|
632
|
+
Add an internal SQL Server journal reader using the coherent read transaction. Share retained-history validation with MySQL/MariaDB, including visible source positions, acknowledged pruning and complete row images. Actual Inspect tests keep a historical replay stable across committed updates, inserts and deletes. Capture provisioning, continuity guards and ordinary host activation remain separate work; this does not enable SQL Server source capture in serving paths.
|
|
633
|
+
- **Preserve migration lock scope in SQL Server Timeline sessions** — `@voltro/cli`
|
|
634
|
+
|
|
635
|
+
Allow SQL Server Timeline maintenance and recorder sessions to use the migration coordinator's configured lock scope independently of physical table schema. Propagate that scope through admission, acknowledgements, retention and closure. Ordinary backend selection remains unchanged while its integration is prepared.
|
|
636
|
+
- **Prepare SQL Server Timeline observer admission** — `@voltro/cli`
|
|
637
|
+
|
|
638
|
+
Add tracked lease storage and migration-coordinated observer admission and closure. Validate the ready epoch, generation and physical catalog before opening immutable server-clock capture windows. Drain in-flight writers, retain history protected by another live observer, and establish a fresh baseline after observer/window expiry. Closing is idempotent and scoped to its observer. ACK, retention and session publication remain pending; ordinary serving and migration backend selection are unchanged.
|
|
639
|
+
- **Prepare SQL Server Timeline observer acknowledgements and retention** — `@voltro/cli`
|
|
640
|
+
|
|
641
|
+
Add revision-fenced acknowledgements, immutable renewal windows and bounded journal retention for the internal SQL Server Timeline foundation. Expired observers cannot renew; retention invalidates lagging observers before deleting unseen events. Surviving observers receive explicit pruning receipts, including when collection occurs between reading and acknowledging a frame.
|
|
642
|
+
|
|
643
|
+
Source/session publication and final activation remain pending. Ordinary dashboard backend selection and migration hooks are unchanged.
|
|
644
|
+
- **Prepare persisted SQL Server Timeline activation contracts** — `@voltro/cli`
|
|
645
|
+
|
|
646
|
+
Persist the prepared generation and physical catalog contract when activating owned Timeline storage. Reject drift between preparation and activation, and discover serving contracts without adopting the current generation on failure. Retirement clears activation. Extend the unactivated internal storage plan to carry the contract; ordinary migration and backend selection remain unchanged.
|
|
647
|
+
- **Persist and retire SQL Server Timeline capture plans** — `@voltro/cli`
|
|
648
|
+
|
|
649
|
+
Store the hashed capture plan with internal metadata so migration retirement does not require an obsolete application registry. Validate it before touching triggers. Retire under the migration coordinator: rotate the epoch, clear capture windows and history, and remove only verified triggers in one transaction after in-flight writers drain. Preparing a changed plan is allowed only after explicit retirement. Native tests cover plan changes, removed tables, failed subsequent DDL and altered-trigger refusal. Serving activation remains pending.
|
|
650
|
+
- **Prepare a coherent SQL Server Timeline read boundary** — `@voltro/cli`
|
|
651
|
+
|
|
652
|
+
Add an internal driver-owned read transaction for SQL Server Timeline source work. Bind isolation, lock timeout and observer deadlock priority to each read RPC, reject nested transactions, and discard conflicting frames completely. Real SQL Server tests cover pooled state, interruption, caller transaction ownership and a coherent retry after concurrent writes. This does not activate SQL Server Timeline source capture or change ordinary host behavior.
|
|
653
|
+
- **Prepare scoped SQL Server Timeline recorder sessions** — `@voltro/cli`
|
|
654
|
+
|
|
655
|
+
Serialize coherent source reads, decode complete batches and acknowledge them before recorder publication. Scope closure and failed or interrupted reads retire the recorder identity and close the observer lease. Internal polling renews the observer and collects changes while the session is open.
|
|
656
|
+
|
|
657
|
+
Ordinary backend wiring, snapshot projection and final activation remain pending.
|
|
658
|
+
- **Prepare schema-aware SQL Server Timeline images** — `@voltro/cli`
|
|
659
|
+
|
|
660
|
+
Add internal SQL Server image expressions and decoder support for exact decimal and bigint text, UTC timestamps, JSON scalars, unusual column names and masked fields. Reject malformed JSON and non-null unsupported storage before capture publication. This prepares generic source capture; migration provisioning, complete-event size limits and ordinary host activation remain separate work.
|
|
661
|
+
- **Compose guarded SQL Server Timeline schema preparation** — `@voltro/cli`
|
|
662
|
+
|
|
663
|
+
Compose application, storage and trigger guards into migration-coordinated capture preparation. Create missing matching objects, enable table tracking and commit the control update required by the generation fence. Stay preparing; ready capture must be retired explicitly. Native tests cover retry, concurrent preparation, missing-trigger recovery and rollback on denied trigger creation. Recognize SQL Server's own tracking child objects while rejecting unexpected dependencies. Preserve original failures alongside transaction-cleanup failures. Observer admission, retention and serving activation remain pending.
|
|
664
|
+
- **Rediscover SQL Server Timeline activation after session invalidation** — `@voltro/cli`
|
|
665
|
+
|
|
666
|
+
Resolve persisted activation when opening a new observer instead of retaining a fixed startup contract. Running recorder sessions can establish a new baseline after migration or later provisioning without serving-side DDL. Require callers to provide the migration lock scope explicitly. Ordinary backend wiring remains pending.
|
|
667
|
+
- **Prepare SQL Server Timeline snapshot projection** — `@voltro/cli`
|
|
668
|
+
|
|
669
|
+
Read Timeline snapshot pages through the coherent source transaction using the journal's exact scalar encoding, privacy rules and row decoder. Unsupported, malformed or oversized images reject the entire snapshot. Scoped recorder sessions now expose table reads backed by this projection.
|
|
670
|
+
|
|
671
|
+
Final activation and ordinary backend wiring remain pending.
|
|
672
|
+
- **Guard SQL Server Timeline storage adoption** — `@voltro/cli`
|
|
673
|
+
|
|
674
|
+
Add a read-only migration-side guard for existing capture storage. Require complete metadata visibility, the expected private table shape and primary keys, and one valid framework owner record. Refuse collisions, incomplete storage, altered identity settings and unexpected dependent objects without repairing or deleting them. Trigger ownership and guarded installation remain separate prerequisites; serving capture is not activated.
|
|
675
|
+
- **Validate SQL Server Timeline application-table prerequisites** — `@voltro/cli`
|
|
676
|
+
|
|
677
|
+
Add a read-only, schema-scoped preflight for capture identity and projected columns. Reject nullable, computed, nonunique, disabled, filtered or compound identities, and reject storage types incompatible with the image encoders. A unique id index may contain included columns, but Change Tracking also needs an enabled primary key. Native SQL Server tests cover these constraints and same-name tables in other schemas. Exact physical-shape fingerprints, private storage ownership and installation remain prerequisites to serving activation.
|
|
678
|
+
- **Validate SQL Server Timeline trigger ownership** — `@voltro/cli`
|
|
679
|
+
|
|
680
|
+
Validate application capture triggers against their recorded generated plan before migration-side adoption. Reject changed bodies, parents, execution options, disabled triggers and colliding objects without modifying them. A ready capture requires all triggers; a preparing installation may have missing ones. Plan upgrades still require explicit retirement. This does not install triggers or activate serving capture.
|
|
681
|
+
|
|
682
|
+
---
|
|
683
|
+
|
|
42
684
|
## [0.83.1] — 2026-10-04
|
|
43
685
|
|
|
44
686
|
### Added
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/plugin-comments",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.84.0",
|
|
4
4
|
"description": "Comment threads on any anchor your app can name — replies, resolve/reopen, reactions, per-subject unread — live over the existing reactivity channel, with no second push mechanism. Access delegates to your app's own guard (access.viaEntity) or a scope and fails closed when neither is declared; @-mentions are re-filtered to the caller's tenant on search and re-validated at create, then delivered through plugin-notifications when it is installed. useComments / useThread / useMentionSearch in /web, an ejectable <CommentsThread> in @voltro/ui, plus inspect endpoints and a dashboard panel.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -48,10 +48,10 @@
|
|
|
48
48
|
"node": ">=24.0.0"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@voltro/client": "0.
|
|
52
|
-
"@voltro/database": "0.
|
|
53
|
-
"@voltro/plugin-notifications": "0.
|
|
54
|
-
"@voltro/protocol": "0.
|
|
51
|
+
"@voltro/client": "0.84.0",
|
|
52
|
+
"@voltro/database": "0.84.0",
|
|
53
|
+
"@voltro/plugin-notifications": "0.84.0",
|
|
54
|
+
"@voltro/protocol": "0.84.0"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
57
|
"effect": "^3.22.2",
|