@voltro/cli 0.59.0 → 0.60.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 +58 -0
- package/dist/bin.js +1 -1
- package/dist/{build-uRMZrT8z.js → build-BxAsLzyU.js} +14 -10
- package/dist/{codemodRunner-kNnh1I7_.js → codemodRunner-ClUqkhvR.js} +86 -37
- package/dist/{commands-cu34ENUT.js → commands-Ro4hYBHD.js} +7 -7
- package/dist/{dashboardCommand-gG1y4PFG.js → dashboardCommand-t8Qsebjr.js} +1 -1
- package/dist/{evolveCommand-8CuFBlbQ.js → evolveCommand-CThb0EZZ.js} +1 -1
- package/dist/index.js +1 -1
- package/dist/{infoCommand-D02A4WI2.js → infoCommand-a0WkKcUY.js} +1 -1
- package/dist/{start-C75w6ftA.js → start-BhoDQ25C.js} +1 -1
- package/dist/{start-DNtIlBcn.js → start-CcdPRG8L.js} +418 -367
- package/dist/startEntry.js +1 -1
- package/dist/{updateCommand-Bw3mCUDT.js → updateCommand-D9avpQFT.js} +1 -1
- package/dist/updateCommand-QMOirvXC.js +2 -0
- package/package.json +25 -19
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/plugins/sentry.md +93 -6
- package/templates/agent-docs/whats-new.md +29 -26
- package/templates/apps/api-ai/package.json +6 -6
- 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 +9 -9
- 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-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-row-history/package.json +8 -8
- 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-webhooks/package.json +9 -9
- package/templates/apps/changelog/package.json +7 -7
- package/templates/apps/edge-functions/package.json +2 -2
- package/templates/apps/frontend-admin/package.json +7 -7
- package/templates/apps/frontend-app/package.json +8 -8
- package/templates/apps/frontend-auth/package.json +7 -7
- package/templates/apps/frontend-blank/package.json +6 -6
- package/templates/apps/frontend-cms/package.json +8 -8
- package/templates/apps/frontend-collab/package.json +9 -9
- package/templates/apps/frontend-contact/package.json +7 -7
- package/templates/apps/frontend-dashboard/package.json +6 -6
- package/templates/apps/frontend-docs/package.json +8 -8
- 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 +7 -7
- package/templates/apps/frontend-saas/package.json +7 -7
- package/templates/apps/frontend-spa/package.json +6 -6
- package/templates/apps/frontend-ssr/package.json +6 -6
- package/templates/apps/frontend-ssr-api/package.json +7 -7
- package/templates/apps/frontend-static-blog/package.json +8 -8
- package/templates/apps/frontend-status/package.json +7 -7
- package/templates/apps/mobile-app/package.json +4 -4
- package/dist/updateCommand-inInBIAh.js +0 -2
package/dist/startEntry.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e, r as t, t as n } from "./codemodRunner-
|
|
1
|
+
import { n as e, r as t, t as n } from "./codemodRunner-ClUqkhvR.js";
|
|
2
2
|
import { basename as r, dirname as i, join as a, relative as o, resolve as s } from "node:path";
|
|
3
3
|
import { existsSync as c, readFileSync as l, readdirSync as u, statSync as d, writeFileSync as f } from "node:fs";
|
|
4
4
|
import { totalmem as p } from "node:os";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voltro/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.60.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",
|
|
@@ -892,6 +892,12 @@
|
|
|
892
892
|
"title": "UiStrings gained a required `connectAccount` section",
|
|
893
893
|
"kind": "manual"
|
|
894
894
|
},
|
|
895
|
+
{
|
|
896
|
+
"version": "0.60.0",
|
|
897
|
+
"id": "0.60.0/01_declared_failures_are_not_incidents",
|
|
898
|
+
"title": "Sentry no longer reports declared failures by default",
|
|
899
|
+
"kind": "manual"
|
|
900
|
+
},
|
|
895
901
|
{
|
|
896
902
|
"version": "0.7.0",
|
|
897
903
|
"id": "0.7.0/01_row-filter-load-failure",
|
|
@@ -938,24 +944,24 @@
|
|
|
938
944
|
"@effect/platform-node": "^0.108.0",
|
|
939
945
|
"@effect/sql": "^0.52.0",
|
|
940
946
|
"@effect/workflow": "^0.19.0",
|
|
941
|
-
"@voltro/ai": "0.
|
|
942
|
-
"@voltro/cache": "0.
|
|
943
|
-
"@voltro/client": "0.
|
|
944
|
-
"@voltro/content": "0.
|
|
945
|
-
"@voltro/data-transfer": "0.
|
|
946
|
-
"@voltro/database": "0.
|
|
947
|
-
"@voltro/env": "0.
|
|
948
|
-
"@voltro/kv": "0.
|
|
949
|
-
"@voltro/logger": "0.
|
|
950
|
-
"@voltro/plugin-auth": "0.
|
|
951
|
-
"@voltro/plugin-broadcast": "0.
|
|
952
|
-
"@voltro/plugin-mail": "0.
|
|
953
|
-
"@voltro/plugin-storage": "0.
|
|
954
|
-
"@voltro/plugin-webhooks": "0.
|
|
955
|
-
"@voltro/protocol": "0.
|
|
956
|
-
"@voltro/runtime": "0.
|
|
957
|
-
"@voltro/serverless": "0.
|
|
958
|
-
"@voltro/workflow": "0.
|
|
947
|
+
"@voltro/ai": "0.60.0",
|
|
948
|
+
"@voltro/cache": "0.60.0",
|
|
949
|
+
"@voltro/client": "0.60.0",
|
|
950
|
+
"@voltro/content": "0.60.0",
|
|
951
|
+
"@voltro/data-transfer": "0.60.0",
|
|
952
|
+
"@voltro/database": "0.60.0",
|
|
953
|
+
"@voltro/env": "0.60.0",
|
|
954
|
+
"@voltro/kv": "0.60.0",
|
|
955
|
+
"@voltro/logger": "0.60.0",
|
|
956
|
+
"@voltro/plugin-auth": "0.60.0",
|
|
957
|
+
"@voltro/plugin-broadcast": "0.60.0",
|
|
958
|
+
"@voltro/plugin-mail": "0.60.0",
|
|
959
|
+
"@voltro/plugin-storage": "0.60.0",
|
|
960
|
+
"@voltro/plugin-webhooks": "0.60.0",
|
|
961
|
+
"@voltro/protocol": "0.60.0",
|
|
962
|
+
"@voltro/runtime": "0.60.0",
|
|
963
|
+
"@voltro/serverless": "0.60.0",
|
|
964
|
+
"@voltro/workflow": "0.60.0",
|
|
959
965
|
"chokidar": "^5.0.0",
|
|
960
966
|
"ioredis": "^5.11.1",
|
|
961
967
|
"tinyglobby": "^0.2.17",
|
package/templates/AGENTS.md
CHANGED
|
@@ -749,7 +749,7 @@ each plugin's own README.
|
|
|
749
749
|
|
|
750
750
|
| Topic | Open | Summary |
|
|
751
751
|
|---|---|---|
|
|
752
|
-
| **What's new in 0.
|
|
752
|
+
| **What's new in 0.60.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. |
|
|
753
753
|
| 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. |
|
|
754
754
|
| 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. |
|
|
755
755
|
| 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.60.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. |
|
|
@@ -243,11 +243,97 @@ Two details worth knowing before the first upload:
|
|
|
243
243
|
store, and it fails with `SSL peer certificate … unable to get local issuer
|
|
244
244
|
certificate`. Add `ca-certificates` to the build stage.
|
|
245
245
|
|
|
246
|
-
**
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
246
|
+
**Debug ids are what make a server frame resolve, and they need their own
|
|
247
|
+
step.** `sentry-cli sourcemaps upload` does **not** write them — `inject` is a
|
|
248
|
+
separate subcommand, and `upload` only uses ids that are already there, falling
|
|
249
|
+
back to matching on the artifact NAME when they are not.
|
|
250
|
+
|
|
251
|
+
That fallback cannot work for a server bundle: the artifact is named from
|
|
252
|
+
`--url-prefix` (`~/chunk-ABC.js`) while the frame carries the absolute path the
|
|
253
|
+
node process loaded (`/workspace/…/serveBundle/chunk-ABC.js`), and nothing
|
|
254
|
+
rewrites either side. Measured downstream before this was fixed: 4300 artifacts
|
|
255
|
+
uploaded, the release finalised, every frame still minified — nothing red, which
|
|
256
|
+
is the failure this page's own warning describes.
|
|
257
|
+
|
|
258
|
+
`voltro build` runs `inject` first now, so the ids are in both the shipped JS and
|
|
259
|
+
the map before anything is uploaded. The URL prefix stays as the fallback for the
|
|
260
|
+
browser bundle, whose frames really are URLs under `~/assets`.
|
|
261
|
+
|
|
262
|
+
## The web server is a SECOND process — and it needs the DSN too
|
|
263
|
+
|
|
264
|
+
A framework app runs two server processes. `voltro serve` is the api, where
|
|
265
|
+
`sentryPlugin()` initialises the SDK through the plugin lifecycle. `voltro start`
|
|
266
|
+
is the **web server** — SSR, loaders, ISR, the revalidation legs — and it has no
|
|
267
|
+
plugin lifecycle at all.
|
|
268
|
+
|
|
269
|
+
It now initialises Sentry itself when `SENTRY_DSN` is set:
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
SENTRY_DSN=… SENTRY_ENVIRONMENT=production SENTRY_RELEASE=1.4.2 voltro start
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
```
|
|
276
|
+
{"level":"info","msg":"sentry active","environment":"production","release":"1.4.2","traces":false,"profiling":false,"process":"web"}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Same line and same field names as the api half, from the same function — one
|
|
280
|
+
vocabulary across both pods, plus `process` so a collector can tell them apart.
|
|
281
|
+
|
|
282
|
+
**Why this was a hole rather than a missing log line.** An SSR shell throw is
|
|
283
|
+
caught, logged, and answered with a 500. No browser ever renders it, so the
|
|
284
|
+
client-side ErrorBoundary bridge below cannot see it either: the error existed
|
|
285
|
+
only in the pod's stdout. Both ends of the integration worked and the middle was
|
|
286
|
+
dark.
|
|
287
|
+
|
|
288
|
+
Three things to know:
|
|
289
|
+
|
|
290
|
+
- **`@voltro/plugin-sentry` must be installed in the WEB app**, not only the api
|
|
291
|
+
— the web server resolves the shared init from it. With a DSN set and the
|
|
292
|
+
package missing, the boot says so and names the command; it does not fail.
|
|
293
|
+
- **`traces` is `false` here, deliberately.** The api half contributes a span
|
|
294
|
+
processor to the framework's tracer. The web server has no tracer, so
|
|
295
|
+
initialising with tracing on would put `traces: true` in a boot line while
|
|
296
|
+
nothing produces a span.
|
|
297
|
+
- **No DSN is silent.** On the api side `sentryPlugin()` in your config is a
|
|
298
|
+
declaration, so an inert one is worth a warning. Here there is no declaration
|
|
299
|
+
to contradict, and a line about an integration you did not ask for is noise.
|
|
300
|
+
|
|
301
|
+
**Re-run `voltro build` after upgrading.** Production `voltro start` loads the
|
|
302
|
+
app's precompiled start bundle, so the web half picks this up when that bundle
|
|
303
|
+
is rebuilt — not from the framework version alone.
|
|
304
|
+
|
|
305
|
+
## What reaches Sentry — a declared failure does not
|
|
306
|
+
|
|
307
|
+
A procedure's `error:` union is a **contract**. Somebody wrote the outcome down,
|
|
308
|
+
the client gets it typed and branches on it, and it describes a state of the
|
|
309
|
+
world: `AccessDeniedError` on a team you are not a member of is the system
|
|
310
|
+
working. A **defect** is the opposite — nobody foresaw it. Sentry is built for
|
|
311
|
+
the second.
|
|
312
|
+
|
|
313
|
+
So a cause that carries only declared failures is **not** reported:
|
|
314
|
+
|
|
315
|
+
```ts
|
|
316
|
+
sentryPlugin() // captureFailures: false — the default
|
|
317
|
+
sentryPlugin({ captureFailures: true }) // report them again
|
|
318
|
+
sentryPlugin({ captureFailures: (e) => (e as { _tag?: string })._tag === 'PaymentDeclined' })
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
- **Defects are always reported**, including a defect that arrived beside a
|
|
322
|
+
failure — the rule is failures-*only*, so one cannot hide the other.
|
|
323
|
+
- **Both halves take the option.** A rejected call is an rpc error on the client
|
|
324
|
+
too, so `initSentryBrowser({ captureFailures })` applies the same rule to
|
|
325
|
+
`rpc.*` events that carry a `_tag`. Set them together, or the api goes quiet
|
|
326
|
+
while the browser keeps filing the same rejection.
|
|
327
|
+
- **Route render failures and `reportClientError` are never filtered.** Nobody
|
|
328
|
+
declared those, which is the whole distinction.
|
|
329
|
+
- **The boot line names it** — `sentry active … captureFailures=false` — because
|
|
330
|
+
a default the framework picks for you is one nobody finds again.
|
|
331
|
+
|
|
332
|
+
Why the default is off: an issue list that fills with the expected is one nobody
|
|
333
|
+
reads. Every invalid form value, every click on a resource without access and
|
|
334
|
+
every call on a deleted row was a `level: error` issue. If Sentry is where you
|
|
335
|
+
see errors at all, `captureFailures: true` is the one-line answer and it is a
|
|
336
|
+
reasonable choice.
|
|
251
337
|
|
|
252
338
|
## Catching errors — what's automatic, what's manual
|
|
253
339
|
|
|
@@ -257,7 +343,8 @@ Once the two halves are wired, most errors are captured **with no per-call code*
|
|
|
257
343
|
|---|---|---|
|
|
258
344
|
| rpc handler throw (mutation/query/action) | ✅ auto | server interceptor → Sentry, trace-correlated + breadcrumbs |
|
|
259
345
|
| Unhandled browser error / promise rejection | ✅ auto | `@sentry/react` global handlers (after `initSentryBrowser`) |
|
|
260
|
-
| **React render error** (any page, incl. catch-all `[...slug]`, `error.tsx` boundary) | ✅ auto | the framework's route ErrorBoundary publishes to a client-error bus → the Sentry web bridge captures it. React swallows boundary-caught errors before `window.onerror`, so this bridge is what makes them reach Sentry — tagged with the route + component stack. |
|
|
346
|
+
| **React render error, in the BROWSER** (any page, incl. catch-all `[...slug]`, `error.tsx` boundary) | ✅ auto | the framework's route ErrorBoundary publishes to a client-error bus → the Sentry web bridge captures it. React swallows boundary-caught errors before `window.onerror`, so this bridge is what makes them reach Sentry — tagged with the route + component stack. |
|
|
347
|
+
| **React render error, during SSR** (shell throw, loader throw, PPR/SWR refresh) | ✅ auto, from the WEB server | a different process and a different path: the render never reaches a browser, so the row above cannot cover it. Captured by the web server's own Sentry (see the section above), tagged `voltro.process=web` and `voltro.stage`. Needs `SENTRY_DSN` on the **web** deployment. |
|
|
261
348
|
| **Loader failure** (page/layout `loader` reject) | ✅ auto | same route bus path |
|
|
262
349
|
| Manual try/catch (event handler, async effect, anywhere) | ✋ one call | `reportClientError(error, context?)` |
|
|
263
350
|
| **Every other server primitive** — REST route (`defineRestRoute`), aggregate, subscriber, schedule, workflow, webhook, startup | ✅ auto | each primitive's error path publishes to the framework's server-error bus → the plugin captures it, tagged `voltro.errorSource` + `voltro.name` (+ traceId for workflows) |
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.60.0
|
|
2
2
|
|
|
3
3
|
Read this FIRST when a task touches an area you have not worked in recently.
|
|
4
4
|
It is the cheapest way to notice that the framework grew the thing you were
|
|
@@ -9,51 +9,54 @@ BREAKING entries name a codemod; run `voltro update` to apply it.
|
|
|
9
9
|
|
|
10
10
|
### ⚠ BREAKING
|
|
11
11
|
|
|
12
|
-
- **@voltro/
|
|
12
|
+
- **@voltro/plugin-sentry** — **A declared failure no longer reaches Sentry by default, and the source-map upload now injects debug ids.** Two separate defects, both found by the same deployment on its first day of real server-side events.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
**1. The contract was being reported as an incident.** The rpc interceptor skipped only clean interrupts; everything else went to `captureException`. So a failure declared in a procedure's `error:` union — the thing the client gets typed and branches on — arrived as `level: error`, `handled: yes`. The first server-side issue a deployment ever received was a person clicking a team they are not a member of.
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
Effect separates a failure from a defect, this framework leans on that split deliberately (a store refusal was made typed so an app could branch on it; an unlookupable conflict key was deliberately left a defect, because it is a broken call rather than a condition in the data), and a descriptor carries it in `error:`. Reporting both as an incident discarded that one layer up.
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
`shouldCapture` now skips a cause that is failures-ONLY. A defect is reported as before, including a defect that travelled beside a failure — the rule is failures-only rather than "any failure present" precisely so one cannot hide the other. `captureFailures: true` restores the old behaviour; a predicate keeps the ones that are signal.
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
**The browser half moved with it**, or the option would have been half-wired: a rejected call is an rpc error on the client too, published to the client error bus and captured by the browser bridge. `initSentryBrowser` takes the same option and applies it to `rpc.*` events carrying a `_tag`. Route render failures and `reportClientError` calls are never filtered — nobody declared those.
|
|
21
21
|
|
|
22
|
-
-
|
|
22
|
+
**2. `sentry-cli sourcemaps upload` does NOT write debug ids.** `inject` is a separate subcommand; `upload` only uses ids that are already present, and falls back to matching on the artifact NAME when they are not. That fallback cannot work for a server bundle: the artifact is named from `--url-prefix` (`~/chunk- ABC.js`) while the frame carries the absolute path the node process loaded, and nothing rewrites either side.
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
Measured downstream: 4300 artifacts uploaded, release finalised, every frame still minified. Nothing was red — the exact shape this code's own header warns about, an upload that matched nothing looking like one that worked. The comment above the uploader asserted the injection happened, which made it a description standing where a check belonged.
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
- **@voltro/ai** — **Speech has a cost path, and a built-in provider name can be taken over.**
|
|
26
|
+
`inject` now runs first, over the same directories, and `sourcemapDebugIds.test.ts` drives the real binary to assert an id lands in both the JS and the map. `--url-prefix` stays as the fallback for the browser bundle, whose frames really are URLs.
|
|
28
27
|
|
|
29
|
-
|
|
28
|
+
The boot line names the new setting (`sentry active … captureFailures=false`), because a default the framework picks for you is one nobody finds again.
|
|
30
29
|
|
|
31
|
-
**`
|
|
30
|
+
**`voltro update` carries you across this** — codemod `0.60.0/01_declared_failures_are_not_incidents`. 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.60.0).
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
### Added
|
|
34
33
|
|
|
35
|
-
|
|
34
|
+
- **@voltro/cli, @voltro/plugin-sentry** — **The web server process now initialises Sentry and reports its own errors.**
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
A framework app runs two server processes. `voltro serve` is the api, where `sentryPlugin()` initialises the SDK through the plugin lifecycle. `voltro start` is the web server — SSR, loaders, ISR, the revalidation legs — and it has no plugin lifecycle, so it had none.
|
|
38
37
|
|
|
39
|
-
|
|
38
|
+
That was not a cosmetic difference in boot output. A web pod legitimately logs less than an api pod, because it has no store, no rpc, no scheduler, no workflows and no plugins. What it also had was **no error reporting**: an SSR shell throw is caught, logged and answered with a 500, so no browser ever renders it and the client-side ErrorBoundary bridge cannot see it either. Both ends of the integration worked and the middle was dark — while the docs' "React render error ✅ auto" row, true of the client path, read as covering all of them.
|
|
40
39
|
|
|
41
|
-
|
|
40
|
+
Set `SENTRY_DSN` on the web deployment and the boot says `sentry active` with the same message and the same field names as the api half, from the same function — `initSentryServer` in `@voltro/plugin-sentry/server`, which the api plugin now calls too. One init, because a copy of `skipOpenTelemetrySetup`, the traces default, the overrides-first spread and the degrade-on-missing-SDK path would have drifted the moment either half gained a case.
|
|
42
41
|
|
|
43
|
-
|
|
42
|
+
Three deliberate asymmetries, each because the two processes are not the same thing:
|
|
43
|
+
|
|
44
|
+
- **`traces: false` on the web side.** The api contributes a span processor to the framework's tracer; the web server has no tracer at all, so tracing on would put `traces: true` in a boot line while nothing produces a span. - **No DSN is SILENT here.** On the api side `sentryPlugin()` is a declaration and an inert one contradicts it. There is no declaration here. - **`@voltro/plugin-sentry` must be installed in the WEB app.** With a DSN set and the package missing, the boot names the command rather than failing — monitoring must never be what stops a deploy.
|
|
44
45
|
|
|
45
|
-
|
|
46
|
+
Measured against a real production `voltro start`, both branches. Note that production `voltro start` loads the app's precompiled start bundle, so a web deployment picks this up when that bundle is rebuilt — the framework version alone is not enough.
|
|
46
47
|
|
|
47
|
-
|
|
48
|
+
### Fixed
|
|
48
49
|
|
|
49
|
-
|
|
50
|
+
- **@voltro/workflow, @voltro/runtime, @voltro/database, @voltro/cli, @voltro/plugin-sentry** — **Six raw writes removed from production log streams — and the guard that was supposed to catch them rewritten, because it was green for two independent reasons.**
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
A pod tail showed `[voltro:workflow] shard-lock coordination: row-based (dialect=mariadb, mode=row)` sitting between JSON records. `@voltro/logger` is what makes a line JSON in a pod and pretty on a TTY; a `process.stderr.write` bypasses that decision at exactly the place nobody looks, because a dev terminal renders both the same.
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
Fixed at the source: the workflow cluster layer (2), `rpcServer`'s computed-cache warning, the subscription outbox's and the RYW store's `warn`/`onError` defaults — those two are not fallbacks, the callers pass nothing, so the default IS the production path — and the migration file discovery's skip notice, which lands in the migrate job's stream.
|
|
55
|
+
|
|
56
|
+
**The guard is the part worth reading.** `prodLogDiscipline.test.ts` existed for this exact class and reported clean, for two reasons that had to be fixed separately:
|
|
54
57
|
|
|
55
|
-
-
|
|
58
|
+
- Its file set was a hand-written list of five. A guard that opts files IN says nothing about any file added after it was written. - Its matcher was LINE-LOCAL, so `process.stderr.write(` on one line and the `` `[tag] `` on the next never matched — 4 of the 9 call sites in the repo are written that way, including one in a file that WAS on the list. The guard had been pointed straight at an offender and called it clean.
|
|
56
59
|
|
|
57
|
-
|
|
60
|
+
It is opt-OUT now: every server-side package's source is scanned, exceptions carry a reason, and a second test fails if an exception's call site disappears — an allowlist entry for code that is gone reads as a rule with a hole in it.
|
|
58
61
|
|
|
59
|
-
|
|
62
|
+
Verified against a real `voltro serve` under `NODE_ENV=production`: 35 records, zero framework lines that are not JSON.
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
"dependencies": {
|
|
13
13
|
"@effect/platform": "^0.97.0",
|
|
14
14
|
"@effect/rpc": "^0.76.0",
|
|
15
|
-
"@voltro/ai": "0.
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/protocol": "0.
|
|
20
|
-
"@voltro/runtime": "0.
|
|
15
|
+
"@voltro/ai": "0.60.0",
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/protocol": "0.60.0",
|
|
20
|
+
"@voltro/runtime": "0.60.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-auth": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
22
|
-
"@voltro/sql-postgres": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/plugin-auth": "0.60.0",
|
|
20
|
+
"@voltro/protocol": "0.60.0",
|
|
21
|
+
"@voltro/runtime": "0.60.0",
|
|
22
|
+
"@voltro/sql-postgres": "0.60.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.60.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -16,16 +16,16 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"@effect/platform": "^0.97.0",
|
|
18
18
|
"@effect/rpc": "^0.76.0",
|
|
19
|
-
"@voltro/cli": "0.
|
|
20
|
-
"@voltro/database": "0.
|
|
21
|
-
"@voltro/env": "0.
|
|
22
|
-
"@voltro/plugin-multitenancy": "0.
|
|
23
|
-
"@voltro/protocol": "0.
|
|
24
|
-
"@voltro/runtime": "0.
|
|
19
|
+
"@voltro/cli": "0.60.0",
|
|
20
|
+
"@voltro/database": "0.60.0",
|
|
21
|
+
"@voltro/env": "0.60.0",
|
|
22
|
+
"@voltro/plugin-multitenancy": "0.60.0",
|
|
23
|
+
"@voltro/protocol": "0.60.0",
|
|
24
|
+
"@voltro/runtime": "0.60.0",
|
|
25
25
|
"effect": "^3.22.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
|
-
"@voltro/testing": "0.
|
|
28
|
+
"@voltro/testing": "0.60.0",
|
|
29
29
|
"typescript": "^6.0.3",
|
|
30
30
|
"@vitest/coverage-v8": "^4.1.10",
|
|
31
31
|
"vitest": "^4.1.10"
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-deactivation": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/plugin-deactivation": "0.60.0",
|
|
20
|
+
"@voltro/protocol": "0.60.0",
|
|
21
|
+
"@voltro/runtime": "0.60.0",
|
|
22
22
|
"effect": "^3.22.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@voltro/testing": "0.
|
|
25
|
+
"@voltro/testing": "0.60.0",
|
|
26
26
|
"typescript": "^6.0.3",
|
|
27
27
|
"@vitest/coverage-v8": "^4.1.10",
|
|
28
28
|
"vitest": "^4.1.10"
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@react-email/components": "^1.0.12",
|
|
15
15
|
"@react-email/render": "^1.4.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-mail": "0.
|
|
20
|
-
"@voltro/plugin-multitenancy": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/plugin-mail": "0.60.0",
|
|
20
|
+
"@voltro/plugin-multitenancy": "0.60.0",
|
|
21
|
+
"@voltro/protocol": "0.60.0",
|
|
22
|
+
"@voltro/runtime": "0.60.0",
|
|
23
23
|
"effect": "^3.22.0",
|
|
24
24
|
"react": "^19.0.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.60.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-multitenancy": "0.
|
|
20
|
-
"@voltro/plugin-storage": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
23
|
-
"@voltro/sql-mysql": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.60.0",
|
|
20
|
+
"@voltro/plugin-storage": "0.60.0",
|
|
21
|
+
"@voltro/protocol": "0.60.0",
|
|
22
|
+
"@voltro/runtime": "0.60.0",
|
|
23
|
+
"@voltro/sql-mysql": "0.60.0",
|
|
24
24
|
"effect": "^3.22.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.60.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|
|
@@ -13,17 +13,17 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/database": "0.
|
|
18
|
-
"@voltro/env": "0.
|
|
19
|
-
"@voltro/plugin-multitenancy": "0.
|
|
20
|
-
"@voltro/protocol": "0.
|
|
21
|
-
"@voltro/runtime": "0.
|
|
22
|
-
"@voltro/sql-sqlite": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/database": "0.60.0",
|
|
18
|
+
"@voltro/env": "0.60.0",
|
|
19
|
+
"@voltro/plugin-multitenancy": "0.60.0",
|
|
20
|
+
"@voltro/protocol": "0.60.0",
|
|
21
|
+
"@voltro/runtime": "0.60.0",
|
|
22
|
+
"@voltro/sql-sqlite": "0.60.0",
|
|
23
23
|
"effect": "^3.22.0"
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@voltro/testing": "0.
|
|
26
|
+
"@voltro/testing": "0.60.0",
|
|
27
27
|
"typescript": "^6.0.3",
|
|
28
28
|
"@vitest/coverage-v8": "^4.1.10",
|
|
29
29
|
"vitest": "^4.1.10"
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
"test": "voltro test"
|
|
12
12
|
},
|
|
13
13
|
"dependencies": {
|
|
14
|
-
"@voltro/cli": "0.
|
|
15
|
-
"@voltro/database": "0.
|
|
16
|
-
"@voltro/env": "0.
|
|
17
|
-
"@voltro/plugin-multitenancy": "0.
|
|
18
|
-
"@voltro/plugin-storage": "0.
|
|
19
|
-
"@voltro/protocol": "0.
|
|
20
|
-
"@voltro/runtime": "0.
|
|
14
|
+
"@voltro/cli": "0.60.0",
|
|
15
|
+
"@voltro/database": "0.60.0",
|
|
16
|
+
"@voltro/env": "0.60.0",
|
|
17
|
+
"@voltro/plugin-multitenancy": "0.60.0",
|
|
18
|
+
"@voltro/plugin-storage": "0.60.0",
|
|
19
|
+
"@voltro/protocol": "0.60.0",
|
|
20
|
+
"@voltro/runtime": "0.60.0",
|
|
21
21
|
"effect": "^3.22.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@voltro/testing": "0.
|
|
24
|
+
"@voltro/testing": "0.60.0",
|
|
25
25
|
"typescript": "^6.0.3",
|
|
26
26
|
"@vitest/coverage-v8": "^4.1.10",
|
|
27
27
|
"vitest": "^4.1.10"
|
|
@@ -13,18 +13,18 @@
|
|
|
13
13
|
"dependencies": {
|
|
14
14
|
"@effect/platform": "^0.97.0",
|
|
15
15
|
"@effect/rpc": "^0.76.0",
|
|
16
|
-
"@voltro/cli": "0.
|
|
17
|
-
"@voltro/cms": "0.
|
|
18
|
-
"@voltro/database": "0.
|
|
19
|
-
"@voltro/env": "0.
|
|
20
|
-
"@voltro/plugin-auth": "0.
|
|
21
|
-
"@voltro/protocol": "0.
|
|
22
|
-
"@voltro/runtime": "0.
|
|
23
|
-
"@voltro/sql-postgres": "0.
|
|
16
|
+
"@voltro/cli": "0.60.0",
|
|
17
|
+
"@voltro/cms": "0.60.0",
|
|
18
|
+
"@voltro/database": "0.60.0",
|
|
19
|
+
"@voltro/env": "0.60.0",
|
|
20
|
+
"@voltro/plugin-auth": "0.60.0",
|
|
21
|
+
"@voltro/protocol": "0.60.0",
|
|
22
|
+
"@voltro/runtime": "0.60.0",
|
|
23
|
+
"@voltro/sql-postgres": "0.60.0",
|
|
24
24
|
"effect": "^3.22.0"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
|
-
"@voltro/testing": "0.
|
|
27
|
+
"@voltro/testing": "0.60.0",
|
|
28
28
|
"typescript": "^6.0.3",
|
|
29
29
|
"@vitest/coverage-v8": "^4.1.10",
|
|
30
30
|
"vitest": "^4.1.10"
|