@voltro/cli 0.12.0 → 0.13.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.
Files changed (85) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/dist/{apiBuild-GefjNI5d.js → apiBuild-B6_ehbem.js} +3 -3
  3. package/dist/apiBuild-Bzpb383i.js +2 -0
  4. package/dist/bin.js +3 -3
  5. package/dist/{commands-BmNi1RgZ.js → commands-DYOuGlEC.js} +1668 -1371
  6. package/dist/dbCommand-ADD4mrTI.js +2 -0
  7. package/dist/{dbCommand-DNrkb58g.js → dbCommand-DIOJQwsq.js} +71 -57
  8. package/dist/{dev-d0LjACxE.js → dev-Fb9BmavX.js} +1483 -1414
  9. package/dist/dev-xdijqojc.js +3 -0
  10. package/dist/{seedRunner-DZmhoqNt.js → frameworkTableAssembly-CYlrafoK.js} +110 -331
  11. package/dist/frameworkTableAssembly-XvKO7wQt.js +2 -0
  12. package/dist/index.js +1 -1
  13. package/dist/{inspectMetrics-uEfIS1vp.js → inspectMetrics-DOiiII34.js} +302 -293
  14. package/dist/seedRunner-D6eu-u5U.js +229 -0
  15. package/dist/{serveCommand-B2-YV9TU.js → serveCommand-CqYxzBZR.js} +368 -367
  16. package/dist/serveEntry.js +3 -3
  17. package/dist/{start-DKcQd52a.js → start-CjG_0xhR.js} +1 -1
  18. package/dist/startEntry.js +2 -2
  19. package/package.json +17 -17
  20. package/templates/AGENTS.md +1 -1
  21. package/templates/agent-docs/_index.md +1 -1
  22. package/templates/agent-docs/authentication.md +36 -0
  23. package/templates/agent-docs/cli.md +78 -4
  24. package/templates/agent-docs/configuration.md +48 -0
  25. package/templates/agent-docs/database/migrations.md +32 -0
  26. package/templates/agent-docs/database/transactions.md +31 -0
  27. package/templates/agent-docs/testing.md +24 -0
  28. package/templates/agent-docs/whats-new.md +41 -137
  29. package/templates/apps/api-ai/package.json +7 -7
  30. package/templates/apps/api-auth/package.json +8 -8
  31. package/templates/apps/api-backend/package.json +7 -7
  32. package/templates/apps/api-backend-deactivation/package.json +7 -7
  33. package/templates/apps/api-backend-deactivation/tests/users.deactivate.test.ts +1 -1
  34. package/templates/apps/api-backend-mail/package.json +8 -8
  35. package/templates/apps/api-backend-mariadb/package.json +9 -9
  36. package/templates/apps/api-backend-storage/package.json +8 -8
  37. package/templates/apps/api-data-advanced/package.json +8 -8
  38. package/templates/apps/api-data-advanced/tests/queries.test.ts +6 -1
  39. package/templates/apps/api-durable/package.json +8 -8
  40. package/templates/apps/api-feature-flags/package.json +9 -9
  41. package/templates/apps/api-governance/app.config.ts +0 -1
  42. package/templates/apps/api-governance/package.json +8 -8
  43. package/templates/apps/api-kv/package.json +8 -8
  44. package/templates/apps/api-kv/tests/sync.test.ts +2 -2
  45. package/templates/apps/api-moderation/package.json +8 -8
  46. package/templates/apps/api-observability/package.json +8 -8
  47. package/templates/apps/api-ratelimit/package.json +8 -8
  48. package/templates/apps/api-rbac/README.md +53 -14
  49. package/templates/apps/api-rbac/app.config.ts +24 -26
  50. package/templates/apps/api-rbac/authz.ts +76 -0
  51. package/templates/apps/api-rbac/database/schema.ts +23 -6
  52. package/templates/apps/api-rbac/mutations/notes.create.mutation.server.ts +7 -5
  53. package/templates/apps/api-rbac/mutations/notes.create.mutation.ts +15 -8
  54. package/templates/apps/api-rbac/mutations/notes.delete.mutation.server.ts +54 -0
  55. package/templates/apps/api-rbac/mutations/notes.delete.mutation.ts +43 -0
  56. package/templates/apps/api-rbac/mutations/teams.rename.mutation.server.ts +19 -0
  57. package/templates/apps/api-rbac/mutations/teams.rename.mutation.ts +37 -0
  58. package/templates/apps/api-rbac/package.json +8 -8
  59. package/templates/apps/api-rbac/queries/notes.list.query.server.ts +12 -0
  60. package/templates/apps/api-rbac/queries/notes.list.query.ts +26 -0
  61. package/templates/apps/api-rbac/template.json +2 -2
  62. package/templates/apps/api-rbac/tests/authz.test.ts +233 -0
  63. package/templates/apps/api-rest/package.json +7 -7
  64. package/templates/apps/api-saas/package.json +11 -11
  65. package/templates/apps/api-search/package.json +8 -8
  66. package/templates/apps/api-versioning/package.json +8 -8
  67. package/templates/apps/api-webhooks/package.json +9 -8
  68. package/templates/apps/changelog/package.json +6 -6
  69. package/templates/apps/edge-functions/package.json +2 -2
  70. package/templates/apps/frontend-admin/package.json +8 -8
  71. package/templates/apps/frontend-app/package.json +8 -8
  72. package/templates/apps/frontend-blank/package.json +7 -7
  73. package/templates/apps/frontend-contact/package.json +7 -7
  74. package/templates/apps/frontend-dashboard/package.json +7 -7
  75. package/templates/apps/frontend-docs/package.json +7 -7
  76. package/templates/apps/frontend-i18n/package.json +6 -6
  77. package/templates/apps/frontend-landing/package.json +7 -7
  78. package/templates/apps/frontend-spa/package.json +7 -7
  79. package/templates/apps/frontend-ssr/package.json +7 -7
  80. package/templates/apps/frontend-ssr-api/package.json +8 -8
  81. package/templates/apps/frontend-static-blog/package.json +6 -6
  82. package/dist/apiBuild-s7swuEU5.js +0 -2
  83. package/dist/dbCommand-Bt6BCG7g.js +0 -2
  84. package/dist/dev-YHbHmeXt.js +0 -3
  85. package/templates/apps/api-rbac/tests/notes.create.test.ts +0 -80
