@mantajs/cli 0.2.0-beta.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 (282) hide show
  1. package/bin/manta.mjs +20 -0
  2. package/bin/manta.ts +13 -0
  3. package/dist/admin/generate-admin-config.d.ts +8 -0
  4. package/dist/admin/generate-admin-config.d.ts.map +1 -0
  5. package/dist/admin/generate-admin-config.js +127 -0
  6. package/dist/admin/generate-admin-config.js.map +1 -0
  7. package/dist/ai/chat-handler.d.ts +10 -0
  8. package/dist/ai/chat-handler.d.ts.map +1 -0
  9. package/dist/ai/chat-handler.js +1353 -0
  10. package/dist/ai/chat-handler.js.map +1 -0
  11. package/dist/bootstrap/boot.d.ts +25 -0
  12. package/dist/bootstrap/boot.d.ts.map +1 -0
  13. package/dist/bootstrap/boot.js +344 -0
  14. package/dist/bootstrap/boot.js.map +1 -0
  15. package/dist/bootstrap/bootstrap-app.d.ts +71 -0
  16. package/dist/bootstrap/bootstrap-app.d.ts.map +1 -0
  17. package/dist/bootstrap/bootstrap-app.js +308 -0
  18. package/dist/bootstrap/bootstrap-app.js.map +1 -0
  19. package/dist/bootstrap/bootstrap-context.d.ts +76 -0
  20. package/dist/bootstrap/bootstrap-context.d.ts.map +1 -0
  21. package/dist/bootstrap/bootstrap-context.js +4 -0
  22. package/dist/bootstrap/bootstrap-context.js.map +1 -0
  23. package/dist/bootstrap/bootstrap-helpers.d.ts +71 -0
  24. package/dist/bootstrap/bootstrap-helpers.d.ts.map +1 -0
  25. package/dist/bootstrap/bootstrap-helpers.js +373 -0
  26. package/dist/bootstrap/bootstrap-helpers.js.map +1 -0
  27. package/dist/bootstrap/generate-types.d.ts +7 -0
  28. package/dist/bootstrap/generate-types.d.ts.map +1 -0
  29. package/dist/bootstrap/generate-types.js +832 -0
  30. package/dist/bootstrap/generate-types.js.map +1 -0
  31. package/dist/bootstrap/phases/assemble/index.d.ts +5 -0
  32. package/dist/bootstrap/phases/assemble/index.d.ts.map +1 -0
  33. package/dist/bootstrap/phases/assemble/index.js +5 -0
  34. package/dist/bootstrap/phases/assemble/index.js.map +1 -0
  35. package/dist/bootstrap/phases/assemble/load-links.d.ts +3 -0
  36. package/dist/bootstrap/phases/assemble/load-links.d.ts.map +1 -0
  37. package/dist/bootstrap/phases/assemble/load-links.js +160 -0
  38. package/dist/bootstrap/phases/assemble/load-links.js.map +1 -0
  39. package/dist/bootstrap/phases/assemble/load-modules.d.ts +3 -0
  40. package/dist/bootstrap/phases/assemble/load-modules.d.ts.map +1 -0
  41. package/dist/bootstrap/phases/assemble/load-modules.js +163 -0
  42. package/dist/bootstrap/phases/assemble/load-modules.js.map +1 -0
  43. package/dist/bootstrap/phases/assemble/load-resources.d.ts +3 -0
  44. package/dist/bootstrap/phases/assemble/load-resources.d.ts.map +1 -0
  45. package/dist/bootstrap/phases/assemble/load-resources.js +270 -0
  46. package/dist/bootstrap/phases/assemble/load-resources.js.map +1 -0
  47. package/dist/bootstrap/phases/assemble/wire-commands.d.ts +3 -0
  48. package/dist/bootstrap/phases/assemble/wire-commands.d.ts.map +1 -0
  49. package/dist/bootstrap/phases/assemble/wire-commands.js +408 -0
  50. package/dist/bootstrap/phases/assemble/wire-commands.js.map +1 -0
  51. package/dist/bootstrap/phases/assemble-modules.d.ts +3 -0
  52. package/dist/bootstrap/phases/assemble-modules.d.ts.map +1 -0
  53. package/dist/bootstrap/phases/assemble-modules.js +14 -0
  54. package/dist/bootstrap/phases/assemble-modules.js.map +1 -0
  55. package/dist/bootstrap/phases/build-app.d.ts +3 -0
  56. package/dist/bootstrap/phases/build-app.d.ts.map +1 -0
  57. package/dist/bootstrap/phases/build-app.js +15 -0
  58. package/dist/bootstrap/phases/build-app.js.map +1 -0
  59. package/dist/bootstrap/phases/discover-resources.d.ts +3 -0
  60. package/dist/bootstrap/phases/discover-resources.d.ts.map +1 -0
  61. package/dist/bootstrap/phases/discover-resources.js +60 -0
  62. package/dist/bootstrap/phases/discover-resources.js.map +1 -0
  63. package/dist/bootstrap/phases/index.d.ts +7 -0
  64. package/dist/bootstrap/phases/index.d.ts.map +1 -0
  65. package/dist/bootstrap/phases/index.js +7 -0
  66. package/dist/bootstrap/phases/index.js.map +1 -0
  67. package/dist/bootstrap/phases/init-infra.d.ts +3 -0
  68. package/dist/bootstrap/phases/init-infra.d.ts.map +1 -0
  69. package/dist/bootstrap/phases/init-infra.js +193 -0
  70. package/dist/bootstrap/phases/init-infra.js.map +1 -0
  71. package/dist/bootstrap/phases/seed-dev-users.d.ts +3 -0
  72. package/dist/bootstrap/phases/seed-dev-users.d.ts.map +1 -0
  73. package/dist/bootstrap/phases/seed-dev-users.js +93 -0
  74. package/dist/bootstrap/phases/seed-dev-users.js.map +1 -0
  75. package/dist/bootstrap/phases/wire/auth-helpers.d.ts +12 -0
  76. package/dist/bootstrap/phases/wire/auth-helpers.d.ts.map +1 -0
  77. package/dist/bootstrap/phases/wire/auth-helpers.js +25 -0
  78. package/dist/bootstrap/phases/wire/auth-helpers.js.map +1 -0
  79. package/dist/bootstrap/phases/wire/contexts/context-registry.d.ts +4 -0
  80. package/dist/bootstrap/phases/wire/contexts/context-registry.d.ts.map +1 -0
  81. package/dist/bootstrap/phases/wire/contexts/context-registry.js +96 -0
  82. package/dist/bootstrap/phases/wire/contexts/context-registry.js.map +1 -0
  83. package/dist/bootstrap/phases/wire/contexts/cqrs-routes.d.ts +3 -0
  84. package/dist/bootstrap/phases/wire/contexts/cqrs-routes.d.ts.map +1 -0
  85. package/dist/bootstrap/phases/wire/contexts/cqrs-routes.js +138 -0
  86. package/dist/bootstrap/phases/wire/contexts/cqrs-routes.js.map +1 -0
  87. package/dist/bootstrap/phases/wire/contexts/index.d.ts +6 -0
  88. package/dist/bootstrap/phases/wire/contexts/index.d.ts.map +1 -0
  89. package/dist/bootstrap/phases/wire/contexts/index.js +6 -0
  90. package/dist/bootstrap/phases/wire/contexts/index.js.map +1 -0
  91. package/dist/bootstrap/phases/wire/contexts/query-endpoints.d.ts +3 -0
  92. package/dist/bootstrap/phases/wire/contexts/query-endpoints.d.ts.map +1 -0
  93. package/dist/bootstrap/phases/wire/contexts/query-endpoints.js +116 -0
  94. package/dist/bootstrap/phases/wire/contexts/query-endpoints.js.map +1 -0
  95. package/dist/bootstrap/phases/wire/contexts/spa-warnings.d.ts +3 -0
  96. package/dist/bootstrap/phases/wire/contexts/spa-warnings.d.ts.map +1 -0
  97. package/dist/bootstrap/phases/wire/contexts/spa-warnings.js +17 -0
  98. package/dist/bootstrap/phases/wire/contexts/spa-warnings.js.map +1 -0
  99. package/dist/bootstrap/phases/wire/contexts/user-routes.d.ts +3 -0
  100. package/dist/bootstrap/phases/wire/contexts/user-routes.d.ts.map +1 -0
  101. package/dist/bootstrap/phases/wire/contexts/user-routes.js +83 -0
  102. package/dist/bootstrap/phases/wire/contexts/user-routes.js.map +1 -0
  103. package/dist/bootstrap/phases/wire/index.d.ts +5 -0
  104. package/dist/bootstrap/phases/wire/index.d.ts.map +1 -0
  105. package/dist/bootstrap/phases/wire/index.js +5 -0
  106. package/dist/bootstrap/phases/wire/index.js.map +1 -0
  107. package/dist/bootstrap/phases/wire/wire-adapter.d.ts +12 -0
  108. package/dist/bootstrap/phases/wire/wire-adapter.d.ts.map +1 -0
  109. package/dist/bootstrap/phases/wire/wire-adapter.js +156 -0
  110. package/dist/bootstrap/phases/wire/wire-adapter.js.map +1 -0
  111. package/dist/bootstrap/phases/wire/wire-auth.d.ts +3 -0
  112. package/dist/bootstrap/phases/wire/wire-auth.d.ts.map +1 -0
  113. package/dist/bootstrap/phases/wire/wire-auth.js +46 -0
  114. package/dist/bootstrap/phases/wire/wire-auth.js.map +1 -0
  115. package/dist/bootstrap/phases/wire/wire-contexts.d.ts +3 -0
  116. package/dist/bootstrap/phases/wire/wire-contexts.d.ts.map +1 -0
  117. package/dist/bootstrap/phases/wire/wire-contexts.js +15 -0
  118. package/dist/bootstrap/phases/wire/wire-contexts.js.map +1 -0
  119. package/dist/bootstrap/phases/wire/wire-cron-routes.d.ts +3 -0
  120. package/dist/bootstrap/phases/wire/wire-cron-routes.d.ts.map +1 -0
  121. package/dist/bootstrap/phases/wire/wire-cron-routes.js +102 -0
  122. package/dist/bootstrap/phases/wire/wire-cron-routes.js.map +1 -0
  123. package/dist/bootstrap/phases/wire/wire-extras.d.ts +3 -0
  124. package/dist/bootstrap/phases/wire/wire-extras.d.ts.map +1 -0
  125. package/dist/bootstrap/phases/wire/wire-extras.js +305 -0
  126. package/dist/bootstrap/phases/wire/wire-extras.js.map +1 -0
  127. package/dist/bootstrap/phases/wire/wire-workflow-routes.d.ts +3 -0
  128. package/dist/bootstrap/phases/wire/wire-workflow-routes.d.ts.map +1 -0
  129. package/dist/bootstrap/phases/wire/wire-workflow-routes.js +212 -0
  130. package/dist/bootstrap/phases/wire/wire-workflow-routes.js.map +1 -0
  131. package/dist/bootstrap/phases/wire-http.d.ts +3 -0
  132. package/dist/bootstrap/phases/wire-http.d.ts.map +1 -0
  133. package/dist/bootstrap/phases/wire-http.js +10 -0
  134. package/dist/bootstrap/phases/wire-http.js.map +1 -0
  135. package/dist/bootstrap/validate-generated-ts.d.ts +6 -0
  136. package/dist/bootstrap/validate-generated-ts.d.ts.map +1 -0
  137. package/dist/bootstrap/validate-generated-ts.js +26 -0
  138. package/dist/bootstrap/validate-generated-ts.js.map +1 -0
  139. package/dist/build/generate-manifest.d.ts +10 -0
  140. package/dist/build/generate-manifest.d.ts.map +1 -0
  141. package/dist/build/generate-manifest.js +138 -0
  142. package/dist/build/generate-manifest.js.map +1 -0
  143. package/dist/cli.d.ts +3 -0
  144. package/dist/cli.d.ts.map +1 -0
  145. package/dist/cli.js +421 -0
  146. package/dist/cli.js.map +1 -0
  147. package/dist/commands/build.d.ts +21 -0
  148. package/dist/commands/build.d.ts.map +1 -0
  149. package/dist/commands/build.js +399 -0
  150. package/dist/commands/build.js.map +1 -0
  151. package/dist/commands/db/create.d.ts +17 -0
  152. package/dist/commands/db/create.d.ts.map +1 -0
  153. package/dist/commands/db/create.js +94 -0
  154. package/dist/commands/db/create.js.map +1 -0
  155. package/dist/commands/db/diff.d.ts +39 -0
  156. package/dist/commands/db/diff.d.ts.map +1 -0
  157. package/dist/commands/db/diff.js +81 -0
  158. package/dist/commands/db/diff.js.map +1 -0
  159. package/dist/commands/db/generate.d.ts +58 -0
  160. package/dist/commands/db/generate.d.ts.map +1 -0
  161. package/dist/commands/db/generate.js +138 -0
  162. package/dist/commands/db/generate.js.map +1 -0
  163. package/dist/commands/db/migrate.d.ts +29 -0
  164. package/dist/commands/db/migrate.d.ts.map +1 -0
  165. package/dist/commands/db/migrate.js +118 -0
  166. package/dist/commands/db/migrate.js.map +1 -0
  167. package/dist/commands/db/pg-deps.d.ts +30 -0
  168. package/dist/commands/db/pg-deps.d.ts.map +1 -0
  169. package/dist/commands/db/pg-deps.js +178 -0
  170. package/dist/commands/db/pg-deps.js.map +1 -0
  171. package/dist/commands/db/rollback.d.ts +21 -0
  172. package/dist/commands/db/rollback.d.ts.map +1 -0
  173. package/dist/commands/db/rollback.js +85 -0
  174. package/dist/commands/db/rollback.js.map +1 -0
  175. package/dist/commands/db/types.d.ts +113 -0
  176. package/dist/commands/db/types.d.ts.map +1 -0
  177. package/dist/commands/db/types.js +4 -0
  178. package/dist/commands/db/types.js.map +1 -0
  179. package/dist/commands/dev.d.ts +12 -0
  180. package/dist/commands/dev.d.ts.map +1 -0
  181. package/dist/commands/dev.js +79 -0
  182. package/dist/commands/dev.js.map +1 -0
  183. package/dist/commands/exec.d.ts +21 -0
  184. package/dist/commands/exec.d.ts.map +1 -0
  185. package/dist/commands/exec.js +148 -0
  186. package/dist/commands/exec.js.map +1 -0
  187. package/dist/commands/generate.d.ts +11 -0
  188. package/dist/commands/generate.d.ts.map +1 -0
  189. package/dist/commands/generate.js +19 -0
  190. package/dist/commands/generate.js.map +1 -0
  191. package/dist/commands/init.d.ts +14 -0
  192. package/dist/commands/init.d.ts.map +1 -0
  193. package/dist/commands/init.js +476 -0
  194. package/dist/commands/init.js.map +1 -0
  195. package/dist/commands/start.d.ts +15 -0
  196. package/dist/commands/start.d.ts.map +1 -0
  197. package/dist/commands/start.js +121 -0
  198. package/dist/commands/start.js.map +1 -0
  199. package/dist/commands/user.d.ts +19 -0
  200. package/dist/commands/user.d.ts.map +1 -0
  201. package/dist/commands/user.js +125 -0
  202. package/dist/commands/user.js.map +1 -0
  203. package/dist/config/load-config.d.ts +23 -0
  204. package/dist/config/load-config.d.ts.map +1 -0
  205. package/dist/config/load-config.js +105 -0
  206. package/dist/config/load-config.js.map +1 -0
  207. package/dist/config/load-env.d.ts +11 -0
  208. package/dist/config/load-env.d.ts.map +1 -0
  209. package/dist/config/load-env.js +61 -0
  210. package/dist/config/load-env.js.map +1 -0
  211. package/dist/config/resolve-adapters.d.ts +23 -0
  212. package/dist/config/resolve-adapters.d.ts.map +1 -0
  213. package/dist/config/resolve-adapters.js +96 -0
  214. package/dist/config/resolve-adapters.js.map +1 -0
  215. package/dist/index.d.ts +18 -0
  216. package/dist/index.d.ts.map +1 -0
  217. package/dist/index.js +19 -0
  218. package/dist/index.js.map +1 -0
  219. package/dist/jiti.d.ts +2 -0
  220. package/dist/jiti.d.ts.map +1 -0
  221. package/dist/jiti.js +2 -0
  222. package/dist/jiti.js.map +1 -0
  223. package/dist/openapi/generate-spec.d.ts +56 -0
  224. package/dist/openapi/generate-spec.d.ts.map +1 -0
  225. package/dist/openapi/generate-spec.js +491 -0
  226. package/dist/openapi/generate-spec.js.map +1 -0
  227. package/dist/openapi/index.d.ts +4 -0
  228. package/dist/openapi/index.d.ts.map +1 -0
  229. package/dist/openapi/index.js +3 -0
  230. package/dist/openapi/index.js.map +1 -0
  231. package/dist/openapi/swagger-html.d.ts +2 -0
  232. package/dist/openapi/swagger-html.d.ts.map +1 -0
  233. package/dist/openapi/swagger-html.js +29 -0
  234. package/dist/openapi/swagger-html.js.map +1 -0
  235. package/dist/plugins/merge-resources.d.ts +18 -0
  236. package/dist/plugins/merge-resources.d.ts.map +1 -0
  237. package/dist/plugins/merge-resources.js +76 -0
  238. package/dist/plugins/merge-resources.js.map +1 -0
  239. package/dist/plugins/resolve-plugins.d.ts +14 -0
  240. package/dist/plugins/resolve-plugins.d.ts.map +1 -0
  241. package/dist/plugins/resolve-plugins.js +73 -0
  242. package/dist/plugins/resolve-plugins.js.map +1 -0
  243. package/dist/resource-loader.d.ts +151 -0
  244. package/dist/resource-loader.d.ts.map +1 -0
  245. package/dist/resource-loader.js +456 -0
  246. package/dist/resource-loader.js.map +1 -0
  247. package/dist/route-discovery.d.ts +33 -0
  248. package/dist/route-discovery.d.ts.map +1 -0
  249. package/dist/route-discovery.js +69 -0
  250. package/dist/route-discovery.js.map +1 -0
  251. package/dist/server-bootstrap.d.ts +38 -0
  252. package/dist/server-bootstrap.d.ts.map +1 -0
  253. package/dist/server-bootstrap.js +21 -0
  254. package/dist/server-bootstrap.js.map +1 -0
  255. package/dist/spa/generate-spa.d.ts +15 -0
  256. package/dist/spa/generate-spa.d.ts.map +1 -0
  257. package/dist/spa/generate-spa.js +357 -0
  258. package/dist/spa/generate-spa.js.map +1 -0
  259. package/dist/templates/agent/nextjs.md +129 -0
  260. package/dist/templates/agent/nuxt.md +98 -0
  261. package/dist/templates/agent/standalone.md +498 -0
  262. package/dist/types.d.ts +145 -0
  263. package/dist/types.d.ts.map +1 -0
  264. package/dist/types.js +3 -0
  265. package/dist/types.js.map +1 -0
  266. package/dist/utils/colors.d.ts +7 -0
  267. package/dist/utils/colors.d.ts.map +1 -0
  268. package/dist/utils/colors.js +8 -0
  269. package/dist/utils/colors.js.map +1 -0
  270. package/dist/utils/logger.d.ts +10 -0
  271. package/dist/utils/logger.d.ts.map +1 -0
  272. package/dist/utils/logger.js +27 -0
  273. package/dist/utils/logger.js.map +1 -0
  274. package/dist/utils/prompts.d.ts +6 -0
  275. package/dist/utils/prompts.d.ts.map +1 -0
  276. package/dist/utils/prompts.js +28 -0
  277. package/dist/utils/prompts.js.map +1 -0
  278. package/dist/utils/spinner.d.ts +7 -0
  279. package/dist/utils/spinner.d.ts.map +1 -0
  280. package/dist/utils/spinner.js +20 -0
  281. package/dist/utils/spinner.js.map +1 -0
  282. package/package.json +80 -0
