@voltro/cli 0.60.0 → 0.62.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 +43 -0
- package/dist/apiBuild-Dl-djDc_.js +2 -0
- package/dist/{apiBuild-BU5cd-Fn.js → apiBuild-DwhySM-6.js} +2 -2
- package/dist/bin.js +1 -1
- package/dist/{build-BxAsLzyU.js → build-B43mm2g2.js} +7 -7
- package/dist/{checkCommand-C1CQc8lD.js → checkCommand-nB68vIo_.js} +1 -1
- package/dist/{checkCommand-DC7k1_hP.js → checkCommand-zGYZtIkJ.js} +3 -3
- package/dist/{codegenCommand-kS3Twuc9.js → codegenCommand-YvqhgQBj.js} +1 -1
- package/dist/{codemodRunner-ClUqkhvR.js → codemodRunner-D90bexh4.js} +233 -159
- package/dist/{commands-Ro4hYBHD.js → commands-Dd6Cp7qs.js} +21 -21
- package/dist/{dashboardCommand-t8Qsebjr.js → dashboardCommand-BsDfQa-g.js} +3 -3
- package/dist/{dataCommand-hNOGKz4K.js → dataCommand-Cgdcl5M0.js} +1 -1
- package/dist/{dev-Ce2gEziv.js → dev-BfUG0jrD.js} +32 -12
- package/dist/{dev-Dff_pdik.js → dev-BpMSAjMk.js} +1 -1
- package/dist/doctorCommand-PHcqxpnx.js +2 -0
- package/dist/{doctorCommand-CGjefPmk.js → doctorCommand-pxYq2bH5.js} +13 -13
- package/dist/{dormancyCommand-DYgI0Kf-.js → dormancyCommand-DZpSCWy9.js} +1 -1
- package/dist/{embeddingsCommand-yJivQSrI.js → embeddingsCommand-YR5Eif0k.js} +1 -1
- package/dist/{envCommand-ORJUf8r_.js → envCommand-Yl4TGM4h.js} +2 -2
- package/dist/{evolveCommand-CThb0EZZ.js → evolveCommand-B2iYAC9t.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{infoCommand-a0WkKcUY.js → infoCommand-DjtMWLZl.js} +1 -1
- package/dist/{probeCommand-BUYzc0CT.js → probeCommand-Dsu5if_4.js} +1 -1
- package/dist/{runtimeTrace-DDuKJgVi.js → runtimeTrace-CQcn26bI.js} +1 -1
- package/dist/{sdkgen-vq1fF9D_.js → sdkgen-DJvyVw7B.js} +1 -1
- package/dist/serveCommand-CZ0kgfIX.js +2 -0
- package/dist/{serveCommand-Dr4KXmTS.js → serveCommand-CaLTTh68.js} +3 -3
- package/dist/serveEntry.js +1 -1
- package/dist/{start-BhoDQ25C.js → start-DE4ixCTi.js} +1 -1
- package/dist/{start-CcdPRG8L.js → start-bqT4GRH0.js} +427 -418
- package/dist/startEntry.js +1 -1
- package/dist/updateCommand-DA4OMF7u.js +2 -0
- package/dist/{updateCommand-D9avpQFT.js → updateCommand-F6HFgz0i.js} +1 -1
- package/dist/{webDev-CBN9KkyQ.js → webDev-CYjhmOTZ.js} +1 -1
- package/dist/{webDev-Bzb8ZFus.js → webDev-CuG3Ged-.js} +1 -1
- package/dist/{webhooksCommand-BPJQOGTe.js → webhooksCommand-Bgdli8dI.js} +1 -1
- package/package.json +37 -19
- package/templates/AGENTS.md +2 -2
- package/templates/agent-docs/_index.md +2 -2
- package/templates/agent-docs/_manifest.json +1 -1
- package/templates/agent-docs/ai.md +32 -0
- package/templates/agent-docs/data.md +10 -2
- package/templates/agent-docs/observability.md +17 -2
- package/templates/agent-docs/plugins/sentry.md +29 -12
- package/templates/agent-docs/schema-driven-ui.md +38 -10
- package/templates/agent-docs/whats-new.md +5 -45
- package/templates/agent-docs/workflows.md +7 -2
- 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/apiBuild-B9OvhITV.js +0 -2
- package/dist/doctorCommand-DXnNpKQT.js +0 -2
- package/dist/serveCommand-1R52mo6F.js +0 -2
- package/dist/updateCommand-QMOirvXC.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-D90bexh4.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";
|
|
@@ -2556,7 +2556,7 @@ The wrapper is what carries \`match\`, and what lets \`voltro doctor\` report wh
|
|
|
2556
2556
|
return [
|
|
2557
2557
|
"",
|
|
2558
2558
|
"// Browser-side Sentry (frontend half of the deep integration). Errors +",
|
|
2559
|
-
"//
|
|
2559
|
+
"// page-owned rpc spans linked to their server traces flow to Sentry.",
|
|
2560
2560
|
n === void 0 ? `await initSentryBrowser(${JSON.stringify(r)})` : `await initSentryBrowser({ ...${JSON.stringify(r)}, ...(await __sentryOptions()) })`
|
|
2561
2561
|
];
|
|
2562
2562
|
}, Fo = (e) => e.env ? ["import './env.public'"] : [], Io = (e) => {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as e, T as t, m as n } from "./webDev-
|
|
1
|
+
import { C as e, T as t, m as n } from "./webDev-CYjhmOTZ.js";
|
|
2
2
|
export { n as loadConfig, e as tryRunWebServe, t as walkPagesTree };
|
|
@@ -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-BpMSAjMk.js"), { outgoingFromEvents: r } = await import("./webhookDiscovery-il9ti-HE.js");
|
|
226
226
|
return r((await n(await t(e), { root: 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.62.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",
|
|
@@ -898,6 +898,24 @@
|
|
|
898
898
|
"title": "Sentry no longer reports declared failures by default",
|
|
899
899
|
"kind": "manual"
|
|
900
900
|
},
|
|
901
|
+
{
|
|
902
|
+
"version": "0.61.0",
|
|
903
|
+
"id": "0.61.0/01_rpc_errors_have_kinds",
|
|
904
|
+
"title": "`RpcError` now carries an explicit failure kind",
|
|
905
|
+
"kind": "manual"
|
|
906
|
+
},
|
|
907
|
+
{
|
|
908
|
+
"version": "0.61.0",
|
|
909
|
+
"id": "0.61.0/02_sentry_rpc_spans_join_page",
|
|
910
|
+
"title": "Sentry rpc spans now join the active browser transaction",
|
|
911
|
+
"kind": "manual"
|
|
912
|
+
},
|
|
913
|
+
{
|
|
914
|
+
"version": "0.62.0",
|
|
915
|
+
"id": "0.62.0/01_finish_timeout_uses_durable_cancellation",
|
|
916
|
+
"title": "Finish timeouts use durable, once-only cancellation",
|
|
917
|
+
"kind": "manual"
|
|
918
|
+
},
|
|
901
919
|
{
|
|
902
920
|
"version": "0.7.0",
|
|
903
921
|
"id": "0.7.0/01_row-filter-load-failure",
|
|
@@ -944,24 +962,24 @@
|
|
|
944
962
|
"@effect/platform-node": "^0.108.0",
|
|
945
963
|
"@effect/sql": "^0.52.0",
|
|
946
964
|
"@effect/workflow": "^0.19.0",
|
|
947
|
-
"@voltro/ai": "0.
|
|
948
|
-
"@voltro/cache": "0.
|
|
949
|
-
"@voltro/client": "0.
|
|
950
|
-
"@voltro/content": "0.
|
|
951
|
-
"@voltro/data-transfer": "0.
|
|
952
|
-
"@voltro/database": "0.
|
|
953
|
-
"@voltro/env": "0.
|
|
954
|
-
"@voltro/kv": "0.
|
|
955
|
-
"@voltro/logger": "0.
|
|
956
|
-
"@voltro/plugin-auth": "0.
|
|
957
|
-
"@voltro/plugin-broadcast": "0.
|
|
958
|
-
"@voltro/plugin-mail": "0.
|
|
959
|
-
"@voltro/plugin-storage": "0.
|
|
960
|
-
"@voltro/plugin-webhooks": "0.
|
|
961
|
-
"@voltro/protocol": "0.
|
|
962
|
-
"@voltro/runtime": "0.
|
|
963
|
-
"@voltro/serverless": "0.
|
|
964
|
-
"@voltro/workflow": "0.
|
|
965
|
+
"@voltro/ai": "0.62.0",
|
|
966
|
+
"@voltro/cache": "0.62.0",
|
|
967
|
+
"@voltro/client": "0.62.0",
|
|
968
|
+
"@voltro/content": "0.62.0",
|
|
969
|
+
"@voltro/data-transfer": "0.62.0",
|
|
970
|
+
"@voltro/database": "0.62.0",
|
|
971
|
+
"@voltro/env": "0.62.0",
|
|
972
|
+
"@voltro/kv": "0.62.0",
|
|
973
|
+
"@voltro/logger": "0.62.0",
|
|
974
|
+
"@voltro/plugin-auth": "0.62.0",
|
|
975
|
+
"@voltro/plugin-broadcast": "0.62.0",
|
|
976
|
+
"@voltro/plugin-mail": "0.62.0",
|
|
977
|
+
"@voltro/plugin-storage": "0.62.0",
|
|
978
|
+
"@voltro/plugin-webhooks": "0.62.0",
|
|
979
|
+
"@voltro/protocol": "0.62.0",
|
|
980
|
+
"@voltro/runtime": "0.62.0",
|
|
981
|
+
"@voltro/serverless": "0.62.0",
|
|
982
|
+
"@voltro/workflow": "0.62.0",
|
|
965
983
|
"chokidar": "^5.0.0",
|
|
966
984
|
"ioredis": "^5.11.1",
|
|
967
985
|
"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.62.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. |
|
|
@@ -832,7 +832,7 @@ each plugin's own README.
|
|
|
832
832
|
| row-history | `node_modules/@voltro/cli/templates/agent-docs/plugins/row-history.md` (or `node_modules/@voltro/plugin-row-history/README.md`) | Full row history + time-travel. audit() records who/when; row-history records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
|
|
833
833
|
| scim | `node_modules/@voltro/cli/templates/agent-docs/plugins/scim.md` (or `node_modules/@voltro/plugin-scim/README.md`) | SCIM 2.0 provisioning — Users + Groups REST endpoints so an enterprise IdP (Okta, Entra, OneLogin) can create / update / deactivate users in your app. |
|
|
834
834
|
| search | `node_modules/@voltro/cli/templates/agent-docs/plugins/search.md` (or `node_modules/@voltro/plugin-search/README.md`) | Keep an external search index (Typesense / Meilisearch / Algolia) in sync with your tables via the ChangeEvent tap, query it tenant-scoped through a typed action + hook. |
|
|
835
|
-
| sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and
|
|
835
|
+
| sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and controlled performance traces. |
|
|
836
836
|
| soft-delete | `node_modules/@voltro/cli/templates/agent-docs/plugins/soft-delete.md` (or `node_modules/@voltro/plugin-soft-delete/README.md`) | The softDelete() schema mixin — deletedAt / deletedBy columns, delete() redirected to an UPDATE, default reads filtered, hardDelete() bypass. |
|
|
837
837
|
| sso-saml | `node_modules/@voltro/cli/templates/agent-docs/plugins/sso-saml.md` (or `node_modules/@voltro/plugin-sso-saml/README.md`) | Enterprise SAML 2.0 SSO — SP-initiated login, ACS assertion consumer, SP metadata. Signature verification via @node-saml/node-saml; framework session minting built in. |
|
|
838
838
|
| storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / MinIO (R2 and GCS via their S3 interop) / Azure / database / filesystem / memory providers, presigned URLs, a dashboard browser. |
|
|
@@ -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.62.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. |
|
|
@@ -92,7 +92,7 @@ each plugin's own README.
|
|
|
92
92
|
| row-history | `node_modules/@voltro/cli/templates/agent-docs/plugins/row-history.md` (or `node_modules/@voltro/plugin-row-history/README.md`) | Full row history + time-travel. audit() records who/when; row-history records what-changed-to-what — a value snapshot of every row on every write, with as-of queries. |
|
|
93
93
|
| scim | `node_modules/@voltro/cli/templates/agent-docs/plugins/scim.md` (or `node_modules/@voltro/plugin-scim/README.md`) | SCIM 2.0 provisioning — Users + Groups REST endpoints so an enterprise IdP (Okta, Entra, OneLogin) can create / update / deactivate users in your app. |
|
|
94
94
|
| search | `node_modules/@voltro/cli/templates/agent-docs/plugins/search.md` (or `node_modules/@voltro/plugin-search/README.md`) | Keep an external search index (Typesense / Meilisearch / Algolia) in sync with your tables via the ChangeEvent tap, query it tenant-scoped through a typed action + hook. |
|
|
95
|
-
| sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and
|
|
95
|
+
| sentry | `node_modules/@voltro/cli/templates/agent-docs/plugins/sentry.md` (or `node_modules/@voltro/plugin-sentry/README.md`) | Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and controlled performance traces. |
|
|
96
96
|
| soft-delete | `node_modules/@voltro/cli/templates/agent-docs/plugins/soft-delete.md` (or `node_modules/@voltro/plugin-soft-delete/README.md`) | The softDelete() schema mixin — deletedAt / deletedBy columns, delete() redirected to an UPDATE, default reads filtered, hardDelete() bypass. |
|
|
97
97
|
| sso-saml | `node_modules/@voltro/cli/templates/agent-docs/plugins/sso-saml.md` (or `node_modules/@voltro/plugin-sso-saml/README.md`) | Enterprise SAML 2.0 SSO — SP-initiated login, ACS assertion consumer, SP metadata. Signature verification via @node-saml/node-saml; framework session minting built in. |
|
|
98
98
|
| storage | `node_modules/@voltro/cli/templates/agent-docs/plugins/storage.md` (or `node_modules/@voltro/plugin-storage/README.md`) | File storage behind one StorageService — public objects served direct from the bucket/CDN, private objects gated by an access policy + per-object grants. S3 / MinIO (R2 and GCS via their S3 interop) / Azure / database / filesystem / memory providers, presigned URLs, a dashboard browser. |
|
|
@@ -660,7 +660,7 @@
|
|
|
660
660
|
{
|
|
661
661
|
"slug": "sentry",
|
|
662
662
|
"title": "Sentry",
|
|
663
|
-
"description": "Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and
|
|
663
|
+
"description": "Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and controlled performance traces.",
|
|
664
664
|
"pkg": "@voltro/plugin-sentry",
|
|
665
665
|
"doc": "plugins/sentry.md",
|
|
666
666
|
"module": "agent-docs/plugins/sentry.md"
|
|
@@ -1303,6 +1303,38 @@ export default (input: { message: string }) =>
|
|
|
1303
1303
|
|
|
1304
1304
|
`streamText` emits `AgentEvent` elements. The `_tag`s are: `token` (text delta), `reasoning` (the model's thinking, separate from the answer), `toolCall`, `toolResult`, `source` (a cited RAG/web source — `url` or `document` variant), `file` (an inline file the model produced, usually an image: `mediaType` + base64 `data`), `message`, `error` (carries `retryable`), and `done`. The stream NEVER fails — an upstream error arrives as a terminal `error` event.
|
|
1305
1305
|
|
|
1306
|
+
## Smooth Streaming
|
|
1307
|
+
|
|
1308
|
+
Provider chunks are transport artifacts: one provider may send a word at a time while another releases a whole paragraph in a burst. Opt into server-side semantic smoothing when the UI should receive predictable word or line chunks:
|
|
1309
|
+
|
|
1310
|
+
```ts
|
|
1311
|
+
streamText({
|
|
1312
|
+
prompt: input.message,
|
|
1313
|
+
smooth: {
|
|
1314
|
+
chunking: 'word', // default; alternatively 'line'
|
|
1315
|
+
delayMs: 10, // default; null rechunks without adding delay
|
|
1316
|
+
},
|
|
1317
|
+
})
|
|
1318
|
+
```
|
|
1319
|
+
|
|
1320
|
+
`smooth` is framework-owned and deliberately narrower than the AI SDK's experimental transform surface. It smooths both text and reasoning, flushes pending content before tool/source/file/error/done events, and shares the stream's abort signal. Omit it or set `smooth: false` to preserve provider-native chunks and latency.
|
|
1321
|
+
|
|
1322
|
+
With `resumableStreamText`, put `smooth` inside `options`. Smoothing happens before `AgentEvent` conversion and before the append-only journal, so a reconnect replays the exact same `SeqEvent` boundaries seen live:
|
|
1323
|
+
|
|
1324
|
+
```ts
|
|
1325
|
+
resumableStreamText({
|
|
1326
|
+
streamId: input.streamId,
|
|
1327
|
+
store,
|
|
1328
|
+
options: {
|
|
1329
|
+
prompt: input.message,
|
|
1330
|
+
smooth: { chunking: 'word', delayMs: 10 },
|
|
1331
|
+
},
|
|
1332
|
+
fromSeq: input.fromSeq,
|
|
1333
|
+
})
|
|
1334
|
+
```
|
|
1335
|
+
|
|
1336
|
+
Smoothing changes only text/reasoning boundaries and timing. Content, usage, finish reason, tool ids, and cost accounting stay unchanged. The client should still batch rendering (for example, at most once per animation frame); server smoothing normalizes semantics, it does not replace UI backpressure.
|
|
1337
|
+
|
|
1306
1338
|
## Cancel, retry
|
|
1307
1339
|
|
|
1308
1340
|
A "Stop" button needs to end an in-flight run out of band. Pass a `streamId` and call `cancelStream(streamId)` from a separate action/mutation — it aborts the provider call (token spend stops) and the stream ends on a terminal, non-retryable `cancelled` error.
|
|
@@ -1220,13 +1220,21 @@ try {
|
|
|
1220
1220
|
}
|
|
1221
1221
|
```
|
|
1222
1222
|
|
|
1223
|
-
**Trace id for debugging.** An error caught from `useMutation` / `useAction`
|
|
1223
|
+
**Trace id for debugging.** An error caught from `useMutation` / `useAction`
|
|
1224
|
+
carries the **non-enumerable client-span id `__voltroTraceId`**:
|
|
1224
1225
|
|
|
1225
1226
|
```ts
|
|
1226
1227
|
const traceId = (err as { __voltroTraceId?: string }).__voltroTraceId
|
|
1227
|
-
//
|
|
1228
|
+
// If the server accepted the call: `voltro logs --trace <traceId>`
|
|
1228
1229
|
```
|
|
1229
1230
|
|
|
1231
|
+
For a declared handler error, the server necessarily accepted the call and the
|
|
1232
|
+
id joins to its span. For a transport error it may not: the connection can fail
|
|
1233
|
+
before the request arrived or after the handler ran but before its response
|
|
1234
|
+
returned. Use `kind` from
|
|
1235
|
+
[`useOnRpcError`](/docs/ui/client-utilities/use-on-rpc-error) for that distinction;
|
|
1236
|
+
the presence of the id alone proves only that the client span existed.
|
|
1237
|
+
|
|
1230
1238
|
`errorTag` lives in `@voltro/protocol` rather than in the client for a reason
|
|
1231
1239
|
worth knowing before you decide where your own error handling goes: **`_tag` is a
|
|
1232
1240
|
wire concept, and protocol owns the wire.** So a shared error handler in a package
|
|
@@ -213,6 +213,12 @@ Trace continuity is **automatic and on by default** in `voltro dev` — a buffer
|
|
|
213
213
|
- **api → api is automatic over HTTP.** An action or handler that calls another api via the framework `HttpClient` sends a W3C `traceparent` header; an inbound `*.webhook.tsx` route (an incoming HTTP handler) **continues** the caller's trace. So frontend → api Y → api Z (via webhook / HTTP) is **one** trace.
|
|
214
214
|
- **Every log line carries it.** Handlers stamp `fields.traceId` onto each log line they emit, so [`voltro logs --trace <id>`](/docs/observability/cli) returns the whole chain across hops, in order.
|
|
215
215
|
|
|
216
|
+
The client span exists before the transport proves delivery. If a connection
|
|
217
|
+
fails, its `traceId` can therefore have no matching server span — or the server
|
|
218
|
+
may have completed the handler and lost only the response. In rpc-error policy,
|
|
219
|
+
use [`RpcError.kind`](/docs/ui/client-utilities/use-on-rpc-error), never the mere
|
|
220
|
+
presence of `traceId`, to distinguish transport failures from handler failures.
|
|
221
|
+
|
|
216
222
|
```
|
|
217
223
|
client.mutation.placeOrder traceId=4bf92f35…
|
|
218
224
|
└─ mutation.placeOrder traceId=4bf92f35… (api Y, ctx.request.traceId)
|
|
@@ -259,7 +265,7 @@ This is the fastest way to answer "where did this error come from?" — far fast
|
|
|
259
265
|
|
|
260
266
|
The same trace continuity flows to a vendor APM when you install a deep-observability plugin — no `OTEL_*` env. Each contributes an OTel span-processor to the framework's tracer via `contributeObservability`, so the vendor runs as a **consumer** of the existing tracer (the in-app Traces panel keeps working) and receives the identical spans:
|
|
261
267
|
|
|
262
|
-
- [`@voltro/plugin-sentry`](/docs/plugins/sentry) — every mutation/query/action error becomes a Sentry issue correlated to its `trace_id` + `span_id`, with the request's log lines as breadcrumbs;
|
|
268
|
+
- [`@voltro/plugin-sentry`](/docs/plugins/sentry) — every mutation/query/action error becomes a Sentry issue correlated to its `trace_id` + `span_id`, with the request's log lines as breadcrumbs; server performance traces are on by default (`traces: false` disables them). The browser integration keeps rpc markers inside the sampled page/navigation transaction and links each marker to its Effect/server trace.
|
|
263
269
|
- [`@voltro/plugin-datadog`](/docs/plugins/datadog) — framework spans → the Datadog Agent's OTLP receiver (`traces: true`), plus log forwarding with `dd.trace_id` correlation.
|
|
264
270
|
|
|
265
271
|
See [Observability › Routing traces to a vendor](/docs/observability/overview#routing-traces-to-a-vendor) for the contribution surface + the sampler caveat.
|
|
@@ -286,7 +292,9 @@ _Inspect traces and logs from the shell — flags, the --trace <id> end-to-end c
|
|
|
286
292
|
|
|
287
293
|
## `voltro logs`
|
|
288
294
|
|
|
289
|
-
Every `voltro dev` / `voltro start` instance buffers the last **2000** server-side `@voltro/logger` records
|
|
295
|
+
Every `voltro dev` / `voltro start` instance buffers the last **2000** server-side `@voltro/logger` records. During `voltro dev`, the browser console bridge also forwards browser console lines into that buffer.
|
|
296
|
+
|
|
297
|
+
The browser-to-inspect bridges are deliberately limited to development builds. Setting `localStorage.framework_debug = '1'` in a production bundle enables the local `[fw …]` connection timeline only; it never starts `clientLog` POSTs or an inspect `EventSource`. In development, both diagnostic transports are single-flight, rate-limited, and bounded: permanent `4xx` responses disable them for the page, while transient failures use exponential backoff and open a circuit after five consecutive failures. The SSE relay probes status and content type before creating an `EventSource`, then explicitly closes a failed source before a bounded retry.
|
|
290
298
|
|
|
291
299
|
```sh
|
|
292
300
|
voltro logs # last 100 from every running process
|
|
@@ -624,6 +632,13 @@ proxy path, cleared the moment the stream opens; the proxy moves it into an
|
|
|
624
632
|
`Authorization` header. Nothing about the token ever appears in a URL, and the
|
|
625
633
|
app receives a header like any other caller.
|
|
626
634
|
|
|
635
|
+
That dashboard proxy is also why a production app page must not open the
|
|
636
|
+
inspect stream merely because `localStorage.framework_debug` is set. The app
|
|
637
|
+
page has no bearer-capable `EventSource` transport and no authority to mint the
|
|
638
|
+
dashboard cookie. Voltro therefore keeps its in-page console and SSE relays
|
|
639
|
+
development-only; the persisted production flag affects local framework
|
|
640
|
+
console output, not inspect traffic.
|
|
641
|
+
|
|
627
642
|
## In the dashboards
|
|
628
643
|
|
|
629
644
|
Both dashboards unwrap `.data` in their fetch layer and keep the envelope. A
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sentry
|
|
2
2
|
|
|
3
|
-
> Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and
|
|
3
|
+
> Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and controlled performance traces.
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
<!-- source: en/plugins/sentry.md -->
|
|
10
10
|
## Sentry
|
|
11
11
|
|
|
12
|
-
_Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and
|
|
12
|
+
_Deep Sentry integration — errors correlated to the distributed trace, breadcrumbs from the log sink, and controlled performance traces._
|
|
13
13
|
|
|
14
|
-
`@voltro/plugin-sentry` is the deep Sentry integration: every mutation/query/action failure becomes a Sentry issue **correlated to the active distributed trace** (trace_id + span_id) and carrying the request's recent log lines as breadcrumbs.
|
|
14
|
+
`@voltro/plugin-sentry` is the deep Sentry integration: every mutation/query/action failure becomes a Sentry issue **correlated to the active distributed trace** (trace_id + span_id) and carrying the request's recent log lines as breadcrumbs. The framework's spans flow to Sentry as transactions by default.
|
|
15
15
|
|
|
16
16
|
Uses the official `@sentry/node` SDK in **OpenTelemetry-consumer mode** — it consumes the framework's existing tracer (it never becomes the global provider), so the in-app [Traces dashboard](/docs/observability/distributed-tracing) stays intact.
|
|
17
17
|
|
|
@@ -29,7 +29,7 @@ export default {
|
|
|
29
29
|
// dsn defaults to SENTRY_DSN; without a valid DSN the plugin is a no-op.
|
|
30
30
|
environment: 'production', // or SENTRY_ENVIRONMENT
|
|
31
31
|
release: '1.4.2', // or SENTRY_RELEASE
|
|
32
|
-
traces: true, // route the framework's spans → Sentry (default
|
|
32
|
+
traces: true, // route the framework's spans → Sentry (default on)
|
|
33
33
|
tracesSampleRate: 1.0,
|
|
34
34
|
profiling: true, // continuous CPU profiler via @sentry/profiling-node
|
|
35
35
|
}),
|
|
@@ -46,7 +46,7 @@ export default {
|
|
|
46
46
|
| `dsn` | `string` | `SENTRY_DSN` env | No valid DSN → the plugin is inert (no interceptors registered). |
|
|
47
47
|
| `environment` | `string` | `SENTRY_ENVIRONMENT` env | Sentry `environment` tag + `deployment.environment` resource attribute. |
|
|
48
48
|
| `release` | `string` | `SENTRY_RELEASE` env | Release-health + source-map matching; also `service.version`. |
|
|
49
|
-
| `traces` | `boolean` | `
|
|
49
|
+
| `traces` | `boolean` | `true` | Route the framework's OTel spans to Sentry as transactions. Off → errors + breadcrumbs only. |
|
|
50
50
|
| `tracesSampleRate` | `number` | `1.0` | Applied by the Sentry client (not a tracer sampler). Only relevant with `traces`. |
|
|
51
51
|
| `profiling` | `boolean` | `false` | Continuous CPU profiler via `@sentry/profiling-node` (lazy; warns if not installed). |
|
|
52
52
|
| `profilesSampleRate` | `number` | `1.0` | Only relevant with `profiling`. |
|
|
@@ -73,15 +73,15 @@ This guarantees the error links to its trace in Sentry **regardless** of the Eff
|
|
|
73
73
|
|
|
74
74
|
The framework log sink feeds a bounded **per-trace** ring (capped per-trace + LRU + TTL), keyed on each log line's `traceId`. On an error the trace's breadcrumbs are attached to the event; traces that never error are reaped by the TTL. So a Sentry issue shows the exact log lines leading up to it — for that request only.
|
|
75
75
|
|
|
76
|
-
##
|
|
76
|
+
## Server traces
|
|
77
77
|
|
|
78
78
|
The plugin contributes a `SentrySpanProcessor` to the framework's tracer (via the plugin observability surface — see [Observability › Routing traces to a vendor](/docs/observability/overview#routing-traces-to-a-vendor)). Every framework span becomes a Sentry transaction, sharing the same trace id the errors carry — so in Sentry you land on an error inside its full distributed trace.
|
|
79
79
|
|
|
80
80
|
We deliberately do **not** install a `SentrySampler` as the tracer's sampler: that would gate recording for the WHOLE tracer and blind the framework's own in-app Traces buffer. The framework keeps its always-on sampler; `tracesSampleRate` is applied by the Sentry client.
|
|
81
81
|
|
|
82
|
-
##
|
|
82
|
+
## Correlating the browser page with server traces
|
|
83
83
|
|
|
84
|
-
The plugin ships a browser half at `@voltro/plugin-sentry/web
|
|
84
|
+
The plugin ships a browser half at `@voltro/plugin-sentry/web`. It records one page-load or navigation transaction with rpc child spans, while each rpc child links to the Effect trace continued by the server. This avoids a transaction and network envelope per rpc call without losing the connection between browser and server work. Turn it on in the web app's `app.config.ts`:
|
|
85
85
|
|
|
86
86
|
```ts
|
|
87
87
|
// apps/web/app.config.ts
|
|
@@ -94,6 +94,8 @@ export default {
|
|
|
94
94
|
environment: 'production',
|
|
95
95
|
release: '1.4.2', // MUST match the api's `release` for unified release health
|
|
96
96
|
tracesSampleRate: 1.0,
|
|
97
|
+
browserTracing: true,
|
|
98
|
+
rpcSpans: true,
|
|
97
99
|
},
|
|
98
100
|
}
|
|
99
101
|
```
|
|
@@ -102,7 +104,22 @@ The framework's generated entry calls `initSentryBrowser()` before mount (no cod
|
|
|
102
104
|
|
|
103
105
|
What it does:
|
|
104
106
|
- **Inits `@sentry/react`** with `browserTracingIntegration` — page loads + client navigations become Sentry transactions, and unhandled errors / promise rejections are captured by the SDK's default global handlers.
|
|
105
|
-
- **
|
|
107
|
+
- **Keeps rpc spans page-owned.** Every framework rpc call (`useMutation`/`useSubscription`/`useAction`) already wraps itself in an Effect client span and propagates that span's W3C `traceId`+`spanId` to the api. The browser half adds a child to the currently active page/navigation transaction and attaches the Effect/server trace as a span link. If no browser transaction is active, it emits no rpc root transaction.
|
|
108
|
+
- **Honours sampling.** `tracesSampleRate` decides whether the page/navigation root is recorded; its rpc children inherit that decision. The bridge does not inject a sampled parent decision.
|
|
109
|
+
|
|
110
|
+
Browser trace controls:
|
|
111
|
+
|
|
112
|
+
| Option | Default | Effect |
|
|
113
|
+
|---|---|---|
|
|
114
|
+
| `tracesSampleRate` | `1.0` | Samples page-load/navigation transactions and therefore their rpc children. Error reporting is independent. |
|
|
115
|
+
| `browserTracing` | `true` | Installs page-load/navigation instrumentation. `false` also defaults `rpcSpans` to off. |
|
|
116
|
+
| `rpcSpans` | same as `browserTracing` | Adds rpc children to an active browser transaction. `false` keeps browser errors and page traces but removes the rpc bridge. Set it to `true` with `browserTracing:false` only if your app creates active Sentry transactions itself. |
|
|
117
|
+
|
|
118
|
+
At browser boot the plugin prints the effective values, including the mode:
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
[@voltro/plugin-sentry] browser active { tracesSampleRate: 1, browserTracing: true, rpcSpans: true, rpcSpanMode: 'page-child-with-server-link' }
|
|
122
|
+
```
|
|
106
123
|
|
|
107
124
|
> **Manual wiring** (no app.config field, e.g. an app that builds its own entry): call it yourself once at boot —
|
|
108
125
|
> ```ts
|
|
@@ -157,9 +174,9 @@ in deployment env. Setting one as a deployment variable deploys cleanly and does
|
|
|
157
174
|
nothing; `voltro start` warns when it finds one, naming whether the bundle
|
|
158
175
|
carries that key at all.
|
|
159
176
|
|
|
160
|
-
The two halves are independent: the api plugin alone gives you server traces + errors; add the web half for
|
|
177
|
+
The two halves are independent: the api plugin alone gives you server traces + errors; add the web half for page performance, browser errors, rpc markers, and links back to the server traces. Both tracing halves are on by default, so an app with the plugin on the api and `@voltro/plugin-sentry` as a dependency of the web app gets server transactions plus one sampled browser transaction per page/navigation from one `SENTRY_DSN` plus one `VOLTRO_PUBLIC_SENTRY_DSN`. Give both halves the same `release`.
|
|
161
178
|
|
|
162
|
-
**Traces default to on, at `tracesSampleRate: 1.0`.** That is
|
|
179
|
+
**Traces default to on, at `tracesSampleRate: 1.0`.** That is explicit, not a production recommendation. Lower the rate independently on api and web to fit the trace budget. Set api `traces:false` to keep server errors and breadcrumbs only; set web `browserTracing:false` to keep browser error capture without automatic performance transactions; or use web `rpcSpans:false` to keep page performance while omitting rpc child spans.
|
|
163
180
|
|
|
164
181
|
## Source maps (every bundle, browser and server)
|
|
165
182
|
|
|
@@ -344,7 +361,7 @@ Once the two halves are wired, most errors are captured **with no per-call code*
|
|
|
344
361
|
| rpc handler throw (mutation/query/action) | ✅ auto | server interceptor → Sentry, trace-correlated + breadcrumbs |
|
|
345
362
|
| Unhandled browser error / promise rejection | ✅ auto | `@sentry/react` global handlers (after `initSentryBrowser`) |
|
|
346
363
|
| **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**
|
|
364
|
+
| **React render error, during SSR** — six sites: `ssr-shell`, `spa-layout-shell`, `render` (incl. a loader throw), `not-found-render`, `ppr-holes`, `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`. The last three are `warn`-level — the request still serves something — and are reported anyway: quieter is not less real, and nothing else can see them. Needs `SENTRY_DSN` on the **web** deployment. |
|
|
348
365
|
| **Loader failure** (page/layout `loader` reject) | ✅ auto | same route bus path |
|
|
349
366
|
| Manual try/catch (event handler, async effect, anywhere) | ✋ one call | `reportClientError(error, context?)` |
|
|
350
367
|
| **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) |
|
|
@@ -1194,10 +1194,20 @@ const { status, reportSuccess } = useConnectionStatus('app')
|
|
|
1194
1194
|
`status` is `'connected' | 'degraded' | 'offline'`. `offline` is browser-reported
|
|
1195
1195
|
(`navigator.onLine` plus its `online` / `offline` events) — reliable for "the
|
|
1196
1196
|
network is gone", and it wins over `degraded`. `degraded` means an rpc on that
|
|
1197
|
-
api failed
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1197
|
+
api failed with `kind: 'transport'` and no later call has proved the server
|
|
1198
|
+
reachable. Declared handler errors do **not** colour the connection; if already
|
|
1199
|
+
degraded, a handler reply clears it because the server demonstrably answered.
|
|
1200
|
+
Local client and unknown failures leave the connection state unchanged. Any rpc
|
|
1201
|
+
success also clears the failure count automatically. Coming back online clears
|
|
1202
|
+
it too, since failures counted during an offline window *are* that window.
|
|
1203
|
+
`reportSuccess()` remains the explicit escape hatch for another signal that
|
|
1204
|
+
proves a round trip succeeded.
|
|
1205
|
+
|
|
1206
|
+
Use this hook to **render aggregate connection state**. To classify the failure
|
|
1207
|
+
that is firing right now — for example, to avoid a data-error toast in the same
|
|
1208
|
+
tick the socket drops — branch on `event.kind` inside
|
|
1209
|
+
[`useOnRpcError`](/docs/ui/client-utilities/use-on-rpc-error). React state updates
|
|
1210
|
+
after the event and therefore cannot classify that event retroactively.
|
|
1201
1211
|
|
|
1202
1212
|
Also returned: `online`, `failureCount`, `lastFailureAt`. There is deliberately
|
|
1203
1213
|
no polling ping — the framework does not call the server just to colour an
|
|
@@ -1578,16 +1588,34 @@ import { useOnRpcError } from '@voltro/client'
|
|
|
1578
1588
|
import { errorTag } from '@voltro/protocol'
|
|
1579
1589
|
|
|
1580
1590
|
useOnRpcError('app', useCallback((e) => {
|
|
1591
|
+
if (e.kind === 'transport') {
|
|
1592
|
+
showConnectionLost()
|
|
1593
|
+
return
|
|
1594
|
+
}
|
|
1581
1595
|
if (errorTag(e.error) === 'Unauthenticated') redirectToSignIn()
|
|
1582
1596
|
}, []))
|
|
1583
1597
|
```
|
|
1584
1598
|
|
|
1585
|
-
The event is `{ source, tag, error, traceId? }`. `source` is
|
|
1599
|
+
The event is `{ source, tag, error, kind, traceId? }`. `source` is
|
|
1586
1600
|
`'mutation' | 'action' | 'subscription'`, so both unary calls and stream
|
|
1587
1601
|
failures arrive here. `error` is the raw value — a `Schema.TaggedError`, a plain
|
|
1588
1602
|
`Error`, or anything else that was thrown; `errorTag(err)` reads `_tag` off
|
|
1589
|
-
tagged errors and returns `undefined` otherwise.
|
|
1590
|
-
|
|
1603
|
+
tagged errors and returns `undefined` otherwise.
|
|
1604
|
+
|
|
1605
|
+
`kind` is `'transport' | 'handler' | 'client' | 'unknown'`:
|
|
1606
|
+
|
|
1607
|
+
- `transport` — @effect/rpc could not complete the exchange. Use this branch for
|
|
1608
|
+
connection banners and to suppress misleading data-error toasts.
|
|
1609
|
+
- `handler` — the rpc returned a declared failure, such as `Unauthenticated`.
|
|
1610
|
+
- `client` — framework work around the call failed locally.
|
|
1611
|
+
- `unknown` — a combined or opaque operation could not be classified honestly.
|
|
1612
|
+
|
|
1613
|
+
`traceId` identifies the **client call span**. When the server accepted the
|
|
1614
|
+
request, it propagates the same id and `voltro logs --trace <id>` can join the
|
|
1615
|
+
call to server logs. A transport error can happen before the server saw the
|
|
1616
|
+
request, or after it handled the request but before the response returned, so a
|
|
1617
|
+
`traceId` on `kind: 'transport'` is not proof that server logs exist. For the
|
|
1618
|
+
same reason the event deliberately has no `reachedServer` boolean.
|
|
1591
1619
|
|
|
1592
1620
|
Two things to know. The hook re-subscribes whenever the listener **reference**
|
|
1593
1621
|
changes, so define it with `useCallback` or at module scope unless you want that.
|
|
@@ -1598,9 +1626,9 @@ per api name.
|
|
|
1598
1626
|
is also published on the client error bus, so a reporter — the Sentry browser
|
|
1599
1627
|
integration, or anything wired with `subscribeClientErrors` — already sees it,
|
|
1600
1628
|
under `source: 'rpc.mutation' | 'rpc.action' | 'rpc.subscription'` with the rpc
|
|
1601
|
-
tag and `traceId` in `context`. This hook is for
|
|
1602
|
-
on `Unauthenticated`, toast on a network
|
|
1603
|
-
the two by hand now reports twice.
|
|
1629
|
+
tag, `rpcErrorKind`, and optional `traceId` in `context`. This hook is for
|
|
1630
|
+
cross-cutting *policy* (redirect on `Unauthenticated`, toast on a network
|
|
1631
|
+
failure), not for telemetry; bridging the two by hand now reports twice.
|
|
1604
1632
|
|
|
1605
1633
|
Everything is published, including a reconnect storm. If that is too loud for
|
|
1606
1634
|
your reporter, gate it in the subscriber — which failures are worth an event is
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# What's new in 0.
|
|
1
|
+
# What's new in 0.62.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,54 +9,14 @@ BREAKING entries name a codemod; run `voltro update` to apply it.
|
|
|
9
9
|
|
|
10
10
|
### ⚠ BREAKING
|
|
11
11
|
|
|
12
|
-
- **@voltro/
|
|
12
|
+
- **@voltro/workflow, @voltro/cli, @voltro/voltro** — `timeouts.finish` now filters running rows by the declared workflow, durably cancels each run before notification, and emits `onFailure` only for the successful terminal transition. Finish-timeout reports carry the run's stable `runId`, `executionId`, and original payload; handler-start logs expose the returned status instead of unconditionally claiming a new start.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
27
|
-
|
|
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.
|
|
29
|
-
|
|
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).
|
|
14
|
+
Low-level adapters that construct `AdmissionDrainDeps` must update `cancelRun` to accept the run object and return whether it made the terminal transition, and return the run identity, workflow name, and payload from `listRunningRuns`. Ordinary workflow declarations need no source change; `voltro update` prints the adapter migration only when the project references this low-level surface.
|
|
31
15
|
|
|
32
16
|
### Added
|
|
33
17
|
|
|
34
|
-
- **@voltro/
|
|
35
|
-
|
|
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.
|
|
37
|
-
|
|
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.
|
|
39
|
-
|
|
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.
|
|
41
|
-
|
|
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.
|
|
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.
|
|
18
|
+
- **@voltro/ai** — `streamText` and `resumableStreamText` now accept an opt-in `smooth` configuration for word- or line-based text and reasoning chunks. Smoothing runs before resumable journaling, preserves provider-native behavior when omitted, and shares the stream abort signal so cancellation also stops a pending smoothing delay.
|
|
47
19
|
|
|
48
20
|
### Fixed
|
|
49
21
|
|
|
50
|
-
- **@voltro/
|
|
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.
|
|
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:
|
|
57
|
-
|
|
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.
|
|
59
|
-
|
|
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.
|
|
61
|
-
|
|
62
|
-
Verified against a real `voltro serve` under `NODE_ENV=production`: 35 records, zero framework lines that are not JSON.
|
|
22
|
+
- **@voltro/web** — Production `framework_debug` now enables local framework diagnostics without opening browser-to-inspect HTTP or SSE transports. Development log relays are single-flight and rate-limited, classify permanent response failures, back off transient failures, expose dropped-log counts, and open a page-scoped circuit after repeated failure; the SSE relay also probes the endpoint before creating an `EventSource` and closes failed sources before retrying.
|
|
@@ -1459,7 +1459,7 @@ timeouts: { start: '1 hour', finish: '10 minutes' }
|
|
|
1459
1459
|
- **`start`** bounds how long a start may sit in the admission queue, measured from the **first** arrival in its group. A debounced run that never gets a quiet moment is a job that silently did not happen.
|
|
1460
1460
|
- **`finish`** bounds the run itself once admitted, and also tightens the crash backstop on its concurrency slot.
|
|
1461
1461
|
|
|
1462
|
-
Both
|
|
1462
|
+
Both reach the same `onFailure` signal as an exhausted retry. `timeouts.start` removes the queued intent before a run exists. `timeouts.finish` durably changes the running row to `cancelled`; only the sweep call that wins that terminal transition emits `onFailure`. Seeing the same old row again does not emit another report. Declaring `timeouts.start` on a workflow that cannot defer is a boot error — it would never fire.
|
|
1463
1463
|
|
|
1464
1464
|
## onFailure — the signal that replaces the sweep
|
|
1465
1465
|
|
|
@@ -1494,10 +1494,15 @@ export const narrationFailed = workflow({
|
|
|
1494
1494
|
failedAt: Schema.Number,
|
|
1495
1495
|
}),
|
|
1496
1496
|
success: Schema.Void,
|
|
1497
|
-
idempotencyKey: ({ runId, failedAt }) =>
|
|
1497
|
+
idempotencyKey: ({ workflow, runId, failedAt }) =>
|
|
1498
|
+
runId === null ? `failed-before-run:${workflow}:${failedAt}` : `failed-run:${runId}`,
|
|
1498
1499
|
})
|
|
1499
1500
|
```
|
|
1500
1501
|
|
|
1502
|
+
For failures of an existing run — including `timeouts.finish` — `runId`, `executionId`, and the original `payload` are populated. Use `runId` as the stable idempotency identity. Pre-run failures (`timeouts.start` and a queued start whose workflow was removed) have both IDs set to `null`; they are emitted once when their durable pending row is consumed.
|
|
1503
|
+
|
|
1504
|
+
The framework logs the result of starting the handler as `workflow onFailure start resolved`. Its metadata includes `startStatus`, `handlerRunId`, and `handlerExecutionId`, so a queued, dropped, or singleton-skipped start is not mislabeled as newly started.
|
|
1505
|
+
|
|
1501
1506
|
There is no `onFailure` for an `onFailure` — a handler that fails is logged and not re-notified, because the alternative is one run per failure per level with no floor.
|
|
1502
1507
|
|
|
1503
1508
|
## encryptSteps
|