@@ -0,0 +1,229 @@
1
+ import { join as e } from "node:path";
2
+ import { pathToFileURL as t } from "node:url";
3
+ import { promises as n } from "node:fs";
4
+ import { createRequire as r } from "node:module";
5
+ import { _voltroSeedsTable as i, and as a, eq as o, generateId as s, isSeedDefinition as c } from "@voltro/database";
6
+ import { createHash as l } from "node:crypto";
7
+ //#region src/dialectDriver.ts
8
+ var u = {
9
+ postgres: "@voltro/sql-postgres",
10
+ sqlite: "@voltro/sql-sqlite",
11
+ mysql: "@voltro/sql-mysql",
12
+ mariadb: "@voltro/sql-mysql",
13
+ mssql: "@voltro/sql-mssql",
14
+ turso: "@voltro/sql-turso"
15
+ }, d = [...new Set(Object.values(u))], f = {
16
+ postgres: "postgresDialect",
17
+ sqlite: "sqliteDialect",
18
+ mysql: "mysqlDialect",
19
+ mariadb: "mariadbDialect",
20
+ mssql: "mssqlDialect",
21
+ turso: "tursoDialect"
22
+ }, p = /* @__PURE__ */ new Map(), m = (e, t) => {
23
+ p.set(e, t);
24
+ }, h = async (n) => {
25
+ let i = p.get(n);
26
+ if (i) return i;
27
+ try {
28
+ return await import(t(r(e(process.cwd(), "package.json")).resolve(n)).href);
29
+ } catch {
30
+ try {
31
+ return await import(n);
32
+ } catch {
33
+ throw Error(`The '${n}' database driver is not installed.\n\nEvery Voltro app declares the driver for its DB dialect as a dependency (a memory store needs none). Install it in the app:\n\n pnpm add ${n}\n`);
34
+ }
35
+ }
36
+ }, g = async (e) => {
37
+ let t = u[e];
38
+ if (!t) throw Error(`Unsupported DB_DIALECT='${e}'. Supported: memory, postgres, sqlite, mysql, mariadb, mssql, turso.`);
39
+ return (await h(t))[f[e]];
40
+ }, _ = async (e, r) => {
41
+ let i = [];
42
+ for (let a of e) {
43
+ let e;
44
+ try {
45
+ e = await import(t(a).href);
46
+ } catch (e) {
47
+ r.warn("seed: failed to import", { file: a }, e);
48
+ continue;
49
+ }
50
+ let o = (e.default && c(e.default) ? e.default : void 0) ?? Object.values(e).find(c);
51
+ if (!o) {
52
+ r.warn("seed: no defineSeed export", { file: a });
53
+ continue;
54
+ }
55
+ let s = await n.readFile(a, "utf8").catch(() => ""), u = o.fingerprint ? o.fingerprint({ src: s }) : l("sha256").update(s).digest("hex").slice(0, 16);
56
+ i.push({
57
+ file: a,
58
+ definition: o,
59
+ fingerprint: u
60
+ });
61
+ }
62
+ return i;
63
+ }, v = (e) => ({
64
+ query: (t) => e.query({
65
+ table: t.table,
66
+ order: t.order ?? [],
67
+ ...t.predicate ? { predicate: t.predicate } : {},
68
+ ...t.take === void 0 ? {} : { take: t.take },
69
+ ...t.skip === void 0 ? {} : { skip: t.skip },
70
+ ...t.projection ? { projection: t.projection } : {}
71
+ }),
72
+ insert: (t, n) => e.insert(t, n),
73
+ insertIgnore: (t, n, r) => e.insertIgnore(t, n, r),
74
+ update: (t, n, r) => e.update(t, n, r),
75
+ delete: (t, n) => e.delete(t, n)
76
+ }), y = (e) => async (t, n, r) => {
77
+ let i = Object.keys(n);
78
+ if (i.length === 0) throw Error("upsertByUnique: matchFields must have at least one key");
79
+ let s;
80
+ if (i.length === 1) {
81
+ let e = i[0];
82
+ s = o(e, n[e]);
83
+ } else s = a(...i.map((e) => o(e, n[e])));
84
+ let c = (await e.query({
85
+ table: t,
86
+ order: [],
87
+ predicate: s
88
+ }))[0];
89
+ if (c) {
90
+ let n = c.id;
91
+ return {
92
+ row: await e.update(t, n, r) ?? c,
93
+ created: !1
94
+ };
95
+ }
96
+ return {
97
+ row: await e.insert(t, r),
98
+ created: !0
99
+ };
100
+ }, b = (e, t) => {
101
+ let n = y(e);
102
+ return {
103
+ store: v(e),
104
+ upsertByUnique: n,
105
+ progress: (e, n) => t.debug("seed progress", {
106
+ done: e,
107
+ total: n
108
+ })
109
+ };
110
+ }, x = "_voltro_seeds", S = () => {
111
+ let e = i.fields.id?.idScheme;
112
+ return (e ? s(e, x) : null) ?? s({
113
+ kind: "typeid",
114
+ prefix: "seed"
115
+ }, x);
116
+ }, C = {
117
+ isUnchanged: () => !1,
118
+ record: async () => {}
119
+ }, w = async (e, t) => {
120
+ let n;
121
+ try {
122
+ n = await e.query({
123
+ table: x,
124
+ order: [],
125
+ predicate: void 0,
126
+ projection: void 0,
127
+ skip: void 0,
128
+ take: void 0
129
+ });
130
+ } catch (e) {
131
+ return t.warn("seeds: ledger unreadable — every boot seed will run", {
132
+ table: x,
133
+ error: String(e)
134
+ }), C;
135
+ }
136
+ let r = new Map(n.map((e) => [e.name, e]));
137
+ return {
138
+ isUnchanged: (e) => {
139
+ let t = r.get(e.definition.id);
140
+ return t?.lastRunStatus === "succeeded" && t.fingerprint === e.fingerprint;
141
+ },
142
+ record: async (n, i) => {
143
+ let a = {
144
+ name: n.definition.id,
145
+ lifecycle: n.definition.lifecycle,
146
+ fingerprint: n.fingerprint,
147
+ lastRunStatus: i.status,
148
+ lastRunAt: /* @__PURE__ */ new Date(),
149
+ lastRunDurationMs: i.durationMs,
150
+ lastRunRowsTouched: i.rowsTouched,
151
+ lastError: i.error?.message ?? null
152
+ };
153
+ try {
154
+ let t = r.get(n.definition.id);
155
+ t ? await e.update(x, t.id, a) : await e.insert(x, {
156
+ id: S(),
157
+ ...a
158
+ });
159
+ } catch (e) {
160
+ t.warn("seeds: could not record the ledger row — this seed will re-run on every boot", {
161
+ seedId: n.definition.id,
162
+ table: x,
163
+ error: String(e)
164
+ });
165
+ }
166
+ }
167
+ };
168
+ }, T = async (e, t, n) => {
169
+ let r = Date.now(), i = b(t, n), a = 0;
170
+ for (let t of e.definition.steps) try {
171
+ let e = await t.body(i);
172
+ e && typeof e.rowsTouched == "number" && (a += e.rowsTouched);
173
+ } catch (i) {
174
+ let o = i;
175
+ return n.error(`seed "${e.definition.id}" failed at step "${t.name}"`, {
176
+ seedId: e.definition.id,
177
+ step: t.name
178
+ }, o), {
179
+ seedId: e.definition.id,
180
+ status: "failed",
181
+ durationMs: Date.now() - r,
182
+ rowsTouched: a,
183
+ error: {
184
+ message: o.message,
185
+ ...o.stack ? { stack: o.stack } : {},
186
+ stepName: t.name
187
+ }
188
+ };
189
+ }
190
+ return {
191
+ seedId: e.definition.id,
192
+ status: "succeeded",
193
+ durationMs: Date.now() - r,
194
+ rowsTouched: a
195
+ };
196
+ }, E = async (e, t, n, r = {}) => {
197
+ let i = e.filter((e) => e.definition.lifecycle === "boot");
198
+ if (i.length === 0) return [];
199
+ let a = await w(t, n), o = [], s = 0;
200
+ for (let e of i) {
201
+ if (!r.force && a.isUnchanged(e)) {
202
+ s++, n.debug(`seed "${e.definition.id}" unchanged — skipped`, { fingerprint: e.fingerprint }), o.push({
203
+ seedId: e.definition.id,
204
+ status: "skipped",
205
+ durationMs: 0,
206
+ rowsTouched: 0
207
+ });
208
+ continue;
209
+ }
210
+ let i = await T(e, t, n);
211
+ i.status === "succeeded" && n.info(`seed "${i.seedId}" applied`, {
212
+ durationMs: i.durationMs,
213
+ rowsTouched: i.rowsTouched,
214
+ fingerprint: e.fingerprint
215
+ }), await a.record(e, i), o.push(i);
216
+ }
217
+ return n.info("seeds: boot-lifecycle pass complete", {
218
+ ran: o.length - s,
219
+ skipped: s,
220
+ ...r.force ? { forced: !0 } : {}
221
+ }), o;
222
+ }, D = async (e, t, n, r) => {
223
+ let i = e.find((e) => e.definition.id === t);
224
+ if (!i) throw Error(`seed not found: ${t}`);
225
+ let a = await T(i, n, r);
226
+ return await (await w(n, r)).record(i, a), a;
227
+ }, O = /\.seed\.ts$/;
228
+ //#endregion
229
+ export { d as a, m as c, D as i, _ as n, h as o, E as r, g as s, O as t };