@voltro/cli 0.39.0 → 0.40.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 +210 -0
- package/dist/agentsMd-Bu_XQgVf.js +2 -0
- package/dist/{agentsMd-7zI2h5l9.js → agentsMd-D6yD7IQv.js} +31 -14
- package/dist/apiBuild-BIyGkym8.js +2 -0
- package/dist/{apiBuild-DGalUk9v.js → apiBuild-C8xBEYbL.js} +2 -2
- package/dist/bin.js +1 -1
- package/dist/{build-CfF6t0UM.js → build-CkhFGnKA.js} +168 -165
- package/dist/{checkCommand-CBtynBKW.js → checkCommand-BcXJa2IS.js} +3 -3
- package/dist/{checkCommand-BV56Pcc1.js → checkCommand-QbHshOac.js} +1 -1
- package/dist/{cloudCmd-C42gaO8s.js → cloudCmd-F4YJeqM3.js} +1 -1
- package/dist/{codegenCommand-W7SDdiAQ.js → codegenCommand-DF2OJh3O.js} +2 -2
- package/dist/{codemodRunner-D-jTyvWo.js → codemodRunner-BcOvi4A2.js} +103 -0
- package/dist/{commands-BD9eBRY3.js → commands-7Z7-HOE3.js} +30 -30
- package/dist/{dashboardCommand-7qGylm0F.js → dashboardCommand-CUycH6dR.js} +5 -5
- package/dist/{dataCommand-C_F2DYxe.js → dataCommand-By78lscK.js} +1 -1
- package/dist/{dev-alhkKoEX.js → dev-D8JSKlBM.js} +1 -1
- package/dist/{dev-gqpnzVhI.js → dev-Dh1NuYx1.js} +1569 -1569
- package/dist/{doctorCommand-Bvs-BQrM.js → doctorCommand-C-8-Z9D6.js} +55 -42
- package/dist/doctorCommand-FhQ7EVYL.js +2 -0
- package/dist/{dormancyCommand-B-PPHc9Q.js → dormancyCommand-A79Odglm.js} +1 -1
- package/dist/{embeddingsCommand-OKY6XjUf.js → embeddingsCommand-CoiyHfkY.js} +1 -1
- package/dist/{envCommand-B1-Zm85H.js → envCommand-B6d0s-jZ.js} +8 -8
- package/dist/{evolveCommand-C4-NlFbd.js → evolveCommand-BC5a9lxX.js} +2 -2
- package/dist/frameworkTableAssembly-DgylYh9_.js +2 -0
- package/dist/index.js +1 -1
- package/dist/{infoCommand-CTo8Jnhq.js → infoCommand-ZqSVzJZ4.js} +1 -1
- package/dist/{metaCommands-DUYR--Ts.js → metaCommands-CfRLra0s.js} +1 -1
- package/dist/{projectScaffold-BEhhHjPr.js → projectScaffold-BIl97_E6.js} +1 -1
- package/dist/{projectScaffold-BvhLOrLq.js → projectScaffold-mIX_DpSe.js} +1 -1
- package/dist/{runtimeTrace-DzZOCd94.js → runtimeTrace-BslKJjDY.js} +1 -1
- package/dist/{sdkgen-C4roLErM.js → sdkgen-DQ8uEmmn.js} +1 -1
- package/dist/serveCommand-BmvEQCMS.js +2 -0
- package/dist/{serveCommand-B6TATyCj.js → serveCommand-Dqb9Ku1-.js} +657 -657
- package/dist/serveEntry.js +1 -1
- package/dist/{start-BNuTWdRd.js → start-BA7txHhY.js} +1 -1
- package/dist/{start-ft_KzFTd.js → start-dkNYKtgQ.js} +342 -318
- package/dist/startEntry.js +1 -1
- package/dist/updateCommand-BauSVxPp.js +2 -0
- package/dist/{updateCommand-CHBmCB17.js → updateCommand-eoGpZr3E.js} +1 -1
- package/dist/webDev-CBbKs4dZ.js +2 -0
- package/dist/{webDev-CTpSY-e_.js → webDev-bybjZA0o.js} +240 -186
- package/dist/{webhooksCommand-BVvOtZ1B.js → webhooksCommand-DubZWNOx.js} +1 -1
- package/package.json +29 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/authentication.md +13 -4
- package/templates/agent-docs/data.md +43 -0
- package/templates/agent-docs/routing.md +40 -0
- package/templates/agent-docs/whats-new.md +91 -157
- package/templates/apps/api-ai/package.json +7 -7
- package/templates/apps/api-auth/package.json +8 -8
- package/templates/apps/api-backend/package.json +7 -7
- package/templates/apps/api-backend-deactivation/package.json +7 -7
- package/templates/apps/api-backend-mail/package.json +8 -8
- package/templates/apps/api-backend-mariadb/package.json +9 -9
- package/templates/apps/api-backend-sqlite/package.json +8 -8
- package/templates/apps/api-backend-storage/package.json +8 -8
- package/templates/apps/api-cms/package.json +10 -10
- package/templates/apps/api-collab/package.json +8 -8
- package/templates/apps/api-data-advanced/package.json +8 -8
- package/templates/apps/api-durable/package.json +8 -8
- package/templates/apps/api-durable/startup/warm.startup.tsx +16 -2
- package/templates/apps/api-durable/tests/orders.place.test.ts +17 -4
- package/templates/apps/api-feature-flags/package.json +9 -9
- package/templates/apps/api-governance/package.json +8 -8
- package/templates/apps/api-kv/package.json +8 -8
- package/templates/apps/api-moderation/package.json +8 -8
- package/templates/apps/api-observability/package.json +8 -8
- package/templates/apps/api-ratelimit/package.json +8 -8
- package/templates/apps/api-rbac/package.json +8 -8
- package/templates/apps/api-rest/package.json +7 -7
- package/templates/apps/api-saas/package.json +11 -11
- package/templates/apps/api-saas-starter/package.json +10 -10
- package/templates/apps/api-search/package.json +8 -8
- package/templates/apps/api-status/package.json +8 -8
- package/templates/apps/api-versioning/package.json +8 -8
- package/templates/apps/api-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +6 -6
- package/templates/apps/changelog/src/pages/[slug]/page.test.tsx +8 -1
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +9 -9
- package/templates/apps/frontend-auth/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- package/templates/apps/frontend-cms/package.json +9 -9
- package/templates/apps/frontend-collab/package.json +10 -10
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +7 -7
- package/templates/apps/frontend-docs/package.json +7 -7
- package/templates/apps/frontend-i18n/package.json +6 -6
- package/templates/apps/frontend-landing/package.json +7 -7
- package/templates/apps/frontend-portal/package.json +8 -8
- package/templates/apps/frontend-saas/package.json +8 -8
- package/templates/apps/frontend-spa/package.json +7 -7
- package/templates/apps/frontend-ssr/package.json +7 -7
- package/templates/apps/frontend-ssr-api/package.json +8 -8
- package/templates/apps/frontend-static-blog/package.json +6 -6
- package/templates/apps/frontend-status/package.json +8 -8
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/agentsMd-BFCXh2gl.js +0 -2
- package/dist/apiBuild-2GvK8CUB.js +0 -2
- package/dist/doctorCommand-CVXfRrng.js +0 -2
- package/dist/frameworkTableAssembly-YyVe32Cb.js +0 -2
- package/dist/serveCommand-CNR0gI9V.js +0 -2
- package/dist/updateCommand-6FMU2klq.js +0 -2
- package/dist/webDev-id3I5PvG.js +0 -2
|
@@ -222,7 +222,7 @@ createVerifier({ secret: [process.env.WEBHOOK_SECRET, process.env.WEBHOOK_SECRET
|
|
|
222
222
|
...t === void 0 ? {} : { payload: t }
|
|
223
223
|
};
|
|
224
224
|
}, S = u({ scope: "voltro:webhooks" }), C = ["--out", "--name"], w = async (e) => {
|
|
225
|
-
let { walk: t, loadDiscovered: n } = await import("./dev-
|
|
225
|
+
let { walk: t, loadDiscovered: n } = await import("./dev-D8JSKlBM.js"), { outgoingFromEvents: r } = await import("./webhookDiscovery-il9ti-HE.js");
|
|
226
226
|
return r((await n(await t(e))).events.map((e) => ({
|
|
227
227
|
file: e.file,
|
|
228
228
|
descriptor: e.descriptor
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "The `voltro` CLI — dev server, codegen, migrations, project scaffolding, agent-docs seeding, and production serve.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"voltro",
|
|
@@ -610,6 +610,18 @@
|
|
|
610
610
|
"title": "@voltro/plugin-rbac/web removed — the UI gate lives in @voltro/client",
|
|
611
611
|
"kind": "transform"
|
|
612
612
|
},
|
|
613
|
+
{
|
|
614
|
+
"version": "0.40.0",
|
|
615
|
+
"id": "0.40.0/01_cold-start-failure-is-its-own-state",
|
|
616
|
+
"title": "a failed cold start is `failed: true`, not `loading: true`",
|
|
617
|
+
"kind": "manual"
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"version": "0.40.0",
|
|
621
|
+
"id": "0.40.0/02_rejected-credential-widens-guard-results",
|
|
622
|
+
"title": "a rejected credential answers `Unauthenticated`, widening three guard results",
|
|
623
|
+
"kind": "manual"
|
|
624
|
+
},
|
|
613
625
|
{
|
|
614
626
|
"version": "0.5.0",
|
|
615
627
|
"id": "0.5.0/01_one-terminal-exactly-one",
|
|
@@ -697,22 +709,22 @@
|
|
|
697
709
|
"@effect/platform-node": "^0.108.0",
|
|
698
710
|
"@effect/sql": "^0.52.0",
|
|
699
711
|
"@effect/workflow": "^0.19.0",
|
|
700
|
-
"@voltro/ai": "0.
|
|
701
|
-
"@voltro/cache": "0.
|
|
702
|
-
"@voltro/data-transfer": "0.
|
|
703
|
-
"@voltro/database": "0.
|
|
704
|
-
"@voltro/env": "0.
|
|
705
|
-
"@voltro/kv": "0.
|
|
706
|
-
"@voltro/logger": "0.
|
|
707
|
-
"@voltro/plugin-auth": "0.
|
|
708
|
-
"@voltro/plugin-broadcast": "0.
|
|
709
|
-
"@voltro/plugin-mail": "0.
|
|
710
|
-
"@voltro/plugin-storage": "0.
|
|
711
|
-
"@voltro/plugin-webhooks": "0.
|
|
712
|
-
"@voltro/protocol": "0.
|
|
713
|
-
"@voltro/runtime": "0.
|
|
714
|
-
"@voltro/serverless": "0.
|
|
715
|
-
"@voltro/workflow": "0.
|
|
712
|
+
"@voltro/ai": "0.40.0",
|
|
713
|
+
"@voltro/cache": "0.40.0",
|
|
714
|
+
"@voltro/data-transfer": "0.40.0",
|
|
715
|
+
"@voltro/database": "0.40.0",
|
|
716
|
+
"@voltro/env": "0.40.0",
|
|
717
|
+
"@voltro/kv": "0.40.0",
|
|
718
|
+
"@voltro/logger": "0.40.0",
|
|
719
|
+
"@voltro/plugin-auth": "0.40.0",
|
|
720
|
+
"@voltro/plugin-broadcast": "0.40.0",
|
|
721
|
+
"@voltro/plugin-mail": "0.40.0",
|
|
722
|
+
"@voltro/plugin-storage": "0.40.0",
|
|
723
|
+
"@voltro/plugin-webhooks": "0.40.0",
|
|
724
|
+
"@voltro/protocol": "0.40.0",
|
|
725
|
+
"@voltro/runtime": "0.40.0",
|
|
726
|
+
"@voltro/serverless": "0.40.0",
|
|
727
|
+
"@voltro/workflow": "0.40.0",
|
|
716
728
|
"chokidar": "^5.0.0",
|
|
717
729
|
"ioredis": "^5.11.1",
|
|
718
730
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -707,7 +707,7 @@ each plugin's own README.
|
|
|
707
707
|
|
|
708
708
|
| Topic | Open | Summary |
|
|
709
709
|
|---|---|---|
|
|
710
|
-
| **What's new in 0.
|
|
710
|
+
| **What's new in 0.40.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
711
711
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
712
712
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
713
713
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -9,7 +9,7 @@ each plugin's own README.
|
|
|
9
9
|
|
|
10
10
|
| Topic | Open | Summary |
|
|
11
11
|
|---|---|---|
|
|
12
|
-
| **What's new in 0.
|
|
12
|
+
| **What's new in 0.40.0** | `node_modules/@voltro/cli/templates/agent-docs/whats-new.md` | Everything that changed in this version. Read it before hand-rolling something the framework may now ship. |
|
|
13
13
|
| AI | `node_modules/@voltro/cli/templates/agent-docs/ai.md` | How Voltro treats AI — agents, tools, streaming, RAG — all primitives over the same WebSocket as the rest of the framework. |
|
|
14
14
|
| Authentication | `node_modules/@voltro/cli/templates/agent-docs/authentication.md` | How @voltro/plugin-auth wires password + session-cookie auth across api + web, plus the pluggable identity-strategy protocol. |
|
|
15
15
|
| Caching | `node_modules/@voltro/cli/templates/agent-docs/caching.md` | Voltro's caching layer (@voltro/cache) — an always-on memory default, swappable Redis-compatible backends, a low-level wrap primitive, and automatic query-result invalidation. |
|
|
@@ -2143,10 +2143,19 @@ setTupleSource((req) =>
|
|
|
2143
2143
|
loadResourceTuples(store, req.subjectId, req.resourceType, req.resourceId))
|
|
2144
2144
|
```
|
|
2145
2145
|
|
|
2146
|
-
`voltro dev` / `voltro serve` register
|
|
2147
|
-
`_voltro_rebac_tuples
|
|
2148
|
-
in your own tables
|
|
2149
|
-
copy it into a framework table to authorize
|
|
2146
|
+
`voltro dev` / `voltro serve` register this default for you, reading
|
|
2147
|
+
`_voltro_rebac_tuples` — **but only if you registered nothing**. Register your
|
|
2148
|
+
own when your relationships already live in your own tables: a `teamMembers` row
|
|
2149
|
+
is a relation; you should not have to copy it into a framework table to authorize
|
|
2150
|
+
against it. Yours wins, wherever you register it (`app.config.ts` or a
|
|
2151
|
+
`*.startup.tsx`), and the boot says so:
|
|
2152
|
+
|
|
2153
|
+
```
|
|
2154
|
+
policy guards: using the app-registered tuple source
|
|
2155
|
+
```
|
|
2156
|
+
|
|
2157
|
+
That line is worth knowing, because its absence is the diagnosis when your own
|
|
2158
|
+
source is not being consulted.
|
|
2150
2159
|
|
|
2151
2160
|
**Every unanswerable case denies.** No tuple source registered, no policy for
|
|
2152
2161
|
that `resourceType`, an input that doesn't identify a resource, a tuple source
|
|
@@ -1728,6 +1728,33 @@ const { data } = useSubscription(
|
|
|
1728
1728
|
|
|
1729
1729
|
While skipped, no WebSocket subscription opens and `data` stays `undefined`.
|
|
1730
1730
|
|
|
1731
|
+
### A failed cold start is `failed`, not `loading`
|
|
1732
|
+
|
|
1733
|
+
If the first snapshot never arrives because the subscription ERRORED, the state
|
|
1734
|
+
is **`failed: true`, `loading: false`, `data: undefined`** — nothing is in
|
|
1735
|
+
flight and nothing more is coming, so "it is loading" would be a false
|
|
1736
|
+
statement. `error` carries the cause.
|
|
1737
|
+
|
|
1738
|
+
```tsx
|
|
1739
|
+
const s = useSubscription<Team[]>('app', 'teams.list')
|
|
1740
|
+
|
|
1741
|
+
if (s.loading) return <Skeleton/>
|
|
1742
|
+
if (s.failed) return <RetryPanel error={s.error}/>
|
|
1743
|
+
return <TeamsTable teams={s.data}/>
|
|
1744
|
+
```
|
|
1745
|
+
|
|
1746
|
+
`failed` is a positive check on purpose. The state used to be `loading: true`
|
|
1747
|
+
with `error` set, and the escape hatch was reading that second field — which the
|
|
1748
|
+
natural shape of a wrapper (`{ data, loading }` passed through) drops. **If you
|
|
1749
|
+
wrap this state, carry `failed` with it**, or your callers inherit an infinite
|
|
1750
|
+
skeleton through your hook.
|
|
1751
|
+
|
|
1752
|
+
Two things this does NOT cover. A failure AFTER the first snapshot leaves the
|
|
1753
|
+
good data on screen and sets `error` — replacing working rows with an error
|
|
1754
|
+
because the socket hiccuped is worse than the hiccup. And the failed state is
|
|
1755
|
+
terminal for one TRANSPORT, not forever: a reconnect discards the error and
|
|
1756
|
+
re-subscribes, so the entry returns to loading on its own.
|
|
1757
|
+
|
|
1731
1758
|
### Skipped is `idle`, not `loading`
|
|
1732
1759
|
|
|
1733
1760
|
A skipped subscription reports **`idle: true`, `loading: false`**. The two are
|
|
@@ -4711,6 +4738,22 @@ To distinguish "we know about this" from "this surprised us":
|
|
|
4711
4738
|
| `throw new Error('oops')` | Surfaces as a defect — full log + trace, generic failure to client |
|
|
4712
4739
|
| Unexpected exception from a library | Same — caught, logged, generic failure |
|
|
4713
4740
|
|
|
4741
|
+
## What the framework merges into your `error:` union
|
|
4742
|
+
|
|
4743
|
+
You do not declare the errors the framework itself can raise for a procedure —
|
|
4744
|
+
they are unioned into the wire contract for you, and only when the procedure can
|
|
4745
|
+
actually produce them:
|
|
4746
|
+
|
|
4747
|
+
| Merged | Into | When |
|
|
4748
|
+
|---|---|---|
|
|
4749
|
+
| `ScopeError` | query · mutation · action · event | the procedure declares a real `guards:` entry. NOT for `openAccess:` — a procedure advertising a denial it cannot produce is what makes an error union stop meaning anything |
|
|
4750
|
+
| `Unauthenticated` | query · mutation · action · event | the same condition. A guard can refuse for TWO reasons and they mean different things: the caller is known and lacks the scope (`ScopeError`), or they presented a credential that was REJECTED and so arrived anonymous (`Unauthenticated`). Without the second, an expired session reads as a permissions problem |
|
|
4751
|
+
| `BusinessRuleViolation` | mutation | always. A cross-table `rule()` on any table the mutation writes can fail it, and the descriptor cannot know which tables carry rules |
|
|
4752
|
+
| `ApprovalRequired` · `ApprovalExpired` · `ApprovalUnavailable` | mutation · action | the procedure declares `requiresApproval:` |
|
|
4753
|
+
|
|
4754
|
+
So a guarded mutation does **not** need `ScopeError` in its own `error:`. If you
|
|
4755
|
+
declared it anyway, that is harmless — the union is the same either way.
|
|
4756
|
+
|
|
4714
4757
|
## Framework-shipped error variants
|
|
4715
4758
|
|
|
4716
4759
|
`@voltro/protocol` exports exactly two tagged errors. The rest of your typed errors are ones you declare yourself (above) or ones a plugin / the runtime contributes.
|
|
@@ -1150,6 +1150,46 @@ Auth is resolved by the **api**, never the web app. Two rules follow:
|
|
|
1150
1150
|
|
|
1151
1151
|
So a cookie-mode Supabase app configures `supabaseStrategy({ cookieName: 'sb-<ref>-auth-token' })` on the **api**; the web loader's `ctx.query` then authenticates for free. See [Supabase Auth](/docs/plugins/auth-supabase).
|
|
1152
1152
|
|
|
1153
|
+
### Renewing an EXPIRED session — `middleware.ts`
|
|
1154
|
+
|
|
1155
|
+
The rules above assume the cookie is still valid. When it is not — a token older
|
|
1156
|
+
than the IdP's lifetime, which for a 1-hour token is practically every first
|
|
1157
|
+
page view of the day — the api resolves the caller to anonymous and every loader
|
|
1158
|
+
and `preload` on the page fails.
|
|
1159
|
+
|
|
1160
|
+
You cannot fix that in a loader. `ctx.query` and every `preload` entry are bound
|
|
1161
|
+
from ONE cookie string **before any loader runs**, so a layout loader that
|
|
1162
|
+
renews the session cannot reach them. `middleware.ts` at the web app root runs
|
|
1163
|
+
earlier than both:
|
|
1164
|
+
|
|
1165
|
+
```ts
|
|
1166
|
+
// middleware.ts — server-only. NOT app.config.ts, which is imported into the
|
|
1167
|
+
// client bundle whenever an api declares `authHeaders`.
|
|
1168
|
+
export default async (req) => {
|
|
1169
|
+
const fresh = await refreshSession(req.cookies['sb-session'])
|
|
1170
|
+
if (!fresh) return
|
|
1171
|
+
return {
|
|
1172
|
+
headers: { authorization: `Bearer ${fresh.accessToken}` },
|
|
1173
|
+
setCookies: [{ name: 'sb-session', value: fresh.cookie, maxAge: 3600 }],
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
**Write the cookie back.** An IdP that rotates refresh tokens (Supabase does, and
|
|
1179
|
+
detects reuse) will invalidate the session if you renew server-side and leave the
|
|
1180
|
+
browser holding the consumed one. `setCookies` is not an optimisation.
|
|
1181
|
+
|
|
1182
|
+
**It cannot redirect or refuse a request**, deliberately: authorization belongs
|
|
1183
|
+
on the api, which is the only thing that sees the data, and a web-side hook that
|
|
1184
|
+
could refuse would be a second authorization layer beside the real one. For a
|
|
1185
|
+
login redirect, throw `RedirectError` from the loader.
|
|
1186
|
+
|
|
1187
|
+
Headers you return are merged over the request's, and only auth-shaped ones
|
|
1188
|
+
(`authorization`, `x-tenant`, `x-voltro-*`) are forwarded to the api. Cookies
|
|
1189
|
+
default to `HttpOnly`, `Path=/`, `SameSite=lax`. The file is loaded once per
|
|
1190
|
+
boot; if it throws, the request fails rather than rendering with the credential
|
|
1191
|
+
you asked to replace.
|
|
1192
|
+
|
|
1153
1193
|
## Errors from loaders
|
|
1154
1194
|
|
|
1155
1195
|
If the loader throws, the framework:
|