@voltro/cli 0.27.0 → 0.28.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 +235 -0
- package/dist/apiBuild-DgBS9ayv.js +2 -0
- package/dist/{apiBuild-D22_EpoR.js → apiBuild-eUM32r1u.js} +2 -2
- package/dist/bin.js +2 -2
- package/dist/{commands-jBX8no1I.js → commands-CSkrUI1h.js} +2430 -2238
- package/dist/{dbCommand-uuNCrFAb.js → dbCommand-CpYgmSw4.js} +1 -1
- package/dist/dbCommand-DvguqlzF.js +2 -0
- package/dist/{dev-DcbIJrWg.js → dev-CEZwJhmb.js} +2774 -2548
- package/dist/dev-DlBWWnJQ.js +3 -0
- package/dist/index.js +1 -1
- package/dist/{seedRunner-D6eu-u5U.js → seedRunner-Bqxgp7HZ.js} +60 -59
- package/dist/serveCommand-ZTn-dPFa.js +1425 -0
- package/dist/serveEntry.js +2 -2
- package/package.json +17 -17
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/deployment.md +56 -0
- package/templates/agent-docs/testing.md +42 -0
- package/templates/agent-docs/whats-new.md +172 -119
- 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-storage/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-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-search/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/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +8 -8
- package/templates/apps/frontend-app/package.json +8 -8
- package/templates/apps/frontend-blank/package.json +7 -7
- 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-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/dist/apiBuild-BrjrVJJh.js +0 -2
- package/dist/dbCommand-DrzXimKf.js +0 -2
- package/dist/dev-DNkso403.js +0 -3
- package/dist/serveCommand-DfkisVWP.js +0 -1310
package/dist/serveEntry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Z as e } from "./inspectMetrics-BU90mvJN.js";
|
|
2
|
-
import { c as t } from "./seedRunner-
|
|
2
|
+
import { c as t } from "./seedRunner-Bqxgp7HZ.js";
|
|
3
3
|
import { r as n } from "./appModuleLoader-C9r9mxZt.js";
|
|
4
|
-
import { t as r } from "./serveCommand-
|
|
4
|
+
import { t as r } from "./serveCommand-ZTn-dPFa.js";
|
|
5
5
|
export { e as loadDotEnv, n as registerAppModules, t as registerDriver, r as runServe };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.28.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",
|
|
@@ -62,22 +62,22 @@
|
|
|
62
62
|
"@effect/platform-node": "^0.108.0",
|
|
63
63
|
"@effect/sql": "^0.52.0",
|
|
64
64
|
"@effect/workflow": "^0.19.0",
|
|
65
|
-
"@voltro/ai": "0.
|
|
66
|
-
"@voltro/cache": "0.
|
|
67
|
-
"@voltro/data-transfer": "0.
|
|
68
|
-
"@voltro/database": "0.
|
|
69
|
-
"@voltro/env": "0.
|
|
70
|
-
"@voltro/kv": "0.
|
|
71
|
-
"@voltro/logger": "0.
|
|
72
|
-
"@voltro/plugin-auth": "0.
|
|
73
|
-
"@voltro/plugin-broadcast": "0.
|
|
74
|
-
"@voltro/plugin-mail": "0.
|
|
75
|
-
"@voltro/plugin-storage": "0.
|
|
76
|
-
"@voltro/plugin-webhooks": "0.
|
|
77
|
-
"@voltro/protocol": "0.
|
|
78
|
-
"@voltro/runtime": "0.
|
|
79
|
-
"@voltro/serverless": "0.
|
|
80
|
-
"@voltro/workflow": "0.
|
|
65
|
+
"@voltro/ai": "0.28.0",
|
|
66
|
+
"@voltro/cache": "0.28.0",
|
|
67
|
+
"@voltro/data-transfer": "0.28.0",
|
|
68
|
+
"@voltro/database": "0.28.0",
|
|
69
|
+
"@voltro/env": "0.28.0",
|
|
70
|
+
"@voltro/kv": "0.28.0",
|
|
71
|
+
"@voltro/logger": "0.28.0",
|
|
72
|
+
"@voltro/plugin-auth": "0.28.0",
|
|
73
|
+
"@voltro/plugin-broadcast": "0.28.0",
|
|
74
|
+
"@voltro/plugin-mail": "0.28.0",
|
|
75
|
+
"@voltro/plugin-storage": "0.28.0",
|
|
76
|
+
"@voltro/plugin-webhooks": "0.28.0",
|
|
77
|
+
"@voltro/protocol": "0.28.0",
|
|
78
|
+
"@voltro/runtime": "0.28.0",
|
|
79
|
+
"@voltro/serverless": "0.28.0",
|
|
80
|
+
"@voltro/workflow": "0.28.0",
|
|
81
81
|
"chokidar": "^5.0.0",
|
|
82
82
|
"ioredis": "^5.11.1",
|
|
83
83
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -602,7 +602,7 @@ each plugin's own README.
|
|
|
602
602
|
|
|
603
603
|
| Topic | Open | Summary |
|
|
604
604
|
|---|---|---|
|
|
605
|
-
| **What's new in 0.
|
|
605
|
+
| **What's new in 0.27.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. |
|
|
606
606
|
| 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. |
|
|
607
607
|
| 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. |
|
|
608
608
|
| 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.27.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. |
|
|
@@ -1150,6 +1150,59 @@ KV_BACKEND=redis
|
|
|
1150
1150
|
|
|
1151
1151
|
Schedules and aggregates auto-coordinate via an advisory lock on SQL stores — no extra config to keep them from double-firing across replicas.
|
|
1152
1152
|
|
|
1153
|
+
### The prerequisites you learn at the SECOND pod
|
|
1154
|
+
|
|
1155
|
+
Every item below is invisible on one replica and breaks on two. They are
|
|
1156
|
+
collected here because an operator reported each of them separately, each found
|
|
1157
|
+
the same way: the first pod proved the configuration worked.
|
|
1158
|
+
|
|
1159
|
+
**The connection pool multiplies, the database limit does not.**
|
|
1160
|
+
|
|
1161
|
+
```sh
|
|
1162
|
+
DB_MAX_CONNECTIONS=10 # per replica — the fleet opens up to this × replicaCount
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
The framework opens ONE pool per process. At 4 replicas a pool of 10 is 40
|
|
1166
|
+
connections against a database that still allows whatever it allowed before you
|
|
1167
|
+
scaled. An operator's second pod died on `Connection timed out` for exactly
|
|
1168
|
+
this. `voltro serve` now prints the number and the arithmetic at boot:
|
|
1169
|
+
|
|
1170
|
+
```
|
|
1171
|
+
db pool: max=10 per replica (DB_MAX_CONNECTIONS) × 4 replicas = up to 40 connections.
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
Set `REPLICA_COUNT` from your deployment (Helm: `{{ .Values.replicaCount }}`) and
|
|
1175
|
+
the line does the multiplication for you; without it the line still names the
|
|
1176
|
+
formula. `voltro dev` deliberately does not print it — one process, no replicas.
|
|
1177
|
+
|
|
1178
|
+
**`POD_IP` is each replica's identity, not only a workflow setting.**
|
|
1179
|
+
|
|
1180
|
+
```yaml
|
|
1181
|
+
env:
|
|
1182
|
+
- name: POD_IP
|
|
1183
|
+
valueFrom:
|
|
1184
|
+
fieldRef:
|
|
1185
|
+
fieldPath: status.podIP
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
Without it every replica registers under the same host, so they are one runner
|
|
1189
|
+
as far as the cluster is concerned. The boot warning for it fires only on SQL
|
|
1190
|
+
cluster storage, so a deployment that has not adopted durable workflows yet gets
|
|
1191
|
+
no signal at all — inject it as a matter of course.
|
|
1192
|
+
|
|
1193
|
+
**Derive the broadcast namespace from something that cannot be forgotten.**
|
|
1194
|
+
|
|
1195
|
+
```yaml
|
|
1196
|
+
- name: VOLTRO_BROADCAST_NAMESPACE
|
|
1197
|
+
value: {{ .Release.Namespace }}
|
|
1198
|
+
```
|
|
1199
|
+
|
|
1200
|
+
Staging and production of the same app share a name, code and fingerprint, so
|
|
1201
|
+
the auto-derived namespace does NOT separate them — only this variable does. An
|
|
1202
|
+
operator's own guidance, and better than ours was: a value taken from the
|
|
1203
|
+
release namespace cannot be left out of one environment's config file, because
|
|
1204
|
+
there is no file to forget.
|
|
1205
|
+
|
|
1153
1206
|
### Workflow failover across replicas
|
|
1154
1207
|
|
|
1155
1208
|
On a **SQL store** (postgres / mysql / mariadb / mssql), durable workflows survive a replica crash: completed `step({...})` activities are checkpointed in the cluster journal, so when a replica dies mid-run, a **surviving replica takes over the run and continues it from the last completed step** — it replays the completed steps rather than re-running them. (On sqlite the engine is single-process — durable within one replica, no cross-replica failover.) Two requirements:
|
|
@@ -1181,6 +1234,9 @@ Lower the lease for **faster failover**, at the cost of **false-positive reclaim
|
|
|
1181
1234
|
- [ ] `VOLTRO_LOG_FORMAT=json`; `sentryPlugin()` + `SENTRY_DSN` for errors
|
|
1182
1235
|
- [ ] `terminationGracePeriodSeconds` generous for graceful drain; `VOLTRO_SHUTDOWN_GRACE_MS` set just under it (minus the preStop sleep)
|
|
1183
1236
|
- [ ] `CACHE_BACKEND` / `KV_BACKEND` + a cross-replica change bus when running >1 replica
|
|
1237
|
+
- [ ] `DB_MAX_CONNECTIONS` set so `pool × replicaCount` fits your database's limit — read the `db pool:` boot line before raising `replicaCount`
|
|
1238
|
+
- [ ] `POD_IP` injected via the downward API on EVERY multi-replica deployment, not only for durable workflows
|
|
1239
|
+
- [ ] `VOLTRO_BROADCAST_NAMESPACE` derived from the release namespace — staging and production do not separate themselves
|
|
1184
1240
|
- [ ] For durable workflows on >1 replica: SQL store + `POD_IP` injected; tune `VOLTRO_WORKFLOW_FAILOVER_LEASE` if a 35s takeover is too slow; step side effects idempotent
|
|
1185
1241
|
|
|
1186
1242
|
|
|
@@ -372,6 +372,48 @@ What it fills and what it leaves alone:
|
|
|
372
372
|
|
|
373
373
|
There is no flag to turn the validation off — a test store that accepts rows production rejects is a fake testing itself. `fixtureRow` is a runtime filler for the loose `store.insert(name, row)` path. For **compile-time** payload typing (a missing required column caught as a type error at the call), use [`insertRow` / `upsertRow`](/docs/data/mutations) from `@voltro/database`, which check against `InferInsertRow<T>`.
|
|
374
374
|
|
|
375
|
+
## Subscribers — `makeSubscribeContext` + the change constructors
|
|
376
|
+
|
|
377
|
+
A `*.subscribe.ts` handler does not receive an `AppContext`. It receives a
|
|
378
|
+
change EVENT and a `SubscribeContext`, and both have constructors:
|
|
379
|
+
|
|
380
|
+
```ts
|
|
381
|
+
import { changeInsert, changeUpdate, changeDelete, changeSoftDelete, makeSubscribeContext, makeTestContext } from '@voltro/testing'
|
|
382
|
+
import subscriber from '../src/attendance.subscribe'
|
|
383
|
+
|
|
384
|
+
const app = makeTestContext({ store: { attendance: [{ id: 'a1', employeeId: 'e1' }] } })
|
|
385
|
+
const ctx = makeSubscribeContext({ id: 'attendance', store: app.store })
|
|
386
|
+
|
|
387
|
+
await subscriber.handler(changeUpdate('attendance', { id: 'a1', state: 'in' }, { id: 'a1', state: 'out' }), ctx)
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Build the event with a constructor, not with an object literal.** The
|
|
391
|
+
constructors put the semantics in the name, which is the half a literal cannot
|
|
392
|
+
give you:
|
|
393
|
+
|
|
394
|
+
| | `op` | `old` | `new` |
|
|
395
|
+
| --- | --- | --- | --- |
|
|
396
|
+
| `changeInsert(t, row)` | `insert` | `null` | the row |
|
|
397
|
+
| `changeUpdate(t, before, after)` | `update` | before | after |
|
|
398
|
+
| `changeDelete(t, row)` | `delete` | the row | `null` |
|
|
399
|
+
| `changeSoftDelete(t, row)` | **`update`** | `deletedAt: null` | `deletedAt` set |
|
|
400
|
+
|
|
401
|
+
`changeSoftDelete` is the reason this exists. There is no `op: 'softDelete'` and
|
|
402
|
+
there never will be — a soft delete is an ordinary update that sets `deletedAt`
|
|
403
|
+
— so a test author who does not know that writes a delete, and the test passes
|
|
404
|
+
against a stream the framework never emits. We shipped exactly that defect: a
|
|
405
|
+
feature that keys off soft deletes was inert in production while its own tests
|
|
406
|
+
were green, because they asserted against an event shape that does not exist.
|
|
407
|
+
|
|
408
|
+
`ctx.store` has **no default and throws when touched**. Pass
|
|
409
|
+
`makeTestContext().store` so the subscriber and the code under test share one; a
|
|
410
|
+
silent empty store would let a subscriber reading the wrong table pass its test,
|
|
411
|
+
which is the same silent-nothing the constructors exist to remove.
|
|
412
|
+
|
|
413
|
+
`ctx.publish` is absent unless you pass one, mirroring the real context — where
|
|
414
|
+
it is optional precisely so that reaching for it in an app that declares no
|
|
415
|
+
event is a type error.
|
|
416
|
+
|
|
375
417
|
## Subject + tenant re-scoping
|
|
376
418
|
|
|
377
419
|
`withSubject` and `withTenant` re-scope to a different principal for one block, sharing the **same** underlying data — so cross-subject reads exercise real tenant scoping, not a closure stub. This is how you prove isolation: write as one tenant, then assert another tenant can't see the row.
|