@@ -0,0 +1,81 @@
1
+ // SPEC-087 — manta db:diff command
2
+ /**
3
+ * Compare expected schema with introspected schema.
4
+ */
5
+ export function compareSchemas(expected, actual) {
6
+ const diffs = [];
7
+ const notifications = [];
8
+ const actualMap = new Map(actual.map((t) => [t.table, new Set(t.columns)]));
9
+ const expectedMap = new Map(expected.map((t) => [t.table, new Set(t.columns)]));
10
+ // Missing tables
11
+ for (const exp of expected) {
12
+ if (!actualMap.has(exp.table)) {
13
+ diffs.push({ type: 'missing', entity: 'table', name: exp.table });
14
+ }
15
+ else {
16
+ // Check columns
17
+ const actualCols = actualMap.get(exp.table);
18
+ for (const col of exp.columns) {
19
+ if (!actualCols.has(col)) {
20
+ diffs.push({
21
+ type: 'missing',
22
+ entity: 'column',
23
+ name: `${exp.table}.${col}`,
24
+ });
25
+ }
26
+ }
27
+ }
28
+ }
29
+ // Extra tables
30
+ for (const act of actual) {
31
+ if (!expectedMap.has(act.table)) {
32
+ notifications.push({ type: 'extra', entity: 'table', name: act.table });
33
+ }
34
+ else {
35
+ const expectedCols = expectedMap.get(act.table);
36
+ for (const col of act.columns) {
37
+ if (!expectedCols.has(col)) {
38
+ notifications.push({
39
+ type: 'extra',
40
+ entity: 'column',
41
+ name: `${act.table}.${col}`,
42
+ });
43
+ }
44
+ }
45
+ }
46
+ }
47
+ return { diffs, notifications };
48
+ }
49
+ /**
50
+ * manta db:diff — Compare DML schema vs actual DB (read-only).
51
+ * Uses information_schema + pg_indexes + pg_trigger.
52
+ * Accepts injectable deps for testability (hexagonal architecture).
53
+ */
54
+ export async function diffCommand(_options = {}, expectedSchema, deps) {
55
+ const result = {
56
+ exitCode: 0,
57
+ errors: [],
58
+ diffs: [],
59
+ notifications: [],
60
+ };
61
+ // Step 1: Introspect the DB via information_schema
62
+ const rows = await deps.db.query(`SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = 'public' ORDER BY table_name, ordinal_position`);
63
+ // Step 2: Group rows into table→columns structure
64
+ const actualMap = new Map();
65
+ for (const row of rows) {
66
+ if (!actualMap.has(row.table_name)) {
67
+ actualMap.set(row.table_name, []);
68
+ }
69
+ actualMap.get(row.table_name).push(row.column_name);
70
+ }
71
+ const actual = Array.from(actualMap.entries()).map(([table, columns]) => ({
72
+ table,
73
+ columns,
74
+ }));
75
+ // Step 3: Compare
76
+ const { diffs, notifications } = compareSchemas(expectedSchema, actual);
77
+ result.diffs = diffs;
78
+ result.notifications = notifications;
79
+ return result;
80
+ }
81
+ //# sourceMappingURL=diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/commands/db/diff.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,58 @@
1
+ import type { GenerateDeps } from './types';
2
+ export interface GenerateOptions {
3
+ name?: string;
4
+ }
5
+ export interface DmlScanResult {
6
+ entities: Array<{
7
+ name: string;
8
+ file: string;
9
+ }>;
10
+ warnings: string[];
11
+ }
12
+ export interface GenerateCommandResult {
13
+ exitCode: number;
14
+ errors: string[];
15
+ warnings: string[];
16
+ migrationFile?: string;
17
+ noChanges?: boolean;
18
+ dmlScan?: DmlScanResult;
19
+ }
20
+ /**
21
+ * Scan DML defineModel() entities under src/modules/. Supports both layouts:
22
+ * V1 (legacy): src/modules/{module}/models/{entity}.ts
23
+ * V2 (current): src/modules/{module}/entities/{entity}/model.ts
24
+ * Both are returned so existing V1 modules keep working while V2 modules
25
+ * produce migrations too.
26
+ */
27
+ export declare function scanDmlModels(cwd: string): DmlScanResult;
28
+ /**
29
+ * Detect potential column renames (same type, drop + add on same table).
30
+ */
31
+ export declare function detectRenames(dropped: Array<{
32
+ table: string;
33
+ column: string;
34
+ type: string;
35
+ }>, added: Array<{
36
+ table: string;
37
+ column: string;
38
+ type: string;
39
+ }>): Array<{
40
+ table: string;
41
+ from: string;
42
+ to: string;
43
+ type: string;
44
+ }>;
45
+ /**
46
+ * Check if running in non-interactive mode (CI, piped stdin).
47
+ */
48
+ export declare function isNonInteractive(): boolean;
49
+ /**
50
+ * Detect dangerous changes in migration SQL.
51
+ */
52
+ export declare function detectDangerousChanges(sql: string): string[];
53
+ /**
54
+ * manta db:generate — Generate SQL migration files from DML changes.
55
+ * Accepts injectable deps for testability (hexagonal architecture).
56
+ */
57
+ export declare function generateCommand(_options: GenerateOptions | undefined, cwd: string | undefined, deps: GenerateDeps): Promise<GenerateCommandResult>;
58
+ //# sourceMappingURL=generate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/db/generate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAE3C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC/C,QAAQ,EAAE,MAAM,EAAE,CAAA;CACnB;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,OAAO,CAAC,EAAE,aAAa,CAAA;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,aAAa,CA4CxD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,EAC/D,KAAK,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,GAC5D,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB5D;AAED;;;GAGG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,eAAe,YAAK,EAC9B,GAAG,EAAE,MAAM,YAAgB,EAC3B,IAAI,EAAE,YAAY,GACjB,OAAO,CAAC,qBAAqB,CAAC,CAmChC"}
@@ -0,0 +1,138 @@
1
+ // SPEC-057f — manta db:generate command
2
+ import { existsSync, readdirSync } from 'node:fs';
3
+ import { join, resolve } from 'node:path';
4
+ /**
5
+ * Scan DML defineModel() entities under src/modules/. Supports both layouts:
6
+ * V1 (legacy): src/modules/{module}/models/{entity}.ts
7
+ * V2 (current): src/modules/{module}/entities/{entity}/model.ts
8
+ * Both are returned so existing V1 modules keep working while V2 modules
9
+ * produce migrations too.
10
+ */
11
+ export function scanDmlModels(cwd) {
12
+ const entities = [];
13
+ const warnings = [];
14
+ const modulesDir = resolve(cwd, 'src', 'modules');
15
+ if (!existsSync(modulesDir)) {
16
+ return { entities, warnings };
17
+ }
18
+ const moduleEntries = readdirSync(modulesDir, { withFileTypes: true });
19
+ for (const moduleEntry of moduleEntries) {
20
+ if (!moduleEntry.isDirectory())
21
+ continue;
22
+ const moduleDir = resolve(modulesDir, moduleEntry.name);
23
+ // V1 — src/modules/{module}/models/{entity}.ts
24
+ const modelsDir = resolve(moduleDir, 'models');
25
+ if (existsSync(modelsDir)) {
26
+ for (const modelFile of readdirSync(modelsDir, { withFileTypes: true })) {
27
+ if (!modelFile.isFile())
28
+ continue;
29
+ if (!modelFile.name.endsWith('.ts') && !modelFile.name.endsWith('.js'))
30
+ continue;
31
+ const filePath = join('src', 'modules', moduleEntry.name, 'models', modelFile.name);
32
+ const entityName = modelFile.name.replace(/\.(ts|js)$/, '');
33
+ entities.push({ name: entityName, file: filePath });
34
+ }
35
+ }
36
+ // V2 — src/modules/{module}/entities/{entity}/model.ts
37
+ const entitiesDir = resolve(moduleDir, 'entities');
38
+ if (existsSync(entitiesDir)) {
39
+ for (const entityEntry of readdirSync(entitiesDir, { withFileTypes: true })) {
40
+ if (!entityEntry.isDirectory())
41
+ continue;
42
+ const modelPathTs = resolve(entitiesDir, entityEntry.name, 'model.ts');
43
+ const modelPathJs = resolve(entitiesDir, entityEntry.name, 'model.js');
44
+ const modelPath = existsSync(modelPathTs) ? modelPathTs : existsSync(modelPathJs) ? modelPathJs : null;
45
+ if (!modelPath)
46
+ continue;
47
+ const ext = modelPath.endsWith('.ts') ? '.ts' : '.js';
48
+ const filePath = join('src', 'modules', moduleEntry.name, 'entities', entityEntry.name, `model${ext}`);
49
+ entities.push({ name: entityEntry.name, file: filePath });
50
+ }
51
+ }
52
+ }
53
+ return { entities, warnings };
54
+ }
55
+ /**
56
+ * Detect potential column renames (same type, drop + add on same table).
57
+ */
58
+ export function detectRenames(dropped, added) {
59
+ const candidates = [];
60
+ for (const drop of dropped) {
61
+ for (const add of added) {
62
+ if (drop.table === add.table && drop.type === add.type) {
63
+ candidates.push({
64
+ table: drop.table,
65
+ from: drop.column,
66
+ to: add.column,
67
+ type: drop.type,
68
+ });
69
+ }
70
+ }
71
+ }
72
+ // Sort by dropped column name (alphabetical)
73
+ return candidates.sort((a, b) => a.from.localeCompare(b.from));
74
+ }
75
+ /**
76
+ * Check if running in non-interactive mode (CI, piped stdin).
77
+ */
78
+ export function isNonInteractive() {
79
+ if (process.env.CI === 'true')
80
+ return true;
81
+ if (process.env.MANTA_NON_INTERACTIVE === 'true')
82
+ return true;
83
+ if (typeof process.stdin.isTTY === 'undefined' || !process.stdin.isTTY)
84
+ return true;
85
+ return false;
86
+ }
87
+ /**
88
+ * Detect dangerous changes in migration SQL.
89
+ */
90
+ export function detectDangerousChanges(sql) {
91
+ const warnings = [];
92
+ const lines = sql.split('\n');
93
+ for (const line of lines) {
94
+ const trimmed = line.trim().toUpperCase();
95
+ if (trimmed.startsWith('DROP COLUMN')) {
96
+ warnings.push(line.trim());
97
+ }
98
+ if (trimmed.startsWith('ALTER') && trimmed.includes('TYPE')) {
99
+ warnings.push(line.trim());
100
+ }
101
+ if (trimmed.startsWith('DROP TABLE')) {
102
+ warnings.push(line.trim());
103
+ }
104
+ }
105
+ return warnings;
106
+ }
107
+ /**
108
+ * manta db:generate — Generate SQL migration files from DML changes.
109
+ * Accepts injectable deps for testability (hexagonal architecture).
110
+ */
111
+ export async function generateCommand(_options = {}, cwd = process.cwd(), deps) {
112
+ const result = { exitCode: 0, errors: [], warnings: [] };
113
+ // Step 1: Scan DML models
114
+ const dmlScan = scanDmlModels(cwd);
115
+ result.dmlScan = dmlScan;
116
+ result.warnings.push(...dmlScan.warnings);
117
+ if (dmlScan.entities.length === 0) {
118
+ result.warnings.push('No DML entities found in src/modules/**/models/ or src/modules/**/entities/*/model.ts');
119
+ result.noChanges = true;
120
+ return result;
121
+ }
122
+ // Step 2: Write Drizzle schema from DML entities
123
+ await deps.migrationFs.writeDrizzleSchema(dmlScan.entities);
124
+ // Step 3: Call drizzle-kit generate
125
+ const generateResult = await deps.drizzleKit.generate(dmlScan.entities);
126
+ if (!generateResult.migrationFile || !generateResult.sql) {
127
+ result.noChanges = true;
128
+ return result;
129
+ }
130
+ result.migrationFile = generateResult.migrationFile;
131
+ // Step 4: Detect dangerous changes in generated SQL
132
+ const dangerousWarnings = detectDangerousChanges(generateResult.sql);
133
+ result.warnings.push(...dangerousWarnings);
134
+ // Step 5: Write rollback skeleton
135
+ await deps.migrationFs.writeRollbackSkeleton(generateResult.migrationFile);
136
+ return result;
137
+ }
138
+ //# sourceMappingURL=generate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/commands/db/generate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ import type { MigrateDeps } from './types';
2
+ export interface MigrateOptions {
3
+ forceUnlock?: boolean;
4
+ dryRun?: boolean;
5
+ allOrNothing?: boolean;
6
+ }
7
+ export interface MigrateCommandResult {
8
+ exitCode: number;
9
+ errors: string[];
10
+ warnings: string[];
11
+ appliedCount: number;
12
+ pendingCount: number;
13
+ dryRunSql?: string[];
14
+ }
15
+ /**
16
+ * Check if migration SQL contains CREATE INDEX CONCURRENTLY.
17
+ * Incompatible with --all-or-nothing mode.
18
+ */
19
+ export declare function detectConcurrentIndex(sql: string): boolean;
20
+ /**
21
+ * Parse pending migrations from filesystem vs tracking table.
22
+ */
23
+ export declare function findPendingMigrations(filesystemMigrations: string[], appliedMigrations: string[]): string[];
24
+ /**
25
+ * manta db:migrate — Apply pending SQL migrations.
26
+ * Accepts injectable deps for testability (hexagonal architecture).
27
+ */
28
+ export declare function migrateCommand(options: MigrateOptions | undefined, deps: MigrateDeps): Promise<MigrateCommandResult>;
29
+ //# sourceMappingURL=migrate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.d.ts","sourceRoot":"","sources":["../../../src/commands/db/migrate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAE1C,MAAM,WAAW,cAAc;IAC7B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,oBAAoB,EAAE,MAAM,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAG3G;AAED;;;GAGG;AACH,wBAAsB,cAAc,CAAC,OAAO,EAAE,cAAc,YAAK,EAAE,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAyGnH"}
@@ -0,0 +1,118 @@
1
+ // SPEC-014 — manta db:migrate command
2
+ /**
3
+ * Check if migration SQL contains CREATE INDEX CONCURRENTLY.
4
+ * Incompatible with --all-or-nothing mode.
5
+ */
6
+ export function detectConcurrentIndex(sql) {
7
+ return /CREATE\s+INDEX\s+CONCURRENTLY/i.test(sql);
8
+ }
9
+ /**
10
+ * Parse pending migrations from filesystem vs tracking table.
11
+ */
12
+ export function findPendingMigrations(filesystemMigrations, appliedMigrations) {
13
+ const appliedSet = new Set(appliedMigrations);
14
+ return filesystemMigrations.filter((m) => !appliedSet.has(m));
15
+ }
16
+ /**
17
+ * manta db:migrate — Apply pending SQL migrations.
18
+ * Accepts injectable deps for testability (hexagonal architecture).
19
+ */
20
+ export async function migrateCommand(options = {}, deps) {
21
+ const result = {
22
+ exitCode: 0,
23
+ errors: [],
24
+ warnings: [],
25
+ appliedCount: 0,
26
+ pendingCount: 0,
27
+ };
28
+ // --force-unlock: release the lock and exit immediately
29
+ if (options.forceUnlock) {
30
+ await deps.lock.forceRelease();
31
+ return result;
32
+ }
33
+ // Step 1: Acquire migration lock
34
+ const locked = await deps.lock.acquire();
35
+ if (!locked) {
36
+ result.exitCode = 1;
37
+ result.errors.push('Could not acquire migration lock (timeout)');
38
+ return result;
39
+ }
40
+ try {
41
+ // Step 2: Ensure tracking table exists
42
+ await deps.tracker.ensureTable();
43
+ // Step 3: Detect pending migrations
44
+ const allFiles = await deps.fs.listMigrationFiles();
45
+ const applied = await deps.tracker.getApplied();
46
+ const pending = findPendingMigrations(allFiles, applied);
47
+ result.pendingCount = pending.length;
48
+ if (pending.length === 0) {
49
+ return result;
50
+ }
51
+ // Step 4: Read SQL for all pending migrations
52
+ const migrations = [];
53
+ for (const name of pending) {
54
+ const sql = await deps.fs.readMigrationSql(name);
55
+ migrations.push({ name, sql });
56
+ }
57
+ // Step 5: --all-or-nothing pre-check for CONCURRENT INDEX
58
+ if (options.allOrNothing) {
59
+ for (const { name, sql } of migrations) {
60
+ if (detectConcurrentIndex(sql)) {
61
+ result.exitCode = 1;
62
+ result.errors.push(`Migration ${name} contains CREATE INDEX CONCURRENTLY which is incompatible with --all-or-nothing (transactions)`);
63
+ return result;
64
+ }
65
+ }
66
+ }
67
+ // Step 6: --dry-run — return SQL without executing
68
+ if (options.dryRun) {
69
+ result.dryRunSql = migrations.map((m) => m.sql);
70
+ return result;
71
+ }
72
+ // Step 7: Apply migrations
73
+ if (options.allOrNothing) {
74
+ // All-or-nothing: wrap in a single transaction
75
+ try {
76
+ await deps.db.transaction(async (tx) => {
77
+ for (const { sql } of migrations) {
78
+ await tx.execute(sql);
79
+ }
80
+ });
81
+ // If transaction succeeded, record all
82
+ for (const { name, sql } of migrations) {
83
+ await deps.tracker.record(name, sql);
84
+ }
85
+ result.appliedCount = migrations.length;
86
+ }
87
+ catch (err) {
88
+ // Transaction rolled back — nothing applied
89
+ result.exitCode = 1;
90
+ result.appliedCount = 0;
91
+ const message = err instanceof Error ? err.message : String(err);
92
+ result.errors.push(`All migrations rolled back: ${message}`);
93
+ }
94
+ }
95
+ else {
96
+ // Apply one by one — partial failure records only successful ones
97
+ for (const { name, sql } of migrations) {
98
+ try {
99
+ await deps.db.execute(sql);
100
+ await deps.tracker.record(name, sql);
101
+ result.appliedCount++;
102
+ }
103
+ catch (err) {
104
+ result.exitCode = 1;
105
+ const message = err instanceof Error ? err.message : String(err);
106
+ result.errors.push(`Migration ${name} failed: ${message}`);
107
+ break;
108
+ }
109
+ }
110
+ }
111
+ }
112
+ finally {
113
+ // Always release the lock
114
+ await deps.lock.release();
115
+ }
116
+ return result;
117
+ }
118
+ //# sourceMappingURL=migrate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/commands/db/migrate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import postgres from 'postgres';
2
+ import type { CreateDeps, DbClient, MigrationFs, MigrationLock, MigrationTracker } from './types';
3
+ /**
4
+ * Create a DbClient from a postgres connection URL.
5
+ * Also exposes the raw postgres sql instance for parameterized queries.
6
+ */
7
+ export declare function createPgClient(url: string): DbClient & {
8
+ __pgSql: ReturnType<typeof postgres>;
9
+ };
10
+ /**
11
+ * Create a DbClient for the 'postgres' maintenance database.
12
+ * Used by db:create command.
13
+ */
14
+ export declare function createPgCreateDeps(): CreateDeps;
15
+ /**
16
+ * Advisory-lock-based migration lock using pg_advisory_lock.
17
+ */
18
+ export declare function createMigrationLock(client: DbClient): MigrationLock;
19
+ /**
20
+ * Migration tracker backed by a _manta_migrations table.
21
+ * Accepts a DbClient with the __pgSql raw postgres instance for parameterized queries.
22
+ */
23
+ export declare function createMigrationTracker(client: DbClient & {
24
+ __pgSql?: ReturnType<typeof postgres>;
25
+ }): MigrationTracker;
26
+ /**
27
+ * Filesystem-based migration file operations.
28
+ */
29
+ export declare function createMigrationFs(migrationsDir: string): MigrationFs;
30
+ //# sourceMappingURL=pg-deps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pg-deps.d.ts","sourceRoot":"","sources":["../../../src/commands/db/pg-deps.ts"],"names":[],"mappings":"AAKA,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAEjG;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG;IAAE,OAAO,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAA;CAAE,CAoD/F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,UAAU,CAM/C;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,QAAQ,GAAG,aAAa,CAyBnE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,QAAQ,GAAG;IAAE,OAAO,CAAC,EAAE,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAA;CAAE,GAAG,gBAAgB,CA2CrH;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW,CA+BpE"}