@voltro/plugin-auth 0.46.0 → 0.47.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/package.json +3 -3
package/CHANGELOG.md CHANGED
@@ -39,6 +39,36 @@ _Changes staged for the next release accumulate here (rolled up from
39
39
 
40
40
  ---
41
41
 
42
+ ## [0.47.0] — 2026-08-22
43
+
44
+ ### Changed
45
+
46
+ - **@voltro/database, @voltro/data-transfer, @voltro/cli, @voltro/plugin-storage** — A `--mode replace` no longer writes per-row history, and three things that were reported alongside it.
47
+
48
+ **Write recorders are suspended for a `replace`.** A replace SETS a state; it does not change rows, so a per-row history entry describes something that did not happen. A deployment measured what that costs: they run `versioningPlugin({ timing: 'in-transaction' })` on 70 of 80 tables, so one import wrote 242 950 history rows and doubled the write load of the most expensive run they make — and those rows were the source of refused writes they spent three rounds diagnosing.
49
+
50
+ The deciding argument is not the cost. **The import path had already decided this, and the recorder was the one layer that did not hear.** These routes write through the RAW store on purpose — no tenant scoping, no row filter, no `audit()` stamping. A recorder fired anyway because it hangs one level below the wrapper. Suspending it makes the layers agree.
51
+
52
+ Suspended for `replace` only: an `upsert` or an `append` CHANGES existing state, which is exactly what a recorder is for. Scoped per execution context rather than by a switch, because an import runs while the app serves requests and a process-global flag would silently drop recording for everything concurrent with it. And every such run SAYS what it suspended — dropping history quietly would be the same defect in a nicer costume.
53
+
54
+ This also removes the reason a staged `replace` used to fall back. A recorder is keyed by table name, so a staged write found none and the recorder never ran; rather than record inconsistently, the run took the slower path. For the deployment above that meant the staged path could never activate — permanently, on every environment.
55
+
56
+ **`voltro codegen` wrote a truncated table declaration.** It discovered tables with the walk that collects the rpc GROUP's inputs — descriptors, workflows, events, and deliberately no `*.entity.ts`. So the generated `voltro-tables.generated.d.ts` listed the framework's tables plus `actors`, which the framework injects. Measured downstream: 37 names where a `voltro dev` boot writes 117, and 299 `TS2322` errors from every `source:` naming one of their own tables. The way in was our own message — `voltro test` refuses a stale rpc group and tells you to run `voltro codegen`. Table discovery has its own walk now, and a test compares the two walks' RESULTS on a real tree rather than trusting they mean the same thing.
57
+
58
+ **The eager-relation doctor rule missed the state that is most wrong.** It resolved relations only against the tables a query already DECLARED, on the reasoning that the base is virtually always in `source:`. Measured: a query reading `projects` while declaring only `projectTeams` produced no finding at all, while the same query with the base added produced two. The base is a fact about the executor, so it is read from the executor now.
59
+
60
+ **A rollback capture says when its path shares the root filesystem.** The 409 answered "is storage configured", which is not the question — a `filesystem` provider pointed at a container directory with no volume behind it passes it and dies with the pod. What a process CAN observe is that a mounted volume is a different filesystem: `pathDurability` compares device ids, and a capture landing on the same device as `/` says so. Three-valued on purpose, and explicitly not an alarm on a development machine, where everything is one device and nothing is a pod.
61
+
62
+ **And the import records ITSELF, once.** Dropping per-row history left an operator asking "was this data imported, and when" with nothing to read, and trading too much for none is not obviously the better trade. `_voltro_data_imports` carries one row per RUN: the mode, the transport, the bundle, the SOURCE deployment's schema fingerprint, the counts, and — for the run an operator is actually looking for — the failure. It is written for a failed import as well as a finished one; a trail that only records successes goes quiet exactly when it is needed.
63
+
64
+ Best effort, unlike the interrupted-replace marker, and the difference is deliberate: the marker is a safety interlock and a run that cannot write it must not proceed, while history is valuable and not load-bearing. A target that has not been migrated yet still imports, and says the trace could not be written.
65
+
66
+ Two things it learned from being wired. The table is `.nonReactive()` — nobody subscribes to "an import happened", and a reactive bookkeeping write showed up in every suite that counts the LOAD's writes. And it is written only when the target actually DECLARES the table: the in-memory store accepts a write to any name, so an absent table cannot be detected by the write failing, and inventing the row would put a framework write into every embedder's counts.
67
+
68
+ **Measured at the reported magnitude.** 114 tables, 243 048 rows, real MariaDB, staged replace: the whole run takes 56.5s and the DESTRUCTIVE TRANSACTION takes **1.13s**. The window in which a dead process can leave a half-replaced target is the second number; before this it was the first.
69
+
70
+ ---
71
+
42
72
  ## [0.46.0] — 2026-08-22
43
73
 
44
74
  ### ⚠ BREAKING
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voltro/plugin-auth",
3
- "version": "0.46.0",
3
+ "version": "0.47.0",
4
4
  "description": "Authentication primitives: password hashing, session creation, schema mixin + tables. Pairs with the `auth` app template for the UI; both independently usable. Server-side only (uses node:crypto).",
5
5
  "keywords": [
6
6
  "voltro",
@@ -79,8 +79,8 @@
79
79
  },
80
80
  "dependencies": {
81
81
  "@effect/sql": "^0.52.0",
82
- "@voltro/database": "0.46.0",
83
- "@voltro/protocol": "0.46.0"
82
+ "@voltro/database": "0.47.0",
83
+ "@voltro/protocol": "0.47.0"
84
84
  },
85
85
  "peerDependencies": {
86
86
  "effect": "^3.22.0",