@voltro/ui-shadcn 0.72.0 → 0.73.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 +85 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -39,6 +39,91 @@ _Changes staged for the next release accumulate here (rolled up from
|
|
|
39
39
|
|
|
40
40
|
---
|
|
41
41
|
|
|
42
|
+
## [0.73.0] — 2026-09-17
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
|
|
46
|
+
- **Typed writes on the Effect channel — the row check and StoreError compose** — `@voltro/runtime`
|
|
47
|
+
|
|
48
|
+
`insertRow`, `insertManyRows`, `upsertRow`, `upsertRowOutcome` and `insertIgnoreRowOutcome` check their payload against the table — a required column the row omits is a compile error at the call site — and return a `Promise`. `EffectStore` carries every one of those operations on the typed error channel and takes `(table, row)` with an unchecked `Row`.
|
|
49
|
+
|
|
50
|
+
So the two properties excluded each other. A handler that wanted the row checked gave up `StoreError`; one that wanted the channel passed an unchecked row. There was no third option: wrapping a typed helper in `Effect.promise` runs the write outside the Effect and discards exactly the channel at issue.
|
|
51
|
+
|
|
52
|
+
Five helpers close it, with the same signatures over a store whose methods return Effects:
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
const store = yield* EffectStore
|
|
56
|
+
const saved = yield* insertRowEffect(store, players, { tenantId, name })
|
|
57
|
+
const { row, outcome } = yield* upsertRowOutcomeEffect(store, players, player, {
|
|
58
|
+
conflictColumns: ['tenantId', 'externalId'],
|
|
59
|
+
update: ['name', 'score'],
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
`EffectStore` satisfies each helper's store parameter structurally, so it is the argument at every call site. The row type, the conflict-key constraint and the return type are spelled as the Promise forms spell them, so moving between the two families means reading one signature rather than two.
|
|
64
|
+
|
|
65
|
+
One deliberate difference: `upsertRowOutcome` throws when a hand-written `DataStore` lacks `upsertWithOutcome`. `EffectStore` always provides it, so the Effect form does not carry that failure — an error case for an unreachable condition is one every caller must handle and none can trigger.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- **A module that re-exports the generated route builder is not a hand-roll** — `@voltro/cli`
|
|
70
|
+
|
|
71
|
+
`voltro doctor`'s `hand-route-module` rule read the importing file and asked whether it mentioned `.framework/routes.generated`. An app that keeps exactly one module importing the generated builder and re-exports it — so that a single file owns the dependency — therefore had every consumer of that alias reported, while using the typed builders the rule recommends.
|
|
72
|
+
|
|
73
|
+
The rule now resolves the imported module and stays silent when it re-exports the generated builder. A genuinely hand-maintained route or url module is reported as before.
|
|
74
|
+
|
|
75
|
+
An alias onto a generated artefact is the adoption of this rule, and a finding that fires on the adoption is an argument for deleting the seam that made it clean.
|
|
76
|
+
- **The migration codemod no longer re-indents the body it rewrites** — `@voltro/cli`
|
|
77
|
+
|
|
78
|
+
`0.72.0/01_migration-context-raw` rewrites two lines per migration and produced diffs of 85 to 133 changed lines. Two causes, both removed.
|
|
79
|
+
|
|
80
|
+
A migration whose body is an expression — `up: (ctx) => Effect.gen(function* () { … })`, the common shape — was hoisted into a block so the `raw(reason)` binding had somewhere to live, which indented the entire body one level. The binding is placed inside the generator instead, so the body keeps its position and the change is the two lines it actually is.
|
|
81
|
+
|
|
82
|
+
Separately, every node any codemod inserted was printed with four-space indentation while this framework's own templates use two. That is fixed for all codemods, not just this one.
|
|
83
|
+
|
|
84
|
+
Neither changes what the codemod means. It changes whether the diff can be read — which matters here more than most, because every `raw(reason)` it writes is a placeholder its author has to fill in before committing.
|
|
85
|
+
- **voltro serve refuses a serve bundle built by a different framework version** — `@voltro/cli`
|
|
86
|
+
|
|
87
|
+
`voltro serve` loads the precompiled serve bundle, and a bundle built before an upgrade imports perfectly — it simply runs the previous version's code. Nothing said so. Updating `@voltro/*` without re-running `voltro build` therefore left a process serving the old framework while the installed one had moved on, and the only way to notice was to recognise a log line's shape as belonging to the older release.
|
|
88
|
+
|
|
89
|
+
The bundle already carries the version that built it. `voltro serve` now reads it before importing and refuses when it disagrees with the installed CLI, naming both versions and the command that fixes it:
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
FATAL: the serve bundle was built by @voltro/cli 0.71.1, but 0.72.0 is installed.
|
|
93
|
+
Serving it would run 0.71.1's code against 0.72.0's dependencies.
|
|
94
|
+
Rebuild it: voltro build .
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
A mismatch refuses rather than falling back to the slower boot path: it is a build error of the deployment, and quietly running a different version is the failure being fixed. A bundle carrying no version marker is left alone — those predate the marker and are not evidence of anything.
|
|
98
|
+
- **A workflow step can reach the store under the test runner** — `@voltro/testing`
|
|
99
|
+
|
|
100
|
+
A workflow step may `yield* EffectStore`, and in production it gets one: the runtime provides the layer from the context's store. `makeWorkflowRunner` provided the step recorder and the workflow's own layer and nothing else, so the step died under test with
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
Service not found: @voltro/EffectStore
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
while the identical code ran in production. The only supported way to drive a workflow in a test could not run the form the framework documents, which left `Effect.promise` as the shape people shipped instead.
|
|
107
|
+
|
|
108
|
+
The runner now provides the same layer from the same place production does, from the context it already receives. A context without a store stays runnable, so a test that never touches the store does not acquire a requirement.
|
|
109
|
+
- **The AI usage receipt key no longer refuses to migrate an existing ledger** — `@voltro/ai`, `@voltro/cli`
|
|
110
|
+
|
|
111
|
+
`_voltro_ai_usage.receiptKey` arrived NOT NULL with neither a default nor a backfill, so adding it to a database that already holds usage rows was refused:
|
|
112
|
+
|
|
113
|
+
```
|
|
114
|
+
auto-migrate: REFUSED — 1 blocked operation(s):
|
|
115
|
+
- add-column [_voltro_ai_usage]: NOT NULL column on a table whose row count is unknown
|
|
116
|
+
auto-migrate failed — aborting boot
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
The refusal was correct and its advice was not reachable: it asks whoever owns the declaration to add `.backfill()` or `.default()`, and this table is the framework's, not the app's. `VOLTRO_AUTO_MIGRATE=0` left the app on the previous schema and `voltro db apply` refused the same way before a deploy, so an upgrade could not be rolled out at all.
|
|
120
|
+
|
|
121
|
+
The column now derives a per-row value from the row's own id. A literal default could not do this job — the column is UNIQUE, so one value for every existing row collides on the second — and the derivation is computed per row rather than in SQL because string concatenation has no dialect-neutral spelling and this table ships on five.
|
|
122
|
+
|
|
123
|
+
A guard now plans every framework table against a populated database and fails on any column added since the last release that an app could not migrate onto. Two earlier shapes of that check were built and discarded, each disproved by its own measurement: both asked every framework column to be addable, and a column created together with its table never is.
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
42
127
|
## [0.72.0] — 2026-09-16
|
|
43
128
|
|
|
44
129
|
### ⚠ BREAKING
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/ui-shadcn",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.73.0",
|
|
4
4
|
"description": "Voltro's first-party shadcn/ui kit: Tailwind v4 design tokens (light + dark), 30+ primitives, layout compositions, styled widgets for the @voltro/ui seam, and the canonical theme/language preference-cookie helpers.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"@radix-ui/react-toggle-group": "^1.1.19",
|
|
53
53
|
"@shikijs/langs": "^4.4.3",
|
|
54
54
|
"@shikijs/themes": "^4.4.3",
|
|
55
|
-
"@voltro/ui": "0.
|
|
55
|
+
"@voltro/ui": "0.73.0",
|
|
56
56
|
"class-variance-authority": "^0.7.1",
|
|
57
57
|
"clsx": "^2.1.1",
|
|
58
58
|
"shiki": "^4.4.3",
|