relq 1.0.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 (305) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +862 -0
  3. package/dist/addons/buffer.js +1869 -0
  4. package/dist/addons/pg-cursor.js +1425 -0
  5. package/dist/addons/pg-format.js +2248 -0
  6. package/dist/addons/pg.js +4790 -0
  7. package/dist/bin/relq.js +2 -0
  8. package/dist/cjs/cache/index.cjs +9 -0
  9. package/dist/cjs/cache/query-cache.cjs +311 -0
  10. package/dist/cjs/cli/commands/add.cjs +82 -0
  11. package/dist/cjs/cli/commands/commit.cjs +145 -0
  12. package/dist/cjs/cli/commands/diff.cjs +84 -0
  13. package/dist/cjs/cli/commands/export.cjs +333 -0
  14. package/dist/cjs/cli/commands/fetch.cjs +59 -0
  15. package/dist/cjs/cli/commands/generate.cjs +242 -0
  16. package/dist/cjs/cli/commands/history.cjs +165 -0
  17. package/dist/cjs/cli/commands/import.cjs +524 -0
  18. package/dist/cjs/cli/commands/init.cjs +437 -0
  19. package/dist/cjs/cli/commands/introspect.cjs +142 -0
  20. package/dist/cjs/cli/commands/log.cjs +62 -0
  21. package/dist/cjs/cli/commands/migrate.cjs +167 -0
  22. package/dist/cjs/cli/commands/pull.cjs +410 -0
  23. package/dist/cjs/cli/commands/push.cjs +165 -0
  24. package/dist/cjs/cli/commands/rollback.cjs +169 -0
  25. package/dist/cjs/cli/commands/status.cjs +110 -0
  26. package/dist/cjs/cli/commands/sync.cjs +79 -0
  27. package/dist/cjs/cli/index.cjs +275 -0
  28. package/dist/cjs/cli/utils/change-tracker.cjs +446 -0
  29. package/dist/cjs/cli/utils/commit-manager.cjs +239 -0
  30. package/dist/cjs/cli/utils/config-loader.cjs +127 -0
  31. package/dist/cjs/cli/utils/env-loader.cjs +62 -0
  32. package/dist/cjs/cli/utils/fast-introspect.cjs +398 -0
  33. package/dist/cjs/cli/utils/git-utils.cjs +404 -0
  34. package/dist/cjs/cli/utils/migration-generator.cjs +269 -0
  35. package/dist/cjs/cli/utils/relqignore.cjs +114 -0
  36. package/dist/cjs/cli/utils/repo-manager.cjs +515 -0
  37. package/dist/cjs/cli/utils/schema-comparator.cjs +313 -0
  38. package/dist/cjs/cli/utils/schema-diff.cjs +284 -0
  39. package/dist/cjs/cli/utils/schema-hash.cjs +108 -0
  40. package/dist/cjs/cli/utils/schema-introspect.cjs +455 -0
  41. package/dist/cjs/cli/utils/snapshot-manager.cjs +223 -0
  42. package/dist/cjs/cli/utils/spinner.cjs +108 -0
  43. package/dist/cjs/cli/utils/sql-generator.cjs +520 -0
  44. package/dist/cjs/cli/utils/sql-parser.cjs +999 -0
  45. package/dist/cjs/cli/utils/type-generator.cjs +2061 -0
  46. package/dist/cjs/condition/array-condition-builder.cjs +503 -0
  47. package/dist/cjs/condition/array-numeric-condition-builder.cjs +186 -0
  48. package/dist/cjs/condition/array-specialized-condition-builder.cjs +206 -0
  49. package/dist/cjs/condition/array-string-condition-builder.cjs +146 -0
  50. package/dist/cjs/condition/base-condition-builder.cjs +2 -0
  51. package/dist/cjs/condition/condition-collector.cjs +284 -0
  52. package/dist/cjs/condition/fulltext-condition-builder.cjs +61 -0
  53. package/dist/cjs/condition/geometric-condition-builder.cjs +208 -0
  54. package/dist/cjs/condition/index.cjs +25 -0
  55. package/dist/cjs/condition/jsonb-condition-builder.cjs +160 -0
  56. package/dist/cjs/condition/network-condition-builder.cjs +230 -0
  57. package/dist/cjs/condition/range-condition-builder.cjs +82 -0
  58. package/dist/cjs/config/config.cjs +190 -0
  59. package/dist/cjs/config/index.cjs +9 -0
  60. package/dist/cjs/constants/pg-values.cjs +68 -0
  61. package/dist/cjs/copy/copy-builder.cjs +316 -0
  62. package/dist/cjs/copy/index.cjs +6 -0
  63. package/dist/cjs/core/query-builder.cjs +440 -0
  64. package/dist/cjs/core/relq-client.cjs +1831 -0
  65. package/dist/cjs/core/typed-kuery-client.cjs +2 -0
  66. package/dist/cjs/count/count-builder.cjs +88 -0
  67. package/dist/cjs/count/index.cjs +5 -0
  68. package/dist/cjs/cte/cte-builder.cjs +89 -0
  69. package/dist/cjs/cte/index.cjs +5 -0
  70. package/dist/cjs/ddl/function.cjs +48 -0
  71. package/dist/cjs/ddl/index.cjs +7 -0
  72. package/dist/cjs/ddl/sql.cjs +54 -0
  73. package/dist/cjs/delete/delete-builder.cjs +135 -0
  74. package/dist/cjs/delete/index.cjs +5 -0
  75. package/dist/cjs/errors/relq-errors.cjs +329 -0
  76. package/dist/cjs/examples/fulltext-search-test.cjs +122 -0
  77. package/dist/cjs/explain/explain-builder.cjs +99 -0
  78. package/dist/cjs/explain/index.cjs +5 -0
  79. package/dist/cjs/function/create-function-builder.cjs +196 -0
  80. package/dist/cjs/function/index.cjs +6 -0
  81. package/dist/cjs/functions/advanced-functions.cjs +241 -0
  82. package/dist/cjs/functions/case-builder.cjs +66 -0
  83. package/dist/cjs/functions/geometric-functions.cjs +104 -0
  84. package/dist/cjs/functions/index.cjs +184 -0
  85. package/dist/cjs/functions/network-functions.cjs +86 -0
  86. package/dist/cjs/functions/sql-functions.cjs +431 -0
  87. package/dist/cjs/index.cjs +164 -0
  88. package/dist/cjs/indexing/create-index-builder.cjs +187 -0
  89. package/dist/cjs/indexing/drop-index-builder.cjs +89 -0
  90. package/dist/cjs/indexing/index-types.cjs +2 -0
  91. package/dist/cjs/indexing/index.cjs +8 -0
  92. package/dist/cjs/insert/conflict-builder.cjs +173 -0
  93. package/dist/cjs/insert/index.cjs +5 -0
  94. package/dist/cjs/insert/insert-builder.cjs +254 -0
  95. package/dist/cjs/introspect/index.cjs +229 -0
  96. package/dist/cjs/maintenance/index.cjs +6 -0
  97. package/dist/cjs/maintenance/vacuum-builder.cjs +166 -0
  98. package/dist/cjs/pubsub/index.cjs +7 -0
  99. package/dist/cjs/pubsub/listen-notify-builder.cjs +57 -0
  100. package/dist/cjs/pubsub/listener-connection.cjs +180 -0
  101. package/dist/cjs/raw/index.cjs +5 -0
  102. package/dist/cjs/raw/raw-query-builder.cjs +27 -0
  103. package/dist/cjs/schema/index.cjs +15 -0
  104. package/dist/cjs/schema/schema-builder.cjs +1167 -0
  105. package/dist/cjs/schema-builder.cjs +21 -0
  106. package/dist/cjs/schema-definition/column-types.cjs +829 -0
  107. package/dist/cjs/schema-definition/index.cjs +62 -0
  108. package/dist/cjs/schema-definition/introspection.cjs +620 -0
  109. package/dist/cjs/schema-definition/partitions.cjs +129 -0
  110. package/dist/cjs/schema-definition/pg-enum.cjs +76 -0
  111. package/dist/cjs/schema-definition/pg-function.cjs +91 -0
  112. package/dist/cjs/schema-definition/pg-sequence.cjs +56 -0
  113. package/dist/cjs/schema-definition/pg-trigger.cjs +108 -0
  114. package/dist/cjs/schema-definition/relations.cjs +98 -0
  115. package/dist/cjs/schema-definition/sql-expressions.cjs +202 -0
  116. package/dist/cjs/schema-definition/table-definition.cjs +636 -0
  117. package/dist/cjs/select/aggregate-builder.cjs +179 -0
  118. package/dist/cjs/select/index.cjs +5 -0
  119. package/dist/cjs/select/select-builder.cjs +233 -0
  120. package/dist/cjs/sequence/index.cjs +7 -0
  121. package/dist/cjs/sequence/sequence-builder.cjs +264 -0
  122. package/dist/cjs/table/alter-table-builder.cjs +146 -0
  123. package/dist/cjs/table/constraint-builder.cjs +102 -0
  124. package/dist/cjs/table/create-table-builder.cjs +248 -0
  125. package/dist/cjs/table/index.cjs +17 -0
  126. package/dist/cjs/table/partition-builder.cjs +131 -0
  127. package/dist/cjs/table/truncate-builder.cjs +70 -0
  128. package/dist/cjs/transaction/index.cjs +6 -0
  129. package/dist/cjs/transaction/transaction-builder.cjs +78 -0
  130. package/dist/cjs/trigger/create-trigger-builder.cjs +174 -0
  131. package/dist/cjs/trigger/index.cjs +6 -0
  132. package/dist/cjs/types/aggregate-types.cjs +2 -0
  133. package/dist/cjs/types/config-types.cjs +40 -0
  134. package/dist/cjs/types/inference-types.cjs +18 -0
  135. package/dist/cjs/types/pagination-types.cjs +7 -0
  136. package/dist/cjs/types/result-types.cjs +2 -0
  137. package/dist/cjs/types/schema-types.cjs +2 -0
  138. package/dist/cjs/types/subscription-types.cjs +2 -0
  139. package/dist/cjs/types.cjs +2 -0
  140. package/dist/cjs/update/array-update-builder.cjs +205 -0
  141. package/dist/cjs/update/index.cjs +13 -0
  142. package/dist/cjs/update/update-builder.cjs +195 -0
  143. package/dist/cjs/utils/case-converter.cjs +58 -0
  144. package/dist/cjs/utils/environment-detection.cjs +120 -0
  145. package/dist/cjs/utils/index.cjs +10 -0
  146. package/dist/cjs/utils/pool-defaults.cjs +106 -0
  147. package/dist/cjs/utils/type-coercion.cjs +118 -0
  148. package/dist/cjs/view/create-view-builder.cjs +180 -0
  149. package/dist/cjs/view/index.cjs +7 -0
  150. package/dist/cjs/window/index.cjs +5 -0
  151. package/dist/cjs/window/window-builder.cjs +80 -0
  152. package/dist/config.cjs +1 -0
  153. package/dist/config.d.ts +655 -0
  154. package/dist/config.js +1 -0
  155. package/dist/esm/cache/index.js +1 -0
  156. package/dist/esm/cache/query-cache.js +303 -0
  157. package/dist/esm/cli/commands/add.js +78 -0
  158. package/dist/esm/cli/commands/commit.js +109 -0
  159. package/dist/esm/cli/commands/diff.js +81 -0
  160. package/dist/esm/cli/commands/export.js +297 -0
  161. package/dist/esm/cli/commands/fetch.js +56 -0
  162. package/dist/esm/cli/commands/generate.js +206 -0
  163. package/dist/esm/cli/commands/history.js +129 -0
  164. package/dist/esm/cli/commands/import.js +488 -0
  165. package/dist/esm/cli/commands/init.js +401 -0
  166. package/dist/esm/cli/commands/introspect.js +106 -0
  167. package/dist/esm/cli/commands/log.js +59 -0
  168. package/dist/esm/cli/commands/migrate.js +131 -0
  169. package/dist/esm/cli/commands/pull.js +374 -0
  170. package/dist/esm/cli/commands/push.js +129 -0
  171. package/dist/esm/cli/commands/rollback.js +133 -0
  172. package/dist/esm/cli/commands/status.js +107 -0
  173. package/dist/esm/cli/commands/sync.js +76 -0
  174. package/dist/esm/cli/index.js +240 -0
  175. package/dist/esm/cli/utils/change-tracker.js +405 -0
  176. package/dist/esm/cli/utils/commit-manager.js +191 -0
  177. package/dist/esm/cli/utils/config-loader.js +86 -0
  178. package/dist/esm/cli/utils/env-loader.js +57 -0
  179. package/dist/esm/cli/utils/fast-introspect.js +362 -0
  180. package/dist/esm/cli/utils/git-utils.js +347 -0
  181. package/dist/esm/cli/utils/migration-generator.js +263 -0
  182. package/dist/esm/cli/utils/relqignore.js +74 -0
  183. package/dist/esm/cli/utils/repo-manager.js +444 -0
  184. package/dist/esm/cli/utils/schema-comparator.js +307 -0
  185. package/dist/esm/cli/utils/schema-diff.js +276 -0
  186. package/dist/esm/cli/utils/schema-hash.js +69 -0
  187. package/dist/esm/cli/utils/schema-introspect.js +418 -0
  188. package/dist/esm/cli/utils/snapshot-manager.js +179 -0
  189. package/dist/esm/cli/utils/spinner.js +101 -0
  190. package/dist/esm/cli/utils/sql-generator.js +504 -0
  191. package/dist/esm/cli/utils/sql-parser.js +992 -0
  192. package/dist/esm/cli/utils/type-generator.js +2058 -0
  193. package/dist/esm/condition/array-condition-builder.js +495 -0
  194. package/dist/esm/condition/array-numeric-condition-builder.js +182 -0
  195. package/dist/esm/condition/array-specialized-condition-builder.js +200 -0
  196. package/dist/esm/condition/array-string-condition-builder.js +142 -0
  197. package/dist/esm/condition/base-condition-builder.js +1 -0
  198. package/dist/esm/condition/condition-collector.js +275 -0
  199. package/dist/esm/condition/fulltext-condition-builder.js +53 -0
  200. package/dist/esm/condition/geometric-condition-builder.js +200 -0
  201. package/dist/esm/condition/index.js +7 -0
  202. package/dist/esm/condition/jsonb-condition-builder.js +152 -0
  203. package/dist/esm/condition/network-condition-builder.js +222 -0
  204. package/dist/esm/condition/range-condition-builder.js +74 -0
  205. package/dist/esm/config/config.js +150 -0
  206. package/dist/esm/config/index.js +1 -0
  207. package/dist/esm/constants/pg-values.js +63 -0
  208. package/dist/esm/copy/copy-builder.js +308 -0
  209. package/dist/esm/copy/index.js +1 -0
  210. package/dist/esm/core/query-builder.js +426 -0
  211. package/dist/esm/core/relq-client.js +1791 -0
  212. package/dist/esm/core/typed-kuery-client.js +1 -0
  213. package/dist/esm/count/count-builder.js +81 -0
  214. package/dist/esm/count/index.js +1 -0
  215. package/dist/esm/cte/cte-builder.js +82 -0
  216. package/dist/esm/cte/index.js +1 -0
  217. package/dist/esm/ddl/function.js +45 -0
  218. package/dist/esm/ddl/index.js +2 -0
  219. package/dist/esm/ddl/sql.js +51 -0
  220. package/dist/esm/delete/delete-builder.js +128 -0
  221. package/dist/esm/delete/index.js +1 -0
  222. package/dist/esm/errors/relq-errors.js +310 -0
  223. package/dist/esm/examples/fulltext-search-test.js +117 -0
  224. package/dist/esm/explain/explain-builder.js +95 -0
  225. package/dist/esm/explain/index.js +1 -0
  226. package/dist/esm/function/create-function-builder.js +188 -0
  227. package/dist/esm/function/index.js +1 -0
  228. package/dist/esm/functions/advanced-functions.js +231 -0
  229. package/dist/esm/functions/case-builder.js +58 -0
  230. package/dist/esm/functions/geometric-functions.js +97 -0
  231. package/dist/esm/functions/index.js +171 -0
  232. package/dist/esm/functions/network-functions.js +79 -0
  233. package/dist/esm/functions/sql-functions.js +421 -0
  234. package/dist/esm/index.js +34 -0
  235. package/dist/esm/indexing/create-index-builder.js +180 -0
  236. package/dist/esm/indexing/drop-index-builder.js +81 -0
  237. package/dist/esm/indexing/index-types.js +1 -0
  238. package/dist/esm/indexing/index.js +2 -0
  239. package/dist/esm/insert/conflict-builder.js +162 -0
  240. package/dist/esm/insert/index.js +1 -0
  241. package/dist/esm/insert/insert-builder.js +247 -0
  242. package/dist/esm/introspect/index.js +224 -0
  243. package/dist/esm/maintenance/index.js +1 -0
  244. package/dist/esm/maintenance/vacuum-builder.js +158 -0
  245. package/dist/esm/pubsub/index.js +1 -0
  246. package/dist/esm/pubsub/listen-notify-builder.js +48 -0
  247. package/dist/esm/pubsub/listener-connection.js +173 -0
  248. package/dist/esm/raw/index.js +1 -0
  249. package/dist/esm/raw/raw-query-builder.js +20 -0
  250. package/dist/esm/schema/index.js +1 -0
  251. package/dist/esm/schema/schema-builder.js +1150 -0
  252. package/dist/esm/schema-builder.js +2 -0
  253. package/dist/esm/schema-definition/column-types.js +738 -0
  254. package/dist/esm/schema-definition/index.js +10 -0
  255. package/dist/esm/schema-definition/introspection.js +614 -0
  256. package/dist/esm/schema-definition/partitions.js +123 -0
  257. package/dist/esm/schema-definition/pg-enum.js +70 -0
  258. package/dist/esm/schema-definition/pg-function.js +85 -0
  259. package/dist/esm/schema-definition/pg-sequence.js +50 -0
  260. package/dist/esm/schema-definition/pg-trigger.js +102 -0
  261. package/dist/esm/schema-definition/relations.js +90 -0
  262. package/dist/esm/schema-definition/sql-expressions.js +193 -0
  263. package/dist/esm/schema-definition/table-definition.js +630 -0
  264. package/dist/esm/select/aggregate-builder.js +172 -0
  265. package/dist/esm/select/index.js +1 -0
  266. package/dist/esm/select/select-builder.js +226 -0
  267. package/dist/esm/sequence/index.js +1 -0
  268. package/dist/esm/sequence/sequence-builder.js +255 -0
  269. package/dist/esm/table/alter-table-builder.js +138 -0
  270. package/dist/esm/table/constraint-builder.js +95 -0
  271. package/dist/esm/table/create-table-builder.js +241 -0
  272. package/dist/esm/table/index.js +5 -0
  273. package/dist/esm/table/partition-builder.js +121 -0
  274. package/dist/esm/table/truncate-builder.js +63 -0
  275. package/dist/esm/transaction/index.js +1 -0
  276. package/dist/esm/transaction/transaction-builder.js +70 -0
  277. package/dist/esm/trigger/create-trigger-builder.js +166 -0
  278. package/dist/esm/trigger/index.js +1 -0
  279. package/dist/esm/types/aggregate-types.js +1 -0
  280. package/dist/esm/types/config-types.js +36 -0
  281. package/dist/esm/types/inference-types.js +12 -0
  282. package/dist/esm/types/pagination-types.js +4 -0
  283. package/dist/esm/types/result-types.js +1 -0
  284. package/dist/esm/types/schema-types.js +1 -0
  285. package/dist/esm/types/subscription-types.js +1 -0
  286. package/dist/esm/types.js +1 -0
  287. package/dist/esm/update/array-update-builder.js +192 -0
  288. package/dist/esm/update/index.js +2 -0
  289. package/dist/esm/update/update-builder.js +188 -0
  290. package/dist/esm/utils/case-converter.js +55 -0
  291. package/dist/esm/utils/environment-detection.js +113 -0
  292. package/dist/esm/utils/index.js +2 -0
  293. package/dist/esm/utils/pool-defaults.js +100 -0
  294. package/dist/esm/utils/type-coercion.js +110 -0
  295. package/dist/esm/view/create-view-builder.js +171 -0
  296. package/dist/esm/view/index.js +1 -0
  297. package/dist/esm/window/index.js +1 -0
  298. package/dist/esm/window/window-builder.js +73 -0
  299. package/dist/index.cjs +1 -0
  300. package/dist/index.d.ts +10341 -0
  301. package/dist/index.js +1 -0
  302. package/dist/schema-builder.cjs +1 -0
  303. package/dist/schema-builder.d.ts +2272 -0
  304. package/dist/schema-builder.js +1 -0
  305. package/package.json +55 -0
@@ -0,0 +1,131 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as readline from 'readline';
4
+ import { requireValidConfig } from "../utils/config-loader.js";
5
+ import { getConnectionDescription } from "../utils/env-loader.js";
6
+ function parseMigration(content) {
7
+ const upMatch = content.match(/--\s*UP\s*\n([\s\S]*?)(?=--\s*DOWN|$)/i);
8
+ const downMatch = content.match(/--\s*DOWN\s*\n([\s\S]*?)$/i);
9
+ return {
10
+ up: upMatch?.[1]?.trim() || '',
11
+ down: downMatch?.[1]?.trim() || '',
12
+ };
13
+ }
14
+ function askConfirm(question) {
15
+ const rl = readline.createInterface({
16
+ input: process.stdin,
17
+ output: process.stdout,
18
+ });
19
+ return new Promise((resolve) => {
20
+ rl.question(`${question} [y/N]: `, (answer) => {
21
+ rl.close();
22
+ resolve(answer.trim().toLowerCase() === 'y');
23
+ });
24
+ });
25
+ }
26
+ export async function migrateCommand(context) {
27
+ const { config, flags } = context;
28
+ if (!config) {
29
+ console.error('Error: No configuration found.');
30
+ process.exit(1);
31
+ }
32
+ requireValidConfig(config);
33
+ const dryRun = flags['dry-run'] === true;
34
+ const force = flags['force'] === true;
35
+ const connection = config.connection;
36
+ const migrationsDir = config.migrations?.directory || './migrations';
37
+ const tableName = config.migrations?.tableName || '_relq_migrations';
38
+ console.log('🔄 Running migrations...');
39
+ console.log(` Connection: ${getConnectionDescription(connection)}`);
40
+ console.log(` Migrations: ${migrationsDir}\n`);
41
+ try {
42
+ const { Pool } = await import("../../addon/pg.js");
43
+ const pool = new Pool({
44
+ host: connection.host,
45
+ port: connection.port || 5432,
46
+ database: connection.database,
47
+ user: connection.user,
48
+ password: connection.password,
49
+ connectionString: connection.url,
50
+ });
51
+ try {
52
+ await pool.query(`
53
+ CREATE TABLE IF NOT EXISTS "${tableName}" (
54
+ id SERIAL PRIMARY KEY,
55
+ name VARCHAR(255) NOT NULL UNIQUE,
56
+ applied_at TIMESTAMPTZ DEFAULT NOW()
57
+ );
58
+ `);
59
+ const appliedResult = await pool.query(`
60
+ SELECT name FROM "${tableName}" ORDER BY id;
61
+ `);
62
+ const appliedMigrations = new Set(appliedResult.rows.map(r => r.name));
63
+ if (!fs.existsSync(migrationsDir)) {
64
+ console.log('No migrations directory found.');
65
+ return;
66
+ }
67
+ const migrationFiles = fs.readdirSync(migrationsDir)
68
+ .filter(f => f.endsWith('.sql'))
69
+ .sort();
70
+ const pending = migrationFiles.filter(f => !appliedMigrations.has(f));
71
+ if (pending.length === 0) {
72
+ console.log('✅ No pending migrations.');
73
+ return;
74
+ }
75
+ console.log(`📋 Pending migrations (${pending.length}):`);
76
+ for (const file of pending) {
77
+ console.log(` • ${file}`);
78
+ }
79
+ console.log('');
80
+ if (!force && !dryRun) {
81
+ if (!await askConfirm('Apply these migrations?')) {
82
+ console.log('Cancelled.');
83
+ return;
84
+ }
85
+ }
86
+ for (const file of pending) {
87
+ const filePath = path.join(migrationsDir, file);
88
+ const content = fs.readFileSync(filePath, 'utf-8');
89
+ const { up } = parseMigration(content);
90
+ if (!up) {
91
+ console.log(`⚠️ Skipping ${file} (no UP section)`);
92
+ continue;
93
+ }
94
+ if (dryRun) {
95
+ console.log(`Would apply: ${file}`);
96
+ console.log('---');
97
+ console.log(up);
98
+ console.log('---\n');
99
+ }
100
+ else {
101
+ console.log(`Applying: ${file}...`);
102
+ const client = await pool.connect();
103
+ try {
104
+ await client.query('BEGIN');
105
+ await client.query(up);
106
+ await client.query(`INSERT INTO "${tableName}" (name) VALUES ($1)`, [file]);
107
+ await client.query('COMMIT');
108
+ console.log(` ✅ Applied`);
109
+ }
110
+ catch (error) {
111
+ await client.query('ROLLBACK');
112
+ throw error;
113
+ }
114
+ finally {
115
+ client.release();
116
+ }
117
+ }
118
+ }
119
+ if (!dryRun) {
120
+ console.log(`\n✅ Applied ${pending.length} migration(s).`);
121
+ }
122
+ }
123
+ finally {
124
+ await pool.end();
125
+ }
126
+ }
127
+ catch (error) {
128
+ console.error('Error:', error instanceof Error ? error.message : error);
129
+ process.exit(1);
130
+ }
131
+ }
@@ -0,0 +1,374 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as readline from 'readline';
4
+ import { requireValidConfig } from "../utils/config-loader.js";
5
+ import { fastIntrospectDatabase } from "../utils/fast-introspect.js";
6
+ import { generateTypeScript } from "../utils/type-generator.js";
7
+ import { getConnectionDescription } from "../utils/env-loader.js";
8
+ import { createSpinner, colors, formatBytes } from "../utils/spinner.js";
9
+ import { getIgnorePatterns, filterIgnored } from "../utils/relqignore.js";
10
+ import { isInitialized, initRepository, getHead, saveSnapshot, loadSnapshot, createCommit, shortHash, fetchRemoteCommits, ensureRemoteTable, setFetchHead, getStagedChanges, getUnstagedChanges, } from "../utils/repo-manager.js";
11
+ function toCamelCase(str) {
12
+ return str.replace(/_([a-z])/g, (_, letter) => letter.toUpperCase());
13
+ }
14
+ function parseSchemaFileForSnapshot(schemaPath) {
15
+ if (!fs.existsSync(schemaPath)) {
16
+ return null;
17
+ }
18
+ const content = fs.readFileSync(schemaPath, 'utf-8');
19
+ const tables = [];
20
+ const tableRegex = /defineTable\s*\(\s*['"]([^'"]+)['"],\s*\{([\s\S]*?)\}(?:\s*,\s*\{([\s\S]*?)\})?\s*\)/g;
21
+ let tableMatch;
22
+ while ((tableMatch = tableRegex.exec(content)) !== null) {
23
+ const tableName = tableMatch[1];
24
+ const columnsBlock = tableMatch[2];
25
+ const optionsBlock = tableMatch[3] || '';
26
+ const columns = [];
27
+ const typePattern = 'varchar|text|uuid|integer|bigint|boolean|timestamp|date|jsonb|json|numeric|serial|bigserial|smallserial|tsvector|smallint|real|doublePrecision|char|inet|cidr|macaddr|macaddr8|interval|time|point|line|lseg|box|path|polygon|circle|bytea|bit|varbit|money|xml|oid';
28
+ const columnRegex = new RegExp(`^\\s*(\\w+):\\s*(${typePattern})(?:\\([^)]*\\))?((?:\\.[a-zA-Z]+\\([^)]*\\))*)`, 'gm');
29
+ let colMatch;
30
+ while ((colMatch = columnRegex.exec(columnsBlock)) !== null) {
31
+ const tsName = colMatch[1];
32
+ const type = colMatch[2];
33
+ const modifiers = colMatch[3] || '';
34
+ const explicitNameMatch = columnsBlock.match(new RegExp(`${tsName}:\\s*${type}\\s*\\(['\"]([^'"]+)['\"]`));
35
+ const dbColName = explicitNameMatch ? explicitNameMatch[1] : tsName;
36
+ columns.push({
37
+ name: dbColName,
38
+ tsName: tsName,
39
+ type: modifiers.includes('.array()') ? `${type}[]` : type,
40
+ nullable: !modifiers.includes('.notNull()') && !modifiers.includes('.primaryKey()'),
41
+ default: null,
42
+ primaryKey: modifiers.includes('.primaryKey()'),
43
+ unique: modifiers.includes('.unique()'),
44
+ });
45
+ }
46
+ const indexes = [];
47
+ const indexRegex = /index\s*\(\s*['"]([^'"]+)['"]\s*\)\.on\(([^)]+)\)/g;
48
+ let idxMatch;
49
+ while ((idxMatch = indexRegex.exec(optionsBlock)) !== null) {
50
+ const indexName = idxMatch[1];
51
+ const indexCols = idxMatch[2].split(',').map(c => c.trim().replace(/table\.\s*/, ''));
52
+ const isUnique = optionsBlock.includes(`index('${indexName}')`) &&
53
+ optionsBlock.substring(optionsBlock.indexOf(`index('${indexName}')`)).split('\n')[0].includes('.unique()');
54
+ indexes.push({
55
+ name: indexName,
56
+ columns: indexCols,
57
+ unique: isUnique,
58
+ type: 'btree',
59
+ });
60
+ }
61
+ const hasPartition = optionsBlock.includes('partitionBy');
62
+ let partitionType;
63
+ let partitionKey = [];
64
+ let partitions = [];
65
+ if (hasPartition) {
66
+ const partitionByMatch = optionsBlock.match(/partitionBy:\s*\([^)]+\)\s*=>\s*\w+\.(list|range|hash)\(([^)]+)\)/i);
67
+ if (partitionByMatch) {
68
+ partitionType = partitionByMatch[1].toUpperCase();
69
+ const colMatch = partitionByMatch[2].match(/table\.(\w+)/);
70
+ if (colMatch) {
71
+ partitionKey = [colMatch[1]];
72
+ }
73
+ }
74
+ const partitionsMatch = optionsBlock.match(/partitions:\s*\(partition\)\s*=>\s*\[([\s\S]*?)\]/);
75
+ if (partitionsMatch) {
76
+ const partitionsBlock = partitionsMatch[1];
77
+ const partitionRegex = /partition\s*\(\s*['"]([^'"]+)['"]\s*\)\.([^,\n]+)/g;
78
+ let pMatch;
79
+ while ((pMatch = partitionRegex.exec(partitionsBlock)) !== null) {
80
+ partitions.push({
81
+ name: pMatch[1],
82
+ bound: pMatch[2].trim(),
83
+ });
84
+ }
85
+ }
86
+ }
87
+ tables.push({
88
+ name: tableName,
89
+ schema: 'public',
90
+ columns,
91
+ indexes,
92
+ constraints: [],
93
+ ...(hasPartition && {
94
+ isPartitioned: true,
95
+ partitionType,
96
+ partitionKey,
97
+ partitions,
98
+ }),
99
+ });
100
+ }
101
+ const enums = [];
102
+ const enumRegex = /pgEnum\s*\(\s*['"]([^'"]+)['"]]/g;
103
+ let enumMatch;
104
+ while ((enumMatch = enumRegex.exec(content)) !== null) {
105
+ enums.push(enumMatch[1]);
106
+ }
107
+ return {
108
+ tables,
109
+ enums: [],
110
+ domains: [],
111
+ compositeTypes: [],
112
+ sequences: [],
113
+ collations: [],
114
+ functions: [],
115
+ triggers: [],
116
+ extensions: [],
117
+ };
118
+ }
119
+ function askConfirm(question, defaultYes = true) {
120
+ const suffix = defaultYes ? colors.muted('[Y/n]') : colors.muted('[y/N]');
121
+ const rl = readline.createInterface({
122
+ input: process.stdin,
123
+ output: process.stdout,
124
+ });
125
+ return new Promise((resolve) => {
126
+ rl.question(`${question} ${suffix}: `, (answer) => {
127
+ rl.close();
128
+ const a = answer.trim().toLowerCase();
129
+ if (!a)
130
+ resolve(defaultYes);
131
+ else
132
+ resolve(a === 'y' || a === 'yes');
133
+ });
134
+ });
135
+ }
136
+ export async function pullCommand(context) {
137
+ const { config, flags } = context;
138
+ if (!config) {
139
+ console.error('Error: No configuration found.');
140
+ process.exit(1);
141
+ }
142
+ requireValidConfig(config);
143
+ const connection = config.connection;
144
+ const projectRoot = process.cwd();
145
+ const force = flags['force'] === true;
146
+ const dryRun = flags['dry-run'] === true;
147
+ const author = config.author || 'Relq CLI';
148
+ const schemaPath = typeof config.schema === 'string' ? config.schema : './db/schema.ts';
149
+ const includeFunctions = config.generate?.includeFunctions ?? false;
150
+ const includeTriggers = config.generate?.includeTriggers ?? false;
151
+ const spinner = createSpinner();
152
+ const startTime = Date.now();
153
+ console.log('');
154
+ if (!isInitialized(projectRoot)) {
155
+ initRepository(projectRoot);
156
+ console.log(`${colors.cyan('ℹ')} Initialized .relq folder`);
157
+ }
158
+ if (!force) {
159
+ const stagedChanges = getStagedChanges(projectRoot);
160
+ const unstagedChanges = getUnstagedChanges(projectRoot);
161
+ if (stagedChanges.length > 0 || unstagedChanges.length > 0) {
162
+ const hasUnstaged = unstagedChanges.length > 0;
163
+ const hasStaged = stagedChanges.length > 0;
164
+ if (hasUnstaged && hasStaged) {
165
+ console.error(colors.red('Error: You have uncommitted and unstaged changes.'));
166
+ }
167
+ else if (hasStaged) {
168
+ console.error(colors.red('Error: You have uncommitted changes.'));
169
+ }
170
+ else {
171
+ console.error(colors.red('Error: You have unstaged changes.'));
172
+ }
173
+ console.log('');
174
+ if (hasStaged) {
175
+ console.log(` ${colors.green('Staged (uncommitted):')} ${stagedChanges.length} change(s)`);
176
+ }
177
+ if (hasUnstaged) {
178
+ console.log(` ${colors.red('Unstaged:')} ${unstagedChanges.length} change(s)`);
179
+ }
180
+ console.log('');
181
+ if (hasUnstaged && !hasStaged) {
182
+ console.log('Please stage and commit, or reset your changes:');
183
+ console.log(` ${colors.cyan('relq add .')} - stage all changes`);
184
+ console.log(` ${colors.cyan('relq commit -m "message"')} - then commit`);
185
+ }
186
+ else {
187
+ console.log('Please commit or reset your changes:');
188
+ console.log(` ${colors.cyan('relq commit -m "message"')} - commit staged changes`);
189
+ }
190
+ console.log(` ${colors.cyan('relq reset')} - discard all changes`);
191
+ console.log(` ${colors.cyan('relq pull --force')} - force pull (overwrites local changes)`);
192
+ return;
193
+ }
194
+ }
195
+ try {
196
+ spinner.start('Connecting to database...');
197
+ await ensureRemoteTable(connection);
198
+ spinner.succeed(`Connected to ${colors.cyan(getConnectionDescription(connection))}`);
199
+ spinner.start('Fetching remote commits...');
200
+ const remoteCommits = await fetchRemoteCommits(connection, 100);
201
+ const remoteHead = remoteCommits.length > 0 ? remoteCommits[0].hash : null;
202
+ if (remoteHead) {
203
+ setFetchHead(remoteHead, projectRoot);
204
+ }
205
+ spinner.succeed(`Fetched ${remoteCommits.length} remote commits`);
206
+ spinner.start('Introspecting database...');
207
+ const dbSchema = await fastIntrospectDatabase(connection, undefined, {
208
+ includeFunctions,
209
+ includeTriggers,
210
+ });
211
+ spinner.succeed(`Found ${dbSchema.tables.length} tables`);
212
+ const ignorePatterns = getIgnorePatterns(projectRoot);
213
+ const filteredTables = filterIgnored(dbSchema.tables, ignorePatterns);
214
+ const localHead = getHead(projectRoot);
215
+ const localSnapshot = loadSnapshot(projectRoot);
216
+ const schemaExists = fs.existsSync(schemaPath);
217
+ const currentSchema = {
218
+ tables: filteredTables.map(t => ({
219
+ name: t.name,
220
+ schema: t.schema,
221
+ columns: t.columns.map(c => ({
222
+ name: c.name,
223
+ tsName: toCamelCase(c.name),
224
+ type: c.dataType,
225
+ nullable: c.isNullable,
226
+ default: c.defaultValue,
227
+ primaryKey: c.isPrimaryKey,
228
+ unique: c.isUnique,
229
+ })),
230
+ indexes: t.indexes.map(i => ({
231
+ name: i.name,
232
+ columns: i.columns,
233
+ unique: i.isUnique,
234
+ type: i.type,
235
+ })),
236
+ constraints: t.constraints.map(c => ({
237
+ name: c.name,
238
+ type: c.type,
239
+ definition: c.definition,
240
+ })),
241
+ })),
242
+ enums: dbSchema.enums.map(e => ({
243
+ name: e.name,
244
+ schema: 'public',
245
+ values: e.values,
246
+ })),
247
+ domains: dbSchema.domains.map(d => ({
248
+ name: d.name,
249
+ schema: 'public',
250
+ baseType: d.baseType,
251
+ notNull: d.isNotNull || false,
252
+ default: d.defaultValue || null,
253
+ check: d.checkExpression || null,
254
+ })),
255
+ compositeTypes: dbSchema.compositeTypes.map(c => ({
256
+ name: c.name,
257
+ schema: 'public',
258
+ attributes: c.attributes,
259
+ })),
260
+ sequences: [],
261
+ collations: [],
262
+ functions: dbSchema.functions.map(f => ({
263
+ name: f.name,
264
+ returnType: f.returnType,
265
+ argTypes: f.argTypes,
266
+ language: f.language,
267
+ })),
268
+ triggers: dbSchema.triggers.map(t => ({
269
+ name: t.name,
270
+ table: t.tableName,
271
+ events: [t.event],
272
+ timing: t.timing,
273
+ forEach: 'STATEMENT',
274
+ functionName: t.functionName || '',
275
+ })),
276
+ extensions: dbSchema.extensions.map(ext => ({ name: ext })),
277
+ };
278
+ console.log('');
279
+ if (schemaExists && localSnapshot && !force) {
280
+ const localTables = new Set(localSnapshot.tables.map(t => t.name));
281
+ const remoteTables = new Set(currentSchema.tables.map(t => t.name));
282
+ const added = [...remoteTables].filter(t => !localTables.has(t));
283
+ const removed = [...localTables].filter(t => !remoteTables.has(t));
284
+ if (added.length === 0 && removed.length === 0) {
285
+ console.log(`${colors.green('✓')} Already up to date with remote`);
286
+ console.log('');
287
+ return;
288
+ }
289
+ console.log(`${colors.yellow('Remote has changes:')}`);
290
+ if (added.length > 0) {
291
+ console.log(` ${colors.green(`+${added.length}`)} tables added`);
292
+ }
293
+ if (removed.length > 0) {
294
+ console.log(` ${colors.red(`-${removed.length}`)} tables removed`);
295
+ }
296
+ console.log('');
297
+ if (!dryRun) {
298
+ const proceed = await askConfirm(`${colors.bold('Pull these changes?')}`, true);
299
+ if (!proceed) {
300
+ console.log('');
301
+ console.log(`${colors.muted('Cancelled.')}`);
302
+ return;
303
+ }
304
+ console.log('');
305
+ }
306
+ }
307
+ else if (schemaExists && !force) {
308
+ console.log(`${colors.yellow('⚠')} ${colors.bold('Local schema exists but not tracked')}`);
309
+ console.log('');
310
+ console.log(` ${colors.cyan(schemaPath)}`);
311
+ console.log('');
312
+ if (!dryRun) {
313
+ const proceed = await askConfirm(`${colors.bold('Overwrite local schema?')}`, false);
314
+ if (!proceed) {
315
+ console.log('');
316
+ console.log(`${colors.muted('Cancelled. Run')} ${colors.cyan('relq status')} ${colors.muted('to see current state.')}`);
317
+ return;
318
+ }
319
+ console.log('');
320
+ }
321
+ }
322
+ else if (!schemaExists) {
323
+ console.log(`${colors.cyan('ℹ')} ${colors.bold('First pull - creating schema')}`);
324
+ console.log('');
325
+ console.log(`📊 ${colors.bold('Schema Summary')}`);
326
+ console.log(` ${colors.green(String(filteredTables.length))} tables`);
327
+ console.log(` ${colors.green(String(dbSchema.extensions.length))} extensions`);
328
+ console.log('');
329
+ }
330
+ if (dryRun) {
331
+ console.log(`${colors.yellow('⚠')} Dry run - no files written`);
332
+ console.log('');
333
+ return;
334
+ }
335
+ spinner.start('Generating TypeScript schema...');
336
+ const typescript = generateTypeScript(dbSchema, {
337
+ includeDefineTables: true,
338
+ includeSchema: true,
339
+ includeIndexes: true,
340
+ includeFunctions,
341
+ includeTriggers,
342
+ camelCase: config.generate?.camelCase ?? true,
343
+ });
344
+ spinner.succeed('Generated TypeScript schema');
345
+ const schemaDir = path.dirname(schemaPath);
346
+ if (!fs.existsSync(schemaDir)) {
347
+ fs.mkdirSync(schemaDir, { recursive: true });
348
+ }
349
+ spinner.start('Writing schema file...');
350
+ fs.writeFileSync(schemaPath, typescript, 'utf-8');
351
+ const fileSize = Buffer.byteLength(typescript, 'utf8');
352
+ spinner.succeed(`Written ${colors.cyan(schemaPath)} ${colors.muted(`(${formatBytes(fileSize)})`)}`);
353
+ const snapshotFromFile = parseSchemaFileForSnapshot(schemaPath);
354
+ if (snapshotFromFile) {
355
+ saveSnapshot(snapshotFromFile, projectRoot);
356
+ }
357
+ else {
358
+ saveSnapshot(currentSchema, projectRoot);
359
+ }
360
+ spinner.start('Creating commit...');
361
+ const message = localHead ? 'Pulled schema from database' : 'Initial schema pull';
362
+ const commit = createCommit(currentSchema, author, message, projectRoot);
363
+ spinner.succeed(`Created commit ${colors.yellow(shortHash(commit.hash))}`);
364
+ const duration = Date.now() - startTime;
365
+ console.log('');
366
+ console.log(`${colors.green('✓')} Pull completed in ${colors.cyan(`${duration}ms`)}`);
367
+ console.log('');
368
+ }
369
+ catch (error) {
370
+ spinner.fail('Pull failed');
371
+ console.error(colors.red(`Error: ${error instanceof Error ? error.message : error}`));
372
+ process.exit(1);
373
+ }
374
+ }
@@ -0,0 +1,129 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { requireValidConfig } from "../utils/config-loader.js";
4
+ import { getConnectionDescription } from "../utils/env-loader.js";
5
+ import { colors, createSpinner } from "../utils/spinner.js";
6
+ import { isInitialized, getHead, shortHash, fetchRemoteCommits, pushCommit, ensureRemoteTable, getAllCommits, } from "../utils/repo-manager.js";
7
+ export async function pushCommand(context) {
8
+ const { config, flags } = context;
9
+ if (!config) {
10
+ console.error('Error: No configuration found.');
11
+ process.exit(1);
12
+ }
13
+ requireValidConfig(config);
14
+ const connection = config.connection;
15
+ const projectRoot = process.cwd();
16
+ const force = flags['force'] === true;
17
+ const dryRun = flags['dry-run'] === true;
18
+ const applySQL = flags['apply'] === true;
19
+ console.log('');
20
+ if (!isInitialized(projectRoot)) {
21
+ console.log(`${colors.red('fatal:')} not a relq repository`);
22
+ console.log('');
23
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq init')} ${colors.muted('to initialize.')}`);
24
+ return;
25
+ }
26
+ const localHead = getHead(projectRoot);
27
+ if (!localHead) {
28
+ console.log(`${colors.red('error:')} no commits to push`);
29
+ console.log('');
30
+ console.log(`${colors.muted('Run')} ${colors.cyan('relq commit -m "message"')} ${colors.muted('to create a commit.')}`);
31
+ return;
32
+ }
33
+ const spinner = createSpinner();
34
+ try {
35
+ spinner.start('Connecting to remote...');
36
+ await ensureRemoteTable(connection);
37
+ spinner.succeed(`Connected to ${colors.cyan(getConnectionDescription(connection))}`);
38
+ spinner.start('Checking remote...');
39
+ const remoteCommits = await fetchRemoteCommits(connection, 100);
40
+ const remoteHead = remoteCommits.length > 0 ? remoteCommits[0].hash : null;
41
+ spinner.stop();
42
+ const localCommits = getAllCommits(projectRoot);
43
+ const remoteHashes = new Set(remoteCommits.map(c => c.hash));
44
+ const localHashes = new Set(localCommits.map(c => c.hash));
45
+ const toPush = localCommits.filter(c => !remoteHashes.has(c.hash));
46
+ if (toPush.length === 0) {
47
+ console.log(`${colors.green('✓')} Everything up-to-date`);
48
+ console.log('');
49
+ return;
50
+ }
51
+ const remoteMissing = remoteCommits.filter(c => !localHashes.has(c.hash));
52
+ if (remoteMissing.length > 0 && !force) {
53
+ console.log(`${colors.red('error:')} failed to push`);
54
+ console.log('');
55
+ console.log(`${colors.yellow('hint:')} Updates were rejected because the remote contains work that you do not have locally.`);
56
+ console.log(`${colors.yellow('hint:')} Run ${colors.cyan('relq pull')} to integrate the remote changes before pushing.`);
57
+ console.log('');
58
+ return;
59
+ }
60
+ console.log(`Pushing to ${colors.cyan(getConnectionDescription(connection))}`);
61
+ console.log('');
62
+ if (dryRun) {
63
+ console.log(`${colors.yellow('Would push')} ${toPush.length} commit(s):`);
64
+ for (const commit of toPush.slice(0, 5)) {
65
+ console.log(` ${colors.yellow(shortHash(commit.hash))} ${commit.message}`);
66
+ }
67
+ if (toPush.length > 5) {
68
+ console.log(` ${colors.muted(`... and ${toPush.length - 5} more`)}`);
69
+ }
70
+ console.log('');
71
+ return;
72
+ }
73
+ const commitsToProcess = [...toPush].reverse();
74
+ spinner.start(`Pushing ${toPush.length} commit(s)...`);
75
+ for (const commit of commitsToProcess) {
76
+ await pushCommit(connection, commit);
77
+ }
78
+ spinner.succeed(`Pushed ${toPush.length} commit(s)`);
79
+ if (applySQL) {
80
+ spinner.start('Applying SQL changes...');
81
+ const pg = await import("../../addon/pg.js");
82
+ const client = new pg.Client({
83
+ host: connection.host,
84
+ port: connection.port,
85
+ database: connection.database,
86
+ user: connection.user,
87
+ password: connection.password,
88
+ });
89
+ try {
90
+ await client.connect();
91
+ let sqlExecuted = 0;
92
+ for (const commit of commitsToProcess) {
93
+ const commitPath = path.join(projectRoot, '.relq', 'commits', `${commit.hash}.json`);
94
+ if (fs.existsSync(commitPath)) {
95
+ const enhancedCommit = JSON.parse(fs.readFileSync(commitPath, 'utf-8'));
96
+ if (enhancedCommit.sql) {
97
+ await client.query(enhancedCommit.sql);
98
+ sqlExecuted++;
99
+ }
100
+ }
101
+ }
102
+ spinner.succeed(`Applied SQL from ${sqlExecuted} commit(s)`);
103
+ }
104
+ finally {
105
+ await client.end();
106
+ }
107
+ }
108
+ const oldHash = remoteHead ? shortHash(remoteHead) : '(none)';
109
+ const newHash = shortHash(localHead);
110
+ console.log(` ${oldHash}..${newHash} ${colors.muted('main -> main')}`);
111
+ if (!applySQL && toPush.some(c => {
112
+ const commitPath = path.join(projectRoot, '.relq', 'commits', `${c.hash}.json`);
113
+ if (fs.existsSync(commitPath)) {
114
+ const ec = JSON.parse(fs.readFileSync(commitPath, 'utf-8'));
115
+ return ec.sql && ec.sql.trim().length > 0;
116
+ }
117
+ return false;
118
+ })) {
119
+ console.log('');
120
+ console.log(`${colors.muted('Use')} ${colors.cyan('relq push --apply')} ${colors.muted('to also execute SQL against database.')}`);
121
+ }
122
+ }
123
+ catch (error) {
124
+ spinner.fail('Push failed');
125
+ console.error(colors.red(`Error: ${error instanceof Error ? error.message : error}`));
126
+ process.exit(1);
127
+ }
128
+ console.log('');
129
+ }