@voltro/cli 0.58.0 → 0.59.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 +55 -0
- package/dist/apiBuild-B9OvhITV.js +2 -0
- package/dist/{apiBuild-CkpsCqIu.js → apiBuild-BU5cd-Fn.js} +50 -48
- package/dist/bin.js +1 -1
- package/dist/{build-51qBWfYY.js → build-uRMZrT8z.js} +338 -253
- package/dist/{checkCommand-C1EbNmwl.js → checkCommand-C1CQc8lD.js} +1 -1
- package/dist/{checkCommand-C30J2F18.js → checkCommand-DC7k1_hP.js} +1 -1
- package/dist/{codemodRunner-BKjCwGiN.js → codemodRunner-kNnh1I7_.js} +474 -390
- package/dist/{commands-DowWkYtd.js → commands-cu34ENUT.js} +10 -10
- package/dist/{doctorCommand-5ULMpL10.js → doctorCommand-CGjefPmk.js} +2 -2
- package/dist/doctorCommand-DXnNpKQT.js +2 -0
- package/dist/{evolveCommand-DTawtTxf.js → evolveCommand-8CuFBlbQ.js} +2 -2
- package/dist/index.js +1 -1
- package/dist/{infoCommand-BFksHunl.js → infoCommand-D02A4WI2.js} +1 -1
- package/dist/{runtimeTrace-BUk5zMXY.js → runtimeTrace-DDuKJgVi.js} +1 -1
- package/dist/{sdkgen-CAhmmbjx.js → sdkgen-vq1fF9D_.js} +1 -1
- package/dist/serveCommand-1R52mo6F.js +2 -0
- package/dist/{serveCommand-DhtC7WBq.js → serveCommand-Dr4KXmTS.js} +1 -1
- package/dist/serveEntry.js +1 -1
- package/dist/{updateCommand-CtuD5r1t.js → updateCommand-Bw3mCUDT.js} +1 -1
- package/dist/updateCommand-inInBIAh.js +2 -0
- package/package.json +31 -19
- package/templates/AGENTS.md +1 -1
- package/templates/agent-docs/_index.md +1 -1
- package/templates/agent-docs/ai.md +50 -1
- package/templates/agent-docs/cli.md +7 -6
- package/templates/agent-docs/plugins/sentry.md +54 -15
- package/templates/agent-docs/whats-new.md +24 -170
- 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-CDE4NXNi.js +0 -2
- package/dist/doctorCommand-B8H2MYCE.js +0 -2
- package/dist/serveCommand-BUXUtSF5.js +0 -2
- package/dist/updateCommand-eVKVHj3N.js +0 -2
|
@@ -121,7 +121,7 @@ var u = () => {
|
|
|
121
121
|
name: "check",
|
|
122
122
|
summary: "Verify the app graph (blast-radius checks) against a running api; LLM-shaped --json diagnostics. Flags: --json, --process <p>, --diff removeTable:<name>.",
|
|
123
123
|
status: "wired",
|
|
124
|
-
run: (e) => import("./checkCommand-
|
|
124
|
+
run: (e) => import("./checkCommand-C1CQc8lD.js").then((t) => t.runCheckCommand(e)),
|
|
125
125
|
help: {
|
|
126
126
|
usage: "[--json] [--offline] [--process <name>] [--diff removeTable:<name>]",
|
|
127
127
|
flags: [
|
|
@@ -171,7 +171,7 @@ var u = () => {
|
|
|
171
171
|
name: "evolve",
|
|
172
172
|
summary: "Schema-evolution copilot: propose an observed-graph-driven codemod + a branch-verified backfill for a schema change (rename/retype/split/drop a column, rename a table). Dry-run by default; --write applies. Usage: voltro evolve rename-column <table>.<col> --to <newName> [--write] [--json].",
|
|
173
173
|
status: "wired",
|
|
174
|
-
run: (e) => import("./evolveCommand-
|
|
174
|
+
run: (e) => import("./evolveCommand-8CuFBlbQ.js").then((t) => t.runEvolveCommand(e)),
|
|
175
175
|
help: {
|
|
176
176
|
usage: "<rename-column|rename-table|retype-column|split-column|drop-column> <target> [--to <new>] [--write]",
|
|
177
177
|
flags: [
|
|
@@ -281,7 +281,7 @@ var u = () => {
|
|
|
281
281
|
name: "info",
|
|
282
282
|
summary: "Report versions (CLI, node, every installed @voltro/* — flags lockstep skew), package manager, and dialect. --json for CI. Exits 1 on version skew.",
|
|
283
283
|
status: "wired",
|
|
284
|
-
run: (e) => import("./infoCommand-
|
|
284
|
+
run: (e) => import("./infoCommand-D02A4WI2.js").then((t) => t.runInfoCommand(e)),
|
|
285
285
|
help: {
|
|
286
286
|
usage: "[--json]",
|
|
287
287
|
flags: [["--json", "machine-readable report"]],
|
|
@@ -331,12 +331,12 @@ var u = () => {
|
|
|
331
331
|
run: async (e) => {
|
|
332
332
|
let t = e.find((e) => !e.startsWith("-")) ?? process.cwd();
|
|
333
333
|
if (e.includes("--preflight")) {
|
|
334
|
-
let { runServePreflight: e } = await import("./doctorCommand-
|
|
334
|
+
let { runServePreflight: e } = await import("./doctorCommand-DXnNpKQT.js");
|
|
335
335
|
return e(s(t), !0);
|
|
336
336
|
}
|
|
337
337
|
let { tryRunWebServe: n } = await import("./webDev-Bzb8ZFus.js"), r = await n(s(t));
|
|
338
338
|
if (!r.ran) {
|
|
339
|
-
let { runServeDispatch: t } = await import("./serveCommand-
|
|
339
|
+
let { runServeDispatch: t } = await import("./serveCommand-1R52mo6F.js");
|
|
340
340
|
return t(e);
|
|
341
341
|
}
|
|
342
342
|
return r.exitCode;
|
|
@@ -364,13 +364,13 @@ var u = () => {
|
|
|
364
364
|
handlesHelp: !0,
|
|
365
365
|
summary: "Preflight an app for production: the precompiled serve bundle, hand-rolled primitives (naming the shipped one), @voltro/* version skew, executors with no access check, `.serverOnly()` leaks, and junction-FK gaps.",
|
|
366
366
|
status: "wired",
|
|
367
|
-
run: (e) => import("./doctorCommand-
|
|
367
|
+
run: (e) => import("./doctorCommand-DXnNpKQT.js").then((t) => t.runDoctorCommand(e))
|
|
368
368
|
},
|
|
369
369
|
{
|
|
370
370
|
name: "build",
|
|
371
371
|
summary: "Production build for a web app (vite build + per-page SSG pre-render).",
|
|
372
372
|
status: "wired",
|
|
373
|
-
run: (e) => import("./build-
|
|
373
|
+
run: (e) => import("./build-uRMZrT8z.js").then((t) => t.runBuildCommand(e)),
|
|
374
374
|
help: {
|
|
375
375
|
usage: "[app] [--target <t>]",
|
|
376
376
|
flags: [["--target <t>", "build target"], ["--report", "print what a visitor downloads: first load, chunks, server artefacts"]],
|
|
@@ -386,7 +386,7 @@ var u = () => {
|
|
|
386
386
|
name: "prune-runtime",
|
|
387
387
|
summary: "Trim a deployed web tree’s node_modules to the reachable runtime set (standalone image slimming).",
|
|
388
388
|
status: "wired",
|
|
389
|
-
run: (e) => import("./runtimeTrace-
|
|
389
|
+
run: (e) => import("./runtimeTrace-DDuKJgVi.js").then((t) => t.runPruneRuntimeCommand(e)),
|
|
390
390
|
hidden: !0
|
|
391
391
|
},
|
|
392
392
|
{
|
|
@@ -555,14 +555,14 @@ var u = () => {
|
|
|
555
555
|
handlesHelp: !0,
|
|
556
556
|
summary: "Upgrade the app to the latest framework: bump every @voltro/* dependency (across ALL workspace members, install once at the workspace root), then run the codemods shipped with the target version. Flags: --to <version>, --from <version>, --codemods-only, --dry-run, --force, --exact, --help. After: run `voltro db apply`.",
|
|
557
557
|
status: "wired",
|
|
558
|
-
run: (e) => import("./updateCommand-
|
|
558
|
+
run: (e) => import("./updateCommand-inInBIAh.js").then((t) => t.runUpdateCommand(e))
|
|
559
559
|
},
|
|
560
560
|
{
|
|
561
561
|
name: "_apply-codemods",
|
|
562
562
|
summary: "Internal: apply shipped codemods for a framework version jump (re-exec target of `voltro update`).",
|
|
563
563
|
status: "wired",
|
|
564
564
|
hidden: !0,
|
|
565
|
-
run: (e) => import("./updateCommand-
|
|
565
|
+
run: (e) => import("./updateCommand-inInBIAh.js").then((t) => t.runApplyCodemods(e))
|
|
566
566
|
},
|
|
567
567
|
{
|
|
568
568
|
name: "embeddings",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Xt as e, Yt as t, Zt as n } from "./dev-Ce2gEziv.js";
|
|
2
2
|
import { Bt as r, Ht as i, T as a, Ut as o, V as s, Vt as c, t as l, u } from "./webDev-CBN9KkyQ.js";
|
|
3
|
-
import { r as d, u as f } from "./apiBuild-
|
|
3
|
+
import { r as d, u as f } from "./apiBuild-BU5cd-Fn.js";
|
|
4
4
|
import { S as p } from "./frameworkTableAssembly-vfkzuzEo.js";
|
|
5
5
|
import { n as m } from "./pageConvention-CMpfDN6r.js";
|
|
6
6
|
import { n as h, r as g, t as ee } from "./cliOutput-D1tSBoRM.js";
|
|
@@ -2162,7 +2162,7 @@ var le = {
|
|
|
2162
2162
|
findings: []
|
|
2163
2163
|
});
|
|
2164
2164
|
try {
|
|
2165
|
-
let { offlineManifest: n, toInput: r } = await import("./checkCommand-
|
|
2165
|
+
let { offlineManifest: n, toInput: r } = await import("./checkCommand-C1CQc8lD.js"), { buildAppGraph: i, checkAppGraph: a } = await import("./appGraph-CFmFKHb2.js"), o = await n(e), s = r(o.manifest, o.tables), c = await zn(e), l = [.../* @__PURE__ */ new Set([...s.scopes ?? [], ...c])];
|
|
2166
2166
|
if (l.length === 0) {
|
|
2167
2167
|
try {
|
|
2168
2168
|
let { loadAppSchemaInputs: t } = await import("./frameworkTableAssembly-B96WCNJA.js");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { n as e } from "./cliOutput-D1tSBoRM.js";
|
|
2
|
-
import { i as t } from "./checkCommand-
|
|
3
|
-
import { i as n, n as r } from "./codemodRunner-
|
|
2
|
+
import { i as t } from "./checkCommand-DC7k1_hP.js";
|
|
3
|
+
import { i as n, n as r } from "./codemodRunner-kNnh1I7_.js";
|
|
4
4
|
import { basename as i, join as a, resolve as o } from "node:path";
|
|
5
5
|
import { branchNamespaceName as s, planBranchProvision as c } from "@voltro/database";
|
|
6
6
|
import { readFile as l } from "node:fs/promises";
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e, r as t, t as n } from "./cliOutput-D1tSBoRM.js";
|
|
2
|
-
import { o as r } from "./updateCommand-
|
|
2
|
+
import { o as r } from "./updateCommand-Bw3mCUDT.js";
|
|
3
3
|
import { join as i, resolve as a } from "node:path";
|
|
4
4
|
import { readFileSync as o, readdirSync as s, statSync as c } from "node:fs";
|
|
5
5
|
//#region src/infoCommand.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as e } from "./apiBuild-
|
|
1
|
+
import { n as e } from "./apiBuild-BU5cd-Fn.js";
|
|
2
2
|
import { join as t, resolve as n, sep as r } from "node:path";
|
|
3
3
|
import { existsSync as i, promises as a } from "node:fs";
|
|
4
4
|
import { createLogger as o } from "@voltro/logger";
|
|
@@ -422,7 +422,7 @@ let package = Package(
|
|
|
422
422
|
await l.mkdir(o(e), { recursive: !0 }), await l.writeFile(e, n.content, "utf8");
|
|
423
423
|
}
|
|
424
424
|
}, X = async (e) => {
|
|
425
|
-
let { offlineManifest: t } = await import("./checkCommand-
|
|
425
|
+
let { offlineManifest: t } = await import("./checkCommand-C1CQc8lD.js"), { manifest: n } = await t(e);
|
|
426
426
|
return n;
|
|
427
427
|
}, Z = async (e) => {
|
|
428
428
|
let t = J(await (e.manifestProvider ?? X)(e.root), {
|
|
@@ -9,7 +9,7 @@ import { Yt as sn, en as cn, ft as ln, ht as un, lt as dn, mt as fn, pt as pn, q
|
|
|
9
9
|
import { g as hn, s as gn } from "./inspect-PcC5J-Dl.js";
|
|
10
10
|
import { n as _n } from "./cliArgs-D4p8n7EE.js";
|
|
11
11
|
import { r as vn } from "./appPort-B_HpJ_ck.js";
|
|
12
|
-
import { r as yn, u as bn } from "./apiBuild-
|
|
12
|
+
import { r as yn, u as bn } from "./apiBuild-BU5cd-Fn.js";
|
|
13
13
|
import { r as xn } from "./dialectDriver-czCHYpeH.js";
|
|
14
14
|
import { i as Sn, n as Cn } from "./connectionConfig-Bk9IC7D0.js";
|
|
15
15
|
import { c as wn, n as Tn, o as En } from "./seedRunner-DISBKow-.js";
|
package/dist/serveEntry.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-kNnh1I7_.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.59.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",
|
|
@@ -844,6 +844,18 @@
|
|
|
844
844
|
"title": "rerank reaches the gateway through a ProviderConfig",
|
|
845
845
|
"kind": "manual"
|
|
846
846
|
},
|
|
847
|
+
{
|
|
848
|
+
"version": "0.59.0",
|
|
849
|
+
"id": "0.59.0/01_sourcemaps_moved_to_the_top_level",
|
|
850
|
+
"title": "`web.sourcemaps` moved to the top level of app.config.ts",
|
|
851
|
+
"kind": "transform"
|
|
852
|
+
},
|
|
853
|
+
{
|
|
854
|
+
"version": "0.59.0",
|
|
855
|
+
"id": "0.59.0/02_costsource_gained_unpriced",
|
|
856
|
+
"title": "`costSource` gained `unpriced`, and AI usage is counted in a unit",
|
|
857
|
+
"kind": "manual"
|
|
858
|
+
},
|
|
847
859
|
{
|
|
848
860
|
"version": "0.6.0",
|
|
849
861
|
"id": "0.6.0/01_no-dev-session-secret",
|
|
@@ -926,24 +938,24 @@
|
|
|
926
938
|
"@effect/platform-node": "^0.108.0",
|
|
927
939
|
"@effect/sql": "^0.52.0",
|
|
928
940
|
"@effect/workflow": "^0.19.0",
|
|
929
|
-
"@voltro/ai": "0.
|
|
930
|
-
"@voltro/cache": "0.
|
|
931
|
-
"@voltro/client": "0.
|
|
932
|
-
"@voltro/content": "0.
|
|
933
|
-
"@voltro/data-transfer": "0.
|
|
934
|
-
"@voltro/database": "0.
|
|
935
|
-
"@voltro/env": "0.
|
|
936
|
-
"@voltro/kv": "0.
|
|
937
|
-
"@voltro/logger": "0.
|
|
938
|
-
"@voltro/plugin-auth": "0.
|
|
939
|
-
"@voltro/plugin-broadcast": "0.
|
|
940
|
-
"@voltro/plugin-mail": "0.
|
|
941
|
-
"@voltro/plugin-storage": "0.
|
|
942
|
-
"@voltro/plugin-webhooks": "0.
|
|
943
|
-
"@voltro/protocol": "0.
|
|
944
|
-
"@voltro/runtime": "0.
|
|
945
|
-
"@voltro/serverless": "0.
|
|
946
|
-
"@voltro/workflow": "0.
|
|
941
|
+
"@voltro/ai": "0.59.0",
|
|
942
|
+
"@voltro/cache": "0.59.0",
|
|
943
|
+
"@voltro/client": "0.59.0",
|
|
944
|
+
"@voltro/content": "0.59.0",
|
|
945
|
+
"@voltro/data-transfer": "0.59.0",
|
|
946
|
+
"@voltro/database": "0.59.0",
|
|
947
|
+
"@voltro/env": "0.59.0",
|
|
948
|
+
"@voltro/kv": "0.59.0",
|
|
949
|
+
"@voltro/logger": "0.59.0",
|
|
950
|
+
"@voltro/plugin-auth": "0.59.0",
|
|
951
|
+
"@voltro/plugin-broadcast": "0.59.0",
|
|
952
|
+
"@voltro/plugin-mail": "0.59.0",
|
|
953
|
+
"@voltro/plugin-storage": "0.59.0",
|
|
954
|
+
"@voltro/plugin-webhooks": "0.59.0",
|
|
955
|
+
"@voltro/protocol": "0.59.0",
|
|
956
|
+
"@voltro/runtime": "0.59.0",
|
|
957
|
+
"@voltro/serverless": "0.59.0",
|
|
958
|
+
"@voltro/workflow": "0.59.0",
|
|
947
959
|
"chokidar": "^5.0.0",
|
|
948
960
|
"ioredis": "^5.11.1",
|
|
949
961
|
"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.59.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.59.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. |
|
|
@@ -185,6 +185,20 @@ const usable = models.filter(canExecute).filter((m) => m.capabilities?.vision)
|
|
|
185
185
|
|
|
186
186
|
Each entry adds `capabilities`, `modalities`, `contextWindow`, `maxOutputTokens`, `releasedAt`, `knowledgeCutoff` and `dataPolicy`.
|
|
187
187
|
|
|
188
|
+
Plus **`raw`** — the entry exactly as it came over the wire.
|
|
189
|
+
|
|
190
|
+
The normalised fields are the shared answer to the questions every app on the gateway asks. `raw` is for the ones only one app asks: a chips row built from the vendor's own `tags`, a pricing display that shows a structure we have not normalised, `zdr` and `no_training` kept apart instead of folded into `dataPolicy`.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
const models = await readGatewayCatalog({ modality: 'language' })
|
|
194
|
+
const chips = models[0]?.raw?.tags // vendor's own vocabulary
|
|
195
|
+
const audioRate = (models[0]?.raw?.pricing as { audio_per_second?: string })?.audio_per_second
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
Without it, an app with its own display fetches `/v1/models` a second time and keeps a second parser of the same response — and then has to decide again, at every field the gateway adds, whether to wait for a framework release. That is the decision `raw` removes, which is why it is one field rather than three more normalised ones.
|
|
199
|
+
|
|
200
|
+
It is absent on the injected-provider path (the seam a test uses), for the same reason `capabilities` is: that path never saw a response, and an empty object would turn "no wire data" into the claim "the wire carried nothing".
|
|
201
|
+
|
|
188
202
|
`capabilities` is **unioned from three fields that each half-say it** — `tags`, `supported_parameters` and `modalities` — because they overlap and regularly disagree: a model tagged `reasoning` does not always carry the parameter, and the other way round. Taking either alone produces a false negative, and a false "cannot" removes a model from a picker with no way for anyone to find out why. That union is framework knowledge; without it every app writes the same forty lines, differently.
|
|
189
203
|
|
|
190
204
|
`dataPolicy` carries `zeroRetention` and `noTraining` (`'all' | 'some' | 'none'`). They decide whether a model may see customer text, and an unreadable value reads as `'none'` — the question is "may this", and an unparseable answer is not a yes.
|
|
@@ -2589,7 +2603,42 @@ yield* generateSpeech({ text, provider: { name: 'elevenlabs', model: 'eleven_tur
|
|
|
2589
2603
|
|
|
2590
2604
|
This ships **no** adapters, on purpose: bundling an ElevenLabs client would put the framework in the business of tracking somebody else's REST API, and the app already has the adapter. What the app deletes is its dispatch, not its adapters.
|
|
2591
2605
|
|
|
2592
|
-
A registered provider receives every option the primitive already had — `voice`, `outputFormat`, `speed`, `language`, `instructions`, `providerOptions` — or the seam would be a narrower primitive wearing the same name.
|
|
2606
|
+
A registered provider receives every option the primitive already had — `voice`, `outputFormat`, `speed`, `language`, `instructions`, `providerOptions` — or the seam would be a narrower primitive wearing the same name.
|
|
2607
|
+
|
|
2608
|
+
#### Taking over a built-in name
|
|
2609
|
+
|
|
2610
|
+
`mock`, `openai`, `gateway` and `anthropic` resolve without a registration, and shadowing one by accident would make the same config mean different things depending on which module loaded first. So it takes a flag:
|
|
2611
|
+
|
|
2612
|
+
```ts
|
|
2613
|
+
registerSpeechProvider('openai', myOpenAiTts, { replaceBuiltin: true })
|
|
2614
|
+
```
|
|
2615
|
+
|
|
2616
|
+
The flag exists because a provider name is not always an alias you choose. `openai` is the value the gateway puts in its model ids, so it is what a stored catalog's rows carry and what a picker submits — an app told to pick another name cannot, without rewriting persisted rows and live sessions. Refusing outright did not protect that app; it made it keep its own dispatch for every provider, not just the colliding one.
|
|
2617
|
+
|
|
2618
|
+
What the refusal was protecting is kept: the intent is now in the call, so an override is a decision someone wrote down rather than an accident of load order. Registered providers are resolved **before** built-ins — otherwise the flag would let you register a name and never reach it.
|
|
2619
|
+
|
|
2620
|
+
### Cost — speech is not billed in tokens
|
|
2621
|
+
|
|
2622
|
+
`generateSpeech` never records a ledger row itself; it returns `usage` and you pass it to `recordAiUsage`, the same as `generateText`. The difference is the unit. Every speech vendor meters characters of input or seconds of audio, so a `usage` shape that only knew tokens could not hold the call at all — speech spend was not un-priced, it was **absent**.
|
|
2623
|
+
|
|
2624
|
+
A registered provider returns a `MeteredUsage`:
|
|
2625
|
+
|
|
2626
|
+
```ts
|
|
2627
|
+
synthesize: (request) => Effect.succeed({
|
|
2628
|
+
audio,
|
|
2629
|
+
usage: { unit: 'characters', input: request.text.length },
|
|
2630
|
+
})
|
|
2631
|
+
```
|
|
2632
|
+
|
|
2633
|
+
```ts
|
|
2634
|
+
yield* recordAiUsage(store, {
|
|
2635
|
+
provider: 'elevenlabs', model: 'eleven_turbo_v3', operation: 'generateSpeech',
|
|
2636
|
+
usage: { unit: 'characters', input: 4200 },
|
|
2637
|
+
price: { inputPer1M: 30, outputPer1M: 0 }, // your rate, in your unit
|
|
2638
|
+
})
|
|
2639
|
+
```
|
|
2640
|
+
|
|
2641
|
+
The ledger row carries `unit` beside the two counts. **A non-token unit is never priced by the token table**: without a `price` or an `actualCostUsd` the row is written `costSource: 'unpriced'` with the real count and a zero cost, because a per-1M-token rate applied to a character count produces a number indistinguishable from a real one. Sum the count columns grouped by `unit`, never across it.
|
|
2593
2642
|
|
|
2594
2643
|
## As a durable step — `transcribeStep`
|
|
2595
2644
|
|
|
@@ -1455,13 +1455,14 @@ web: {
|
|
|
1455
1455
|
// `dist/assets/` to the prefix on deploy. Filenames are content-hashed, so a
|
|
1456
1456
|
// previous deploy's assets stay valid for a visitor mid-navigation.
|
|
1457
1457
|
assetPrefix: 'https://cdn.example.com/_assets',
|
|
1458
|
-
|
|
1459
|
-
// Emit `.map` files WITHOUT a `//# sourceMappingURL` comment, so nothing in
|
|
1460
|
-
// the shipped JS points at them. For `plugin-sentry`: upload them in your
|
|
1461
|
-
// deploy step and DELETE them before the image is built. `voltro start`
|
|
1462
|
-
// refuses to serve a `.map` regardless, so a forgotten delete is not a leak.
|
|
1463
|
-
sourcemaps: 'hidden',
|
|
1464
1458
|
},
|
|
1459
|
+
|
|
1460
|
+
// Top level, NOT under `web:` — it covers every bundle the build minifies
|
|
1461
|
+
// (browser, SSR, start, and an api app's serve bundle). Emits `.map` files with
|
|
1462
|
+
// no `//# sourceMappingURL` comment, so nothing shipped points at them.
|
|
1463
|
+
// `plugin-sentry` can upload and sweep them for you; `voltro start` refuses to
|
|
1464
|
+
// serve a `.map` regardless, so a forgotten delete is not a leak.
|
|
1465
|
+
sourcemaps: 'hidden',
|
|
1465
1466
|
http: {
|
|
1466
1467
|
// Node hangs up an idle keep-alive connection after 5s; every proxy in front
|
|
1467
1468
|
// holds one longer, and the request that lands in that window comes back as
|
|
@@ -161,17 +161,15 @@ The two halves are independent: the api plugin alone gives you server traces + e
|
|
|
161
161
|
|
|
162
162
|
**Traces default to on, at `tracesSampleRate: 1.0`.** That is the coherent default rather than a generous one: the browser half already sampled every page load, navigation and rpc call at 1.0, so with the api half off each of those spans was emitted, paid for, and belonged to a trace with no server side — a browser hop hanging off nothing. The rate is named on the boot line (`sentry active traces=true tracesSampleRate=1`) so a first boot shows what it is about to send; lower it with `tracesSampleRate`, or set `traces: false` to keep errors and breadcrumbs only.
|
|
163
163
|
|
|
164
|
-
## Source maps (browser
|
|
164
|
+
## Source maps (every bundle, browser and server)
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
Every bundle `voltro build` emits is minified, so an error arrives in Sentry with a **minified** stack trace unless the maps are uploaded. `voltro build` does it:
|
|
167
167
|
|
|
168
168
|
```ts
|
|
169
|
-
// app.config.ts
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
upload: { org: 'acme', project: 'web' },
|
|
174
|
-
},
|
|
169
|
+
// app.config.ts — top level, for a web app AND an api app
|
|
170
|
+
sourcemaps: {
|
|
171
|
+
mode: 'hidden',
|
|
172
|
+
upload: { org: 'acme', project: 'web' },
|
|
175
173
|
}
|
|
176
174
|
```
|
|
177
175
|
|
|
@@ -191,11 +189,9 @@ That emits the maps, uploads them through `@sentry/cli`, and then **removes them
|
|
|
191
189
|
`app.config.ts` is TypeScript, so the ordinary branch is the answer:
|
|
192
190
|
|
|
193
191
|
```ts
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
: 'hidden',
|
|
198
|
-
}
|
|
192
|
+
sourcemaps: process.env.CI
|
|
193
|
+
? { mode: 'hidden', upload: { org: 'acme', project: 'web' } }
|
|
194
|
+
: 'hidden',
|
|
199
195
|
```
|
|
200
196
|
|
|
201
197
|
`'hidden'` alone emits the maps and **keeps** them — right for reading a stack trace locally, and a leak in an image. Omit the field entirely and nothing is emitted, which is the default.
|
|
@@ -206,9 +202,52 @@ web: {
|
|
|
206
202
|
|
|
207
203
|
It is read from `SENTRY_AUTH_TOKEN` and there is deliberately no `authToken` option: `app.config.ts` is a committed file, and a token with `project:releases` scope can write to every project in the org. Give it to the **build** (a CI secret, a Docker build secret) — not to the deployment, since the upload happens while the bundle is being built.
|
|
208
204
|
|
|
209
|
-
**Install `@sentry/cli` yourself: `pnpm add -D @sentry/cli` in the
|
|
205
|
+
**Install `@sentry/cli` yourself: `pnpm add -D @sentry/cli` in the app being built.** The framework depends on it nowhere, and that is a licence decision rather than a packaging one — it is FSL-1.1-MIT, which restricts competing commercial use, so it must not sit in the dependency graph of a package we publish. A build with an upload configured and the package missing **refuses and names the command**, rather than skipping the upload and leaving you to find out months later that no frame resolves.
|
|
206
|
+
|
|
207
|
+
### It covers the server too — and that is what it was missing
|
|
208
|
+
|
|
209
|
+
An earlier version of this page said server traces were un-minified already and
|
|
210
|
+
that source maps were a browser-only concern. That was wrong about the built
|
|
211
|
+
artefact, and the correction is the reason the option moved to the top level.
|
|
212
|
+
|
|
213
|
+
`voltro build` minifies **four** bundles, not one: the browser bundle, the SSR
|
|
214
|
+
bundle, the `voltro start` bundle, and — for an api app — the precompiled entry
|
|
215
|
+
plus the serve bundle that `voltro serve` actually runs. `keepNames` rescues the
|
|
216
|
+
handful of identifiers that are read as strings (Effect tags, error `name`s) and
|
|
217
|
+
nothing else, so a frame out of the serve bundle reads:
|
|
218
|
+
|
|
219
|
+
```
|
|
220
|
+
at l (file:///…/serveBundle/serveEntry.js:79:51)
|
|
221
|
+
at Qo (file:///…/serveBundle/serveEntry.js:236:76405)
|
|
222
|
+
```
|
|
210
223
|
|
|
211
|
-
|
|
224
|
+
The server half is also where it hurts most. A schedule, a workflow step, a
|
|
225
|
+
subscriber or a REST route has no browser caller whose frame could stand in for
|
|
226
|
+
it — a workflow that dies at 03:30 in a cron is only what its stack trace says.
|
|
227
|
+
|
|
228
|
+
So `sourcemaps` is one field at the top level of `app.config.ts` and it covers
|
|
229
|
+
everything the build minifies. **It replaces `web.sourcemaps`**, which reached
|
|
230
|
+
only the browser bundle; the build refuses the old spelling rather than ignoring
|
|
231
|
+
it, and `voltro update` moves it for you.
|
|
232
|
+
|
|
233
|
+
Two details worth knowing before the first upload:
|
|
234
|
+
|
|
235
|
+
- **Each output directory is uploaded under the prefix that matches how its
|
|
236
|
+
files are named.** `dist/assets` is fetched by a browser under `~/assets`; the
|
|
237
|
+
SSR, start and serve bundles are files a node process loaded and go up under
|
|
238
|
+
`~/`. Set `upload.urlPrefix` only if you know your project needs one value for
|
|
239
|
+
both.
|
|
240
|
+
- **`node:*-slim` images have no CA certificates.** `/etc/ssl/certs` is empty and
|
|
241
|
+
the `ca-certificates` package is not installed. Node carries its own roots, so
|
|
242
|
+
nothing in JS notices — but `sentry-cli` is a Rust binary that uses the system
|
|
243
|
+
store, and it fails with `SSL peer certificate … unable to get local issuer
|
|
244
|
+
certificate`. Add `ca-certificates` to the build stage.
|
|
245
|
+
|
|
246
|
+
**What we have not measured:** how a given Sentry project resolves the uploaded
|
|
247
|
+
artifacts end to end. `sentry-cli sourcemaps upload` matches on debug IDs it
|
|
248
|
+
injects into the emitted JS, and the URL prefix is the older release-artifact
|
|
249
|
+
fallback — which is why the prefix is set correctly per directory rather than
|
|
250
|
+
left to one default, and why this paragraph is here instead of a claim.
|
|
212
251
|
|
|
213
252
|
## Catching errors — what's automatic, what's manual
|
|
214
253
|
|