@intentius/sql-yodeler 0.0.0-stage → 0.2.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 (324) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +112 -2
  3. package/dist/bin.d.ts +2 -0
  4. package/dist/bin.js +29 -0
  5. package/dist/bin.js.map +1 -0
  6. package/dist/chant/apply.d.ts +59 -0
  7. package/dist/chant/apply.js +116 -0
  8. package/dist/chant/apply.js.map +1 -0
  9. package/dist/chant/build.d.ts +34 -0
  10. package/dist/chant/build.js +48 -0
  11. package/dist/chant/build.js.map +1 -0
  12. package/dist/chant/drift.d.ts +112 -0
  13. package/dist/chant/drift.js +238 -0
  14. package/dist/chant/drift.js.map +1 -0
  15. package/dist/chant/plan.d.ts +45 -0
  16. package/dist/chant/plan.js +61 -0
  17. package/dist/chant/plan.js.map +1 -0
  18. package/dist/chant/process.d.ts +41 -0
  19. package/dist/chant/process.js +87 -0
  20. package/dist/chant/process.js.map +1 -0
  21. package/dist/chant/runnable.d.ts +19 -0
  22. package/dist/chant/runnable.js +47 -0
  23. package/dist/chant/runnable.js.map +1 -0
  24. package/dist/cli.d.ts +8 -0
  25. package/dist/cli.js +99 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/command.d.ts +23 -0
  28. package/dist/command.js +13 -0
  29. package/dist/command.js.map +1 -0
  30. package/dist/commands/apply.d.ts +3 -0
  31. package/dist/commands/apply.js +426 -0
  32. package/dist/commands/apply.js.map +1 -0
  33. package/dist/commands/approve.d.ts +5 -0
  34. package/dist/commands/approve.js +111 -0
  35. package/dist/commands/approve.js.map +1 -0
  36. package/dist/commands/drift.d.ts +14 -0
  37. package/dist/commands/drift.js +267 -0
  38. package/dist/commands/drift.js.map +1 -0
  39. package/dist/commands/index.d.ts +3 -0
  40. package/dist/commands/index.js +28 -0
  41. package/dist/commands/index.js.map +1 -0
  42. package/dist/commands/init.d.ts +6 -0
  43. package/dist/commands/init.js +139 -0
  44. package/dist/commands/init.js.map +1 -0
  45. package/dist/commands/lint.d.ts +3 -0
  46. package/dist/commands/lint.js +202 -0
  47. package/dist/commands/lint.js.map +1 -0
  48. package/dist/commands/mcp.d.ts +3 -0
  49. package/dist/commands/mcp.js +50 -0
  50. package/dist/commands/mcp.js.map +1 -0
  51. package/dist/commands/new.d.ts +5 -0
  52. package/dist/commands/new.js +292 -0
  53. package/dist/commands/new.js.map +1 -0
  54. package/dist/commands/override.d.ts +3 -0
  55. package/dist/commands/override.js +118 -0
  56. package/dist/commands/override.js.map +1 -0
  57. package/dist/commands/plan.d.ts +3 -0
  58. package/dist/commands/plan.js +183 -0
  59. package/dist/commands/plan.js.map +1 -0
  60. package/dist/commands/rebase.d.ts +3 -0
  61. package/dist/commands/rebase.js +167 -0
  62. package/dist/commands/rebase.js.map +1 -0
  63. package/dist/commands/repair.d.ts +14 -0
  64. package/dist/commands/repair.js +125 -0
  65. package/dist/commands/repair.js.map +1 -0
  66. package/dist/commands/status.d.ts +7 -0
  67. package/dist/commands/status.js +54 -0
  68. package/dist/commands/status.js.map +1 -0
  69. package/dist/config/define.d.ts +148 -0
  70. package/dist/config/define.js +20 -0
  71. package/dist/config/define.js.map +1 -0
  72. package/dist/config/index.d.ts +11 -0
  73. package/dist/config/index.js +12 -0
  74. package/dist/config/index.js.map +1 -0
  75. package/dist/config/load.d.ts +17 -0
  76. package/dist/config/load.js +162 -0
  77. package/dist/config/load.js.map +1 -0
  78. package/dist/config/settings.d.ts +53 -0
  79. package/dist/config/settings.js +116 -0
  80. package/dist/config/settings.js.map +1 -0
  81. package/dist/env-args.d.ts +24 -0
  82. package/dist/env-args.js +92 -0
  83. package/dist/env-args.js.map +1 -0
  84. package/dist/exit.d.ts +20 -0
  85. package/dist/exit.js +28 -0
  86. package/dist/exit.js.map +1 -0
  87. package/dist/history/client.d.ts +25 -0
  88. package/dist/history/client.js +42 -0
  89. package/dist/history/client.js.map +1 -0
  90. package/dist/history/ddl.d.ts +58 -0
  91. package/dist/history/ddl.js +100 -0
  92. package/dist/history/ddl.js.map +1 -0
  93. package/dist/history/index.d.ts +25 -0
  94. package/dist/history/index.js +26 -0
  95. package/dist/history/index.js.map +1 -0
  96. package/dist/history/lock.d.ts +104 -0
  97. package/dist/history/lock.js +230 -0
  98. package/dist/history/lock.js.map +1 -0
  99. package/dist/history/postgres/ddl.d.ts +22 -0
  100. package/dist/history/postgres/ddl.js +47 -0
  101. package/dist/history/postgres/ddl.js.map +1 -0
  102. package/dist/history/postgres/index.d.ts +12 -0
  103. package/dist/history/postgres/index.js +13 -0
  104. package/dist/history/postgres/index.js.map +1 -0
  105. package/dist/history/postgres/lock.d.ts +48 -0
  106. package/dist/history/postgres/lock.js +95 -0
  107. package/dist/history/postgres/lock.js.map +1 -0
  108. package/dist/history/postgres/store.d.ts +39 -0
  109. package/dist/history/postgres/store.js +68 -0
  110. package/dist/history/postgres/store.js.map +1 -0
  111. package/dist/history/rows.d.ts +96 -0
  112. package/dist/history/rows.js +73 -0
  113. package/dist/history/rows.js.map +1 -0
  114. package/dist/history/store.d.ts +72 -0
  115. package/dist/history/store.js +134 -0
  116. package/dist/history/store.js.map +1 -0
  117. package/dist/history/topology.d.ts +41 -0
  118. package/dist/history/topology.js +54 -0
  119. package/dist/history/topology.js.map +1 -0
  120. package/dist/index.d.ts +10 -0
  121. package/dist/index.js +10 -0
  122. package/dist/index.js.map +1 -0
  123. package/dist/init/adopt.d.ts +70 -0
  124. package/dist/init/adopt.js +143 -0
  125. package/dist/init/adopt.js.map +1 -0
  126. package/dist/init/baseline.d.ts +61 -0
  127. package/dist/init/baseline.js +88 -0
  128. package/dist/init/baseline.js.map +1 -0
  129. package/dist/init/files.d.ts +23 -0
  130. package/dist/init/files.js +77 -0
  131. package/dist/init/files.js.map +1 -0
  132. package/dist/init/index.d.ts +16 -0
  133. package/dist/init/index.js +17 -0
  134. package/dist/init/index.js.map +1 -0
  135. package/dist/init/live.d.ts +39 -0
  136. package/dist/init/live.js +68 -0
  137. package/dist/init/live.js.map +1 -0
  138. package/dist/lint/check.d.ts +88 -0
  139. package/dist/lint/check.js +227 -0
  140. package/dist/lint/check.js.map +1 -0
  141. package/dist/lint/config.d.ts +21 -0
  142. package/dist/lint/config.js +43 -0
  143. package/dist/lint/config.js.map +1 -0
  144. package/dist/lint/index.d.ts +31 -0
  145. package/dist/lint/index.js +43 -0
  146. package/dist/lint/index.js.map +1 -0
  147. package/dist/lint/project-rules.d.ts +19 -0
  148. package/dist/lint/project-rules.js +32 -0
  149. package/dist/lint/project-rules.js.map +1 -0
  150. package/dist/lint/report.d.ts +7 -0
  151. package/dist/lint/report.js +48 -0
  152. package/dist/lint/report.js.map +1 -0
  153. package/dist/lint/rules.d.ts +53 -0
  154. package/dist/lint/rules.js +42 -0
  155. package/dist/lint/rules.js.map +1 -0
  156. package/dist/lint/silences.d.ts +49 -0
  157. package/dist/lint/silences.js +91 -0
  158. package/dist/lint/silences.js.map +1 -0
  159. package/dist/lint/statements.d.ts +38 -0
  160. package/dist/lint/statements.js +120 -0
  161. package/dist/lint/statements.js.map +1 -0
  162. package/dist/mcp/server.d.ts +40 -0
  163. package/dist/mcp/server.js +106 -0
  164. package/dist/mcp/server.js.map +1 -0
  165. package/dist/mcp/tools.d.ts +72 -0
  166. package/dist/mcp/tools.js +178 -0
  167. package/dist/mcp/tools.js.map +1 -0
  168. package/dist/migrations/checks.d.ts +28 -0
  169. package/dist/migrations/checks.js +97 -0
  170. package/dist/migrations/checks.js.map +1 -0
  171. package/dist/migrations/checksum.d.ts +56 -0
  172. package/dist/migrations/checksum.js +72 -0
  173. package/dist/migrations/checksum.js.map +1 -0
  174. package/dist/migrations/create.d.ts +75 -0
  175. package/dist/migrations/create.js +120 -0
  176. package/dist/migrations/create.js.map +1 -0
  177. package/dist/migrations/directory.d.ts +119 -0
  178. package/dist/migrations/directory.js +229 -0
  179. package/dist/migrations/directory.js.map +1 -0
  180. package/dist/migrations/document.d.ts +106 -0
  181. package/dist/migrations/document.js +83 -0
  182. package/dist/migrations/document.js.map +1 -0
  183. package/dist/migrations/index.d.ts +21 -0
  184. package/dist/migrations/index.js +22 -0
  185. package/dist/migrations/index.js.map +1 -0
  186. package/dist/pr/comment.d.ts +32 -0
  187. package/dist/pr/comment.js +99 -0
  188. package/dist/pr/comment.js.map +1 -0
  189. package/dist/pr/forge.d.ts +54 -0
  190. package/dist/pr/forge.js +119 -0
  191. package/dist/pr/forge.js.map +1 -0
  192. package/dist/pr/issue.d.ts +68 -0
  193. package/dist/pr/issue.js +107 -0
  194. package/dist/pr/issue.js.map +1 -0
  195. package/dist/pr/model.d.ts +99 -0
  196. package/dist/pr/model.js +137 -0
  197. package/dist/pr/model.js.map +1 -0
  198. package/dist/pr/render.d.ts +29 -0
  199. package/dist/pr/render.js +279 -0
  200. package/dist/pr/render.js.map +1 -0
  201. package/dist/project.d.ts +62 -0
  202. package/dist/project.js +92 -0
  203. package/dist/project.js.map +1 -0
  204. package/dist/rebase/index.d.ts +121 -0
  205. package/dist/rebase/index.js +390 -0
  206. package/dist/rebase/index.js.map +1 -0
  207. package/dist/rebase/repair.d.ts +41 -0
  208. package/dist/rebase/repair.js +68 -0
  209. package/dist/rebase/repair.js.map +1 -0
  210. package/dist/replay/clickhouse.d.ts +33 -0
  211. package/dist/replay/clickhouse.js +106 -0
  212. package/dist/replay/clickhouse.js.map +1 -0
  213. package/dist/replay/index.d.ts +39 -0
  214. package/dist/replay/index.js +57 -0
  215. package/dist/replay/index.js.map +1 -0
  216. package/dist/replay/postgres.d.ts +31 -0
  217. package/dist/replay/postgres.js +140 -0
  218. package/dist/replay/postgres.js.map +1 -0
  219. package/dist/replay/replay.d.ts +114 -0
  220. package/dist/replay/replay.js +98 -0
  221. package/dist/replay/replay.js.map +1 -0
  222. package/dist/replay/report.d.ts +18 -0
  223. package/dist/replay/report.js +72 -0
  224. package/dist/replay/report.js.map +1 -0
  225. package/dist/replay/shared.d.ts +28 -0
  226. package/dist/replay/shared.js +77 -0
  227. package/dist/replay/shared.js.map +1 -0
  228. package/dist/schemas.d.ts +34 -0
  229. package/dist/schemas.js +38 -0
  230. package/dist/schemas.js.map +1 -0
  231. package/dist/server.d.ts +40 -0
  232. package/dist/server.js +87 -0
  233. package/dist/server.js.map +1 -0
  234. package/dist/steps/backfill.d.ts +132 -0
  235. package/dist/steps/backfill.js +307 -0
  236. package/dist/steps/backfill.js.map +1 -0
  237. package/dist/steps/index.d.ts +52 -0
  238. package/dist/steps/index.js +52 -0
  239. package/dist/steps/index.js.map +1 -0
  240. package/dist/steps/kinds.d.ts +101 -0
  241. package/dist/steps/kinds.js +143 -0
  242. package/dist/steps/kinds.js.map +1 -0
  243. package/dist/steps/postgres-migration.d.ts +95 -0
  244. package/dist/steps/postgres-migration.js +149 -0
  245. package/dist/steps/postgres-migration.js.map +1 -0
  246. package/dist/steps/rebuild.d.ts +97 -0
  247. package/dist/steps/rebuild.js +155 -0
  248. package/dist/steps/rebuild.js.map +1 -0
  249. package/dist/steps/run.d.ts +45 -0
  250. package/dist/steps/run.js +72 -0
  251. package/dist/steps/run.js.map +1 -0
  252. package/dist/topology/render.d.ts +17 -0
  253. package/dist/topology/render.js +17 -0
  254. package/dist/topology/render.js.map +1 -0
  255. package/dist/version.d.ts +2 -0
  256. package/dist/version.js +11 -0
  257. package/dist/version.js.map +1 -0
  258. package/dist/versioned/approval.d.ts +35 -0
  259. package/dist/versioned/approval.js +53 -0
  260. package/dist/versioned/approval.js.map +1 -0
  261. package/dist/versioned/checks.d.ts +29 -0
  262. package/dist/versioned/checks.js +54 -0
  263. package/dist/versioned/checks.js.map +1 -0
  264. package/dist/versioned/clickhouse.d.ts +24 -0
  265. package/dist/versioned/clickhouse.js +42 -0
  266. package/dist/versioned/clickhouse.js.map +1 -0
  267. package/dist/versioned/digest.d.ts +77 -0
  268. package/dist/versioned/digest.js +69 -0
  269. package/dist/versioned/digest.js.map +1 -0
  270. package/dist/versioned/driver.d.ts +51 -0
  271. package/dist/versioned/driver.js +13 -0
  272. package/dist/versioned/driver.js.map +1 -0
  273. package/dist/versioned/engine.d.ts +206 -0
  274. package/dist/versioned/engine.js +370 -0
  275. package/dist/versioned/engine.js.map +1 -0
  276. package/dist/versioned/explain.d.ts +123 -0
  277. package/dist/versioned/explain.js +294 -0
  278. package/dist/versioned/explain.js.map +1 -0
  279. package/dist/versioned/index.d.ts +46 -0
  280. package/dist/versioned/index.js +77 -0
  281. package/dist/versioned/index.js.map +1 -0
  282. package/dist/versioned/op.d.ts +72 -0
  283. package/dist/versioned/op.js +185 -0
  284. package/dist/versioned/op.js.map +1 -0
  285. package/dist/versioned/policy.d.ts +67 -0
  286. package/dist/versioned/policy.js +161 -0
  287. package/dist/versioned/policy.js.map +1 -0
  288. package/dist/versioned/postgres/catalog.d.ts +33 -0
  289. package/dist/versioned/postgres/catalog.js +34 -0
  290. package/dist/versioned/postgres/catalog.js.map +1 -0
  291. package/dist/versioned/postgres/driver.d.ts +71 -0
  292. package/dist/versioned/postgres/driver.js +140 -0
  293. package/dist/versioned/postgres/driver.js.map +1 -0
  294. package/dist/versioned/postgres/executor.d.ts +104 -0
  295. package/dist/versioned/postgres/executor.js +172 -0
  296. package/dist/versioned/postgres/executor.js.map +1 -0
  297. package/dist/versioned/postgres/index.d.ts +11 -0
  298. package/dist/versioned/postgres/index.js +12 -0
  299. package/dist/versioned/postgres/index.js.map +1 -0
  300. package/dist/versioned/postgres/waits.d.ts +46 -0
  301. package/dist/versioned/postgres/waits.js +78 -0
  302. package/dist/versioned/postgres/waits.js.map +1 -0
  303. package/dist/versioned/report.d.ts +25 -0
  304. package/dist/versioned/report.js +84 -0
  305. package/dist/versioned/report.js.map +1 -0
  306. package/dist/versioned/stand-down.d.ts +30 -0
  307. package/dist/versioned/stand-down.js +56 -0
  308. package/dist/versioned/stand-down.js.map +1 -0
  309. package/dist/versioned/state.d.ts +108 -0
  310. package/dist/versioned/state.js +153 -0
  311. package/dist/versioned/state.js.map +1 -0
  312. package/package.json +61 -4
  313. package/schemas/apply.schema.json +269 -0
  314. package/schemas/common.schema.json +213 -0
  315. package/schemas/drift.schema.json +36 -0
  316. package/schemas/init.schema.json +31 -0
  317. package/schemas/lint-rules.schema.json +54 -0
  318. package/schemas/lint.schema.json +290 -0
  319. package/schemas/mcp.schema.json +70 -0
  320. package/schemas/new.schema.json +71 -0
  321. package/schemas/plan.schema.json +371 -0
  322. package/schemas/rebase.schema.json +54 -0
  323. package/schemas/repair.schema.json +20 -0
  324. package/schemas/status.schema.json +310 -0
@@ -0,0 +1,162 @@
1
+ /**
2
+ * Finding, loading and checking `yodel.config.ts`. The file is optional; a
3
+ * project without one gets `undefined` and every setting's default.
4
+ */
5
+ import { existsSync } from "node:fs";
6
+ import { join } from "node:path";
7
+ import { pathToFileURL } from "node:url";
8
+ import { parseTopology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
9
+ import { YodelError } from "../project.js";
10
+ export const CONFIG_FILE = "yodel.config.ts";
11
+ const isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
12
+ const TOPOLOGY_KINDS = ["single", "cluster", "replicated", "cloud"];
13
+ function checkTopology(value, where) {
14
+ if (typeof value === "string") {
15
+ try {
16
+ parseTopology(value);
17
+ }
18
+ catch (e) {
19
+ throw new YodelError(`${where}: ${e instanceof Error ? e.message : String(e)}`);
20
+ }
21
+ return;
22
+ }
23
+ if (!isRecord(value) || typeof value.kind !== "string" || !TOPOLOGY_KINDS.includes(value.kind)) {
24
+ throw new YodelError(`${where}: expected single, cluster:<name>, replicated, replicated:<cluster>, cloud, or { kind: ... }`);
25
+ }
26
+ const allowed = { single: [], cloud: [], replicated: ["cluster"], cluster: ["cluster", "replicaPath", "replicaName"] };
27
+ for (const [k, v] of Object.entries(value)) {
28
+ if (k === "kind")
29
+ continue;
30
+ if (!(allowed[value.kind] ?? []).includes(k))
31
+ throw new YodelError(`${where}.${k}: a ${value.kind} topology takes no ${k}`);
32
+ if (typeof v !== "string" || v === "")
33
+ throw new YodelError(`${where}.${k}: expected a non-empty string`);
34
+ }
35
+ if (value.kind === "cluster" && typeof value.cluster !== "string")
36
+ throw new YodelError(`${where}.cluster: a cluster topology needs the cluster's name`);
37
+ }
38
+ function checkEnvironment(value, where) {
39
+ if (!isRecord(value))
40
+ throw new YodelError(`${where}: expected an object`);
41
+ for (const k of Object.keys(value)) {
42
+ if (!["topology", "history", "lockTtl", "lockWait"].includes(k))
43
+ throw new YodelError(`${where}.${k}: unknown setting (expected topology, history, lockTtl, lockWait)`);
44
+ }
45
+ if (value.topology !== undefined)
46
+ checkTopology(value.topology, `${where}.topology`);
47
+ if (value.history !== undefined) {
48
+ if (!isRecord(value.history))
49
+ throw new YodelError(`${where}.history: expected an object`);
50
+ for (const k of Object.keys(value.history))
51
+ if (k !== "database")
52
+ throw new YodelError(`${where}.history.${k}: unknown setting (expected database)`);
53
+ const db = value.history.database;
54
+ if (db !== undefined && (typeof db !== "string" || db === ""))
55
+ throw new YodelError(`${where}.history.database: expected a database name`);
56
+ }
57
+ if (value.lockTtl !== undefined && !(typeof value.lockTtl === "number" && Number.isFinite(value.lockTtl) && value.lockTtl > 0)) {
58
+ throw new YodelError(`${where}.lockTtl: expected a number of seconds greater than 0`);
59
+ }
60
+ if (value.lockWait !== undefined && !(typeof value.lockWait === "number" && Number.isFinite(value.lockWait) && value.lockWait >= 0)) {
61
+ throw new YodelError(`${where}.lockWait: expected a number of seconds, 0 or more`);
62
+ }
63
+ return value;
64
+ }
65
+ const RULE_ID = /^[a-z0-9][a-z0-9_-]*$/;
66
+ function checkPolicy(value, where, profiles) {
67
+ if (!isRecord(value))
68
+ throw new YodelError(`${where}: expected { rules: [...], overriders?: [...] }`);
69
+ for (const k of Object.keys(value))
70
+ if (k !== "rules" && k !== "overriders")
71
+ throw new YodelError(`${where}.${k}: unknown setting (expected rules, overriders)`);
72
+ if (value.overriders !== undefined && !(Array.isArray(value.overriders) && value.overriders.every((o) => typeof o === "string" && o !== ""))) {
73
+ throw new YodelError(`${where}.overriders: expected a list of names`);
74
+ }
75
+ if (!Array.isArray(value.rules))
76
+ throw new YodelError(`${where}.rules: expected a list of rules`);
77
+ const seen = new Set();
78
+ for (const [i, rule] of value.rules.entries()) {
79
+ const at = `${where}.rules[${String(i)}]`;
80
+ if (!isRecord(rule))
81
+ throw new YodelError(`${at}: expected an object`);
82
+ for (const k of Object.keys(rule)) {
83
+ if (!["id", "description", "environments", "refuse", "silences", "check"].includes(k))
84
+ throw new YodelError(`${at}.${k}: unknown setting (expected id, description, environments, refuse, silences, check)`);
85
+ }
86
+ if (typeof rule.id !== "string" || !RULE_ID.test(rule.id))
87
+ throw new YodelError(`${at}.id: lowercase letters, digits, - and _, got ${JSON.stringify(rule.id)}`);
88
+ if (seen.has(rule.id))
89
+ throw new YodelError(`${at}.id: two rules are named ${rule.id}`);
90
+ seen.add(rule.id);
91
+ if (rule.environments !== undefined) {
92
+ if (!Array.isArray(rule.environments) || !rule.environments.every((e) => typeof e === "string"))
93
+ throw new YodelError(`${at}.environments: expected a list of environment names`);
94
+ const unknown = profiles ? rule.environments.filter((e) => !profiles.includes(e)) : [];
95
+ if (unknown.length > 0)
96
+ throw new YodelError(`${at}.environments: ${unknown.join(", ")} ${unknown.length === 1 ? "is not an environment" : "are not environments"} chant.config.ts declares`);
97
+ }
98
+ if (rule.refuse === undefined && rule.silences === undefined && rule.check === undefined)
99
+ throw new YodelError(`${at}: a rule needs refuse, silences or check`);
100
+ if (rule.refuse !== undefined) {
101
+ const r = rule.refuse;
102
+ if (!isRecord(r) || Object.keys(r).some((k) => k !== "classes" && k !== "destructive"))
103
+ throw new YodelError(`${at}.refuse: expected { classes?: [...], destructive?: true }`);
104
+ if (r.classes !== undefined && !(Array.isArray(r.classes) && r.classes.every((c) => typeof c === "string")))
105
+ throw new YodelError(`${at}.refuse.classes: expected a list of classes`);
106
+ if (r.destructive !== undefined && typeof r.destructive !== "boolean")
107
+ throw new YodelError(`${at}.refuse.destructive: expected true or false`);
108
+ }
109
+ if (rule.silences !== undefined) {
110
+ const s = rule.silences;
111
+ if (!isRecord(s) || !(s.reason instanceof RegExp) || Object.keys(s).some((k) => k !== "rules" && k !== "reason"))
112
+ throw new YodelError(`${at}.silences: expected { reason: /pattern/, rules?: [...] }`);
113
+ if (s.rules !== undefined && !(Array.isArray(s.rules) && s.rules.every((x) => typeof x === "string")))
114
+ throw new YodelError(`${at}.silences.rules: expected a list of lint rules`);
115
+ }
116
+ if (rule.check !== undefined && typeof rule.check !== "function")
117
+ throw new YodelError(`${at}.check: expected a function of the plan`);
118
+ }
119
+ }
120
+ /**
121
+ * Checks a loaded config's shape. `environments` names each environment by
122
+ * its `sql.profiles` name; one that chant.config.ts does not declare is an
123
+ * error, so a typo does not silently leave an environment on the defaults.
124
+ */
125
+ export function checkYodelConfig(value, path, profiles) {
126
+ if (!isRecord(value))
127
+ throw new YodelError(`${path}: the default export must be a config object (export default defineConfig({ ... }))`);
128
+ for (const k of Object.keys(value)) {
129
+ if (k !== "environments" && k !== "lint" && k !== "policy")
130
+ throw new YodelError(`${path}: unknown setting ${k} (expected environments, lint, policy)`);
131
+ }
132
+ if (value.policy !== undefined)
133
+ checkPolicy(value.policy, `${path}: policy`, profiles);
134
+ if (value.lint !== undefined && !isRecord(value.lint))
135
+ throw new YodelError(`${path}: lint: expected an object`);
136
+ if (value.environments !== undefined) {
137
+ if (!isRecord(value.environments))
138
+ throw new YodelError(`${path}: environments: expected an object keyed by environment`);
139
+ for (const [name, env] of Object.entries(value.environments)) {
140
+ checkEnvironment(env, `${path}: environments.${name}`);
141
+ if (profiles && !profiles.includes(name)) {
142
+ throw new YodelError(`${path}: environments.${name} is not an environment chant.config.ts declares` + (profiles.length > 0 ? ` (sql.profiles: ${profiles.join(", ")})` : " (it declares no sql.profiles)"));
143
+ }
144
+ }
145
+ }
146
+ return value;
147
+ }
148
+ /** Loads `<dir>/yodel.config.ts`, or `undefined` when there is none. */
149
+ export async function loadYodelConfig(dir, profiles) {
150
+ const path = join(dir, CONFIG_FILE);
151
+ if (!existsSync(path))
152
+ return undefined;
153
+ let mod;
154
+ try {
155
+ mod = (await import(pathToFileURL(path).href));
156
+ }
157
+ catch (e) {
158
+ throw new YodelError(`${path}: ${e instanceof Error ? e.message : String(e)}`);
159
+ }
160
+ return { path, config: checkYodelConfig(mod.default, path, profiles) };
161
+ }
162
+ //# sourceMappingURL=load.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"load.js","sourceRoot":"","sources":["../../src/config/load.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * One environment's settings, from `yodel.config.ts`, chant's profile and
3
+ * the process environment, first one set wins:
4
+ *
5
+ * | setting | 1. yodel.config.ts | 2. chant.config.ts | 3. env var | default |
6
+ * |------------------|----------------------------------------|-----------------------------------|-------------------------|----------|
7
+ * | topology | `environments.<env>.topology` | `sql.profiles.<env>.topology` | `YODEL_TOPOLOGY` | `single` |
8
+ * | history database | `environments.<env>.history.database` | | `YODEL_HISTORY_DATABASE`| `yodeler`|
9
+ * | lock TTL | `environments.<env>.lockTtl` (seconds) | | `YODEL_LOCK_TTL` | 900 |
10
+ * | lock wait | `environments.<env>.lockWait` (seconds)| | `YODEL_LOCK_WAIT` | 0 |
11
+ *
12
+ * `yodel apply --lock-wait <duration>` sets the lock wait over all three.
13
+ */
14
+ import { type Topology } from "@intentius/chant-lexicon-sql/clickhouse/topology";
15
+ import type { HistoryTopology } from "../history/topology.js";
16
+ import { YodelError, type Project } from "../project.js";
17
+ export interface EnvironmentSettings {
18
+ /** What every statement is rendered for when it is sent. */
19
+ topology: Topology;
20
+ /** Where {@link topology} came from, for messages: `yodel.config.ts`, `sql.profiles.<env>.topology`, `YODEL_TOPOLOGY` or `default`. */
21
+ topologySource: string;
22
+ /**
23
+ * The history's topology: {@link topology} without a cluster's Keeper
24
+ * path and replica name, which are for the migrations' tables. The
25
+ * history keeps its own path, one copy for the whole cluster.
26
+ */
27
+ historyTopology: HistoryTopology;
28
+ historyDatabase: string;
29
+ lockTtlMs: number;
30
+ /** How long an apply waits for a lock another apply holds; 0 gives up at once (exit 5). */
31
+ lockWaitMs: number;
32
+ }
33
+ /** The variable that sets the lock wait (a duration, as {@link parseDuration} reads it). */
34
+ export declare const LOCK_WAIT_ENV = "YODEL_LOCK_WAIT";
35
+ /**
36
+ * A duration in milliseconds: `90` (seconds), `500ms`, `30s`, `10m`, `1h`,
37
+ * or a sum of them (`1m30s`). `what` names it in the error.
38
+ */
39
+ export declare function parseDuration(text: string, what: string): number;
40
+ /** The topology the history's DDL is written for. */
41
+ export declare function historyTopologyOf(t: Topology): HistoryTopology;
42
+ /** The settings of environment `name`; see the module comment for the order. */
43
+ export declare function environmentSettings(project: Pick<Project, "config" | "yodel">, name: string, env?: NodeJS.ProcessEnv): EnvironmentSettings;
44
+ /** `cluster:main (yodel.config.ts)`, for a report's header. */
45
+ export declare const describeSettingsTopology: (s: Pick<EnvironmentSettings, "topology" | "topologySource">) => string;
46
+ /**
47
+ * The declarative path (`yodel plan`, `yodel apply` without migrations) runs
48
+ * chant's planner and applier, which render for `sql.profiles.<env>.topology`
49
+ * and do not read `yodel.config.ts`. A topology set only in yodel.config.ts
50
+ * would be ignored there, so it is refused unless chant's profile says the same
51
+ * (an unset profile topology is a single node, as chant renders it).
52
+ */
53
+ export declare function declarativeTopologyRefusal(project: Pick<Project, "config" | "yodel">, name: string): YodelError | undefined;
@@ -0,0 +1,116 @@
1
+ /**
2
+ * One environment's settings, from `yodel.config.ts`, chant's profile and
3
+ * the process environment, first one set wins:
4
+ *
5
+ * | setting | 1. yodel.config.ts | 2. chant.config.ts | 3. env var | default |
6
+ * |------------------|----------------------------------------|-----------------------------------|-------------------------|----------|
7
+ * | topology | `environments.<env>.topology` | `sql.profiles.<env>.topology` | `YODEL_TOPOLOGY` | `single` |
8
+ * | history database | `environments.<env>.history.database` | | `YODEL_HISTORY_DATABASE`| `yodeler`|
9
+ * | lock TTL | `environments.<env>.lockTtl` (seconds) | | `YODEL_LOCK_TTL` | 900 |
10
+ * | lock wait | `environments.<env>.lockWait` (seconds)| | `YODEL_LOCK_WAIT` | 0 |
11
+ *
12
+ * `yodel apply --lock-wait <duration>` sets the lock wait over all three.
13
+ */
14
+ import { toTopology, topologyLabel } from "@intentius/chant-lexicon-sql/clickhouse/topology";
15
+ import { DEFAULT_HISTORY_DATABASE } from "../history/ddl.js";
16
+ import { DEFAULT_LOCK_TTL_MS } from "../history/lock.js";
17
+ import { YodelError } from "../project.js";
18
+ import { CONFIG_FILE } from "./load.js";
19
+ /** The variable that sets the lock wait (a duration, as {@link parseDuration} reads it). */
20
+ export const LOCK_WAIT_ENV = "YODEL_LOCK_WAIT";
21
+ const UNITS = { ms: 1, s: 1000, m: 60_000, h: 3_600_000 };
22
+ /**
23
+ * A duration in milliseconds: `90` (seconds), `500ms`, `30s`, `10m`, `1h`,
24
+ * or a sum of them (`1m30s`). `what` names it in the error.
25
+ */
26
+ export function parseDuration(text, what) {
27
+ const t = text.trim();
28
+ if (/^\d+(\.\d+)?$/.test(t))
29
+ return Math.round(Number(t) * 1000);
30
+ const parts = [...t.matchAll(/(\d+(?:\.\d+)?)(ms|s|m|h)/g)];
31
+ if (t === "" || parts.map((m) => m[0]).join("") !== t) {
32
+ throw new YodelError(`${what} must be a duration such as 90 (seconds), 30s, 10m or 1h, got ${JSON.stringify(text)}`);
33
+ }
34
+ return Math.round(parts.reduce((sum, m) => sum + Number(m[1]) * (UNITS[m[2] ?? "s"] ?? 1000), 0));
35
+ }
36
+ function parse(value, where) {
37
+ try {
38
+ return toTopology(value);
39
+ }
40
+ catch (e) {
41
+ throw new YodelError(`${where}: ${e instanceof Error ? e.message : String(e)}`);
42
+ }
43
+ }
44
+ /** The topology the history's DDL is written for. */
45
+ export function historyTopologyOf(t) {
46
+ return t.kind === "cluster" ? { kind: "cluster", cluster: t.cluster } : t;
47
+ }
48
+ /** The settings of environment `name`; see the module comment for the order. */
49
+ export function environmentSettings(project, name, env = process.env) {
50
+ const own = project.yodel?.config.environments?.[name];
51
+ const profile = project.config.sql?.profiles?.[name];
52
+ let topology;
53
+ let topologySource;
54
+ if (own?.topology !== undefined) {
55
+ topology = parse(own.topology, `${CONFIG_FILE}: environments.${name}.topology`);
56
+ topologySource = CONFIG_FILE;
57
+ }
58
+ else if (profile?.topology !== undefined) {
59
+ topology = parse(profile.topology, `sql.profiles.${name}.topology`);
60
+ topologySource = `sql.profiles.${name}.topology`;
61
+ }
62
+ else if (env.YODEL_TOPOLOGY) {
63
+ topology = parse(env.YODEL_TOPOLOGY, "YODEL_TOPOLOGY");
64
+ topologySource = "YODEL_TOPOLOGY";
65
+ }
66
+ else {
67
+ topology = { kind: "single" };
68
+ topologySource = "default";
69
+ }
70
+ let lockTtlMs = DEFAULT_LOCK_TTL_MS;
71
+ if (own?.lockTtl !== undefined)
72
+ lockTtlMs = own.lockTtl * 1000;
73
+ else if (env.YODEL_LOCK_TTL) {
74
+ const ttl = Number(env.YODEL_LOCK_TTL);
75
+ if (!(Number.isFinite(ttl) && ttl > 0))
76
+ throw new YodelError(`YODEL_LOCK_TTL must be a number of seconds, got ${JSON.stringify(env.YODEL_LOCK_TTL)}`);
77
+ lockTtlMs = ttl * 1000;
78
+ }
79
+ let lockWaitMs = 0;
80
+ if (own?.lockWait !== undefined)
81
+ lockWaitMs = own.lockWait * 1000;
82
+ else if (env[LOCK_WAIT_ENV])
83
+ lockWaitMs = parseDuration(env[LOCK_WAIT_ENV], LOCK_WAIT_ENV);
84
+ return {
85
+ topology,
86
+ topologySource,
87
+ historyTopology: historyTopologyOf(topology),
88
+ historyDatabase: own?.history?.database ?? (env.YODEL_HISTORY_DATABASE || DEFAULT_HISTORY_DATABASE),
89
+ lockTtlMs,
90
+ lockWaitMs,
91
+ };
92
+ }
93
+ /** `cluster:main (yodel.config.ts)`, for a report's header. */
94
+ export const describeSettingsTopology = (s) => `${topologyLabel(s.topology)} (${s.topologySource})`;
95
+ /**
96
+ * The declarative path (`yodel plan`, `yodel apply` without migrations) runs
97
+ * chant's planner and applier, which render for `sql.profiles.<env>.topology`
98
+ * and do not read `yodel.config.ts`. A topology set only in yodel.config.ts
99
+ * would be ignored there, so it is refused unless chant's profile says the same
100
+ * (an unset profile topology is a single node, as chant renders it).
101
+ */
102
+ export function declarativeTopologyRefusal(project, name) {
103
+ const own = project.yodel?.config.environments?.[name]?.topology;
104
+ if (own === undefined)
105
+ return undefined;
106
+ const profile = project.config.sql?.profiles?.[name]?.topology;
107
+ const ours = parse(own, `${CONFIG_FILE}: environments.${name}.topology`);
108
+ // An unset profile topology is a single node to chant, so "single" in yodel.config.ts agrees with it (#25).
109
+ const chants = parse(profile ?? "single", `sql.profiles.${name}.topology`);
110
+ if (JSON.stringify(sorted(chants)) === JSON.stringify(sorted(ours)))
111
+ return undefined;
112
+ return new YodelError(`${CONFIG_FILE} sets environments.${name}.topology to ${topologyLabel(ours)}, but the declarative path plans and applies through chant, which reads sql.profiles.${name}.topology ` +
113
+ `(${profile === undefined ? "unset, so a single node" : topologyLabel(chants)}). Set sql.profiles.${name}.topology to the same in chant.config.ts, or leave the topology to chant.config.ts.`);
114
+ }
115
+ const sorted = (t) => Object.entries(t).sort(([a], [b]) => a.localeCompare(b));
116
+ //# sourceMappingURL=settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings.js","sourceRoot":"","sources":["../../src/config/settings.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ import type { Io } from "./command.js";
2
+ /** The arguments `yodel <verb> <env>` takes: the environment, `--json`, `--dir`, and any extra string options. */
3
+ export interface EnvArgs {
4
+ env: string;
5
+ json: boolean;
6
+ /** The project directory, or a directory inside it. Default: the working directory. */
7
+ dir: string;
8
+ options: Record<string, string | undefined>;
9
+ }
10
+ /** True when the arguments ask for the verb's help. */
11
+ export declare const wantsHelp: (args: readonly string[]) => boolean;
12
+ export declare function parseEnvArgs(verb: string, args: string[], extra?: readonly string[]): EnvArgs;
13
+ export declare function usage(verb: string, extra?: readonly string[]): string;
14
+ /**
15
+ * Runs a verb: prints `help` for `--help`, else runs `body`, turning a
16
+ * {@link YodelError} (or any error) into a message on stderr and its exit code.
17
+ */
18
+ export declare function guarded(verb: string, io: Io, args: readonly string[], help: string, body: () => Promise<number>): Promise<number>;
19
+ /**
20
+ * Wraps each line of a help text longer than `width` columns, continuing
21
+ * where its text starts: after `usage: yodel <verb> `, in an option's or an
22
+ * exit code's description column, else at the line's own indent.
23
+ */
24
+ export declare function formatHelp(text: string, width?: number): string;
@@ -0,0 +1,92 @@
1
+ import { parseArgs } from "node:util";
2
+ import { YodelError } from "./project.js";
3
+ /** True when the arguments ask for the verb's help. */
4
+ export const wantsHelp = (args) => args.includes("--help") || args.includes("-h");
5
+ export function parseEnvArgs(verb, args, extra = []) {
6
+ let parsed;
7
+ try {
8
+ parsed = parseArgs({
9
+ args,
10
+ allowPositionals: true,
11
+ strict: true,
12
+ options: {
13
+ json: { type: "boolean" },
14
+ dir: { type: "string", short: "C" },
15
+ ...Object.fromEntries(extra.map((name) => [name, { type: "string" }])),
16
+ },
17
+ });
18
+ }
19
+ catch (e) {
20
+ throw new YodelError(`${e instanceof Error ? e.message : String(e)}\n${usage(verb, extra)}`);
21
+ }
22
+ const { values, positionals } = parsed;
23
+ const [env, ...rest] = positionals;
24
+ if (env === undefined || rest.length > 0)
25
+ throw new YodelError(usage(verb, extra));
26
+ const options = {};
27
+ for (const name of extra) {
28
+ const v = values[name];
29
+ options[name] = typeof v === "string" ? v : undefined;
30
+ }
31
+ return {
32
+ env,
33
+ json: values.json === true,
34
+ dir: typeof values.dir === "string" ? values.dir : process.cwd(),
35
+ options,
36
+ };
37
+ }
38
+ export function usage(verb, extra = []) {
39
+ return `usage: yodel ${verb} <env> [--json] [--dir <project>]${extra.map((e) => ` [--${e} <${e}>]`).join("")}`;
40
+ }
41
+ /**
42
+ * Runs a verb: prints `help` for `--help`, else runs `body`, turning a
43
+ * {@link YodelError} (or any error) into a message on stderr and its exit code.
44
+ */
45
+ export async function guarded(verb, io, args, help, body) {
46
+ if (wantsHelp(args)) {
47
+ io.out(formatHelp(help));
48
+ return 0;
49
+ }
50
+ try {
51
+ return await body();
52
+ }
53
+ catch (e) {
54
+ if (e instanceof YodelError) {
55
+ io.err(`yodel ${verb}: ${e.message}\n`);
56
+ return e.exitCode;
57
+ }
58
+ io.err(`yodel ${verb}: ${e instanceof Error ? (e.stack ?? e.message) : String(e)}\n`);
59
+ return 1;
60
+ }
61
+ }
62
+ /**
63
+ * Wraps each line of a help text longer than `width` columns, continuing
64
+ * where its text starts: after `usage: yodel <verb> `, in an option's or an
65
+ * exit code's description column, else at the line's own indent.
66
+ */
67
+ export function formatHelp(text, width = 80) {
68
+ return text
69
+ .split("\n")
70
+ .map((line) => {
71
+ if (line.length <= width)
72
+ return line;
73
+ const usage = /^usage: yodel \S+ /.exec(line);
74
+ const column = /^(\s*(?:-\S.*?|\d)\s{2,})(?=\S)/.exec(line);
75
+ const indent = " ".repeat(usage ? usage[0].length : column ? (column[1] ?? "").length : (/^\s*/.exec(line)?.[0].length ?? 0));
76
+ const out = [];
77
+ let current = "";
78
+ for (const word of line.split(/(?<=\S) (?=\S)/)) {
79
+ if (current && current.length + 1 + word.length > width) {
80
+ out.push(current);
81
+ current = indent + word.trimStart();
82
+ }
83
+ else
84
+ current = current ? `${current} ${word}` : word;
85
+ }
86
+ if (current)
87
+ out.push(current);
88
+ return out.join("\n");
89
+ })
90
+ .join("\n");
91
+ }
92
+ //# sourceMappingURL=env-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env-args.js","sourceRoot":"","sources":["../src/env-args.ts"],"names":[],"mappings":"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"}
package/dist/exit.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ /**
2
+ * yodel's exit codes (#13). Every command uses them with these meanings;
3
+ * each command's `--help` lists the ones it can return. `yodel --help` and
4
+ * docs/README.md print {@link EXIT_CODES}, and test/exit-codes.test.ts
5
+ * keeps them in agreement.
6
+ */
7
+ export declare const EXIT_OK = 0;
8
+ export declare const EXIT_ERROR = 1;
9
+ /** Something yodel will not do itself; drift found, for `yodel drift`. */
10
+ export declare const EXIT_NEEDS_OP = 2;
11
+ /** Something outstanding: an approval, pending migrations, lint errors. */
12
+ export declare const EXIT_OUTSTANDING = 3;
13
+ /** Refused, nothing done. */
14
+ export declare const EXIT_REFUSED = 4;
15
+ /** Another apply holds the lock. */
16
+ export declare const EXIT_LOCKED = 5;
17
+ /** Each code and what it means, one line each. */
18
+ export declare const EXIT_CODES: ReadonlyArray<readonly [number, string]>;
19
+ /** Why `yodel plan` exits 0 with pending migrations, where `yodel status` exits 3. */
20
+ export declare const PLAN_PENDING_NOTE = "yodel plan exits 0 when migrations are pending: it reports, and a CI job that posts the plan on a pull request should not fail because the pull request adds a migration. To gate on pending migrations, use yodel status.";
package/dist/exit.js ADDED
@@ -0,0 +1,28 @@
1
+ /**
2
+ * yodel's exit codes (#13). Every command uses them with these meanings;
3
+ * each command's `--help` lists the ones it can return. `yodel --help` and
4
+ * docs/README.md print {@link EXIT_CODES}, and test/exit-codes.test.ts
5
+ * keeps them in agreement.
6
+ */
7
+ export const EXIT_OK = 0;
8
+ export const EXIT_ERROR = 1;
9
+ /** Something yodel will not do itself; drift found, for `yodel drift`. */
10
+ export const EXIT_NEEDS_OP = 2;
11
+ /** Something outstanding: an approval, pending migrations, lint errors. */
12
+ export const EXIT_OUTSTANDING = 3;
13
+ /** Refused, nothing done. */
14
+ export const EXIT_REFUSED = 4;
15
+ /** Another apply holds the lock. */
16
+ export const EXIT_LOCKED = 5;
17
+ /** Each code and what it means, one line each. */
18
+ export const EXIT_CODES = [
19
+ [EXIT_OK, "done, or nothing to do"],
20
+ [EXIT_ERROR, "an error"],
21
+ [EXIT_NEEDS_OP, "something yodel will not do itself (a change that needs an Op it does not run, a manual step); for yodel drift, drift found"],
22
+ [EXIT_OUTSTANDING, "something outstanding: apply stopped at its approval gate, status found pending migrations, lint found errors"],
23
+ [EXIT_REFUSED, "refused, nothing done: a checksum mismatch, an applied migration gone from the directory, an out-of-order migration, a fork or another problem in the migrations directory"],
24
+ [EXIT_LOCKED, "another apply holds the lock"],
25
+ ];
26
+ /** Why `yodel plan` exits 0 with pending migrations, where `yodel status` exits 3. */
27
+ export const PLAN_PENDING_NOTE = "yodel plan exits 0 when migrations are pending: it reports, and a CI job that posts the plan on a pull request should not fail because the pull request adds a migration. To gate on pending migrations, use yodel status.";
28
+ //# sourceMappingURL=exit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit.js","sourceRoot":"","sources":["../src/exit.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAC5B,0EAA0E;AAC1E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC;AAC/B,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAClC,6BAA6B;AAC7B,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAC;AAC9B,oCAAoC;AACpC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B,kDAAkD;AAClD,MAAM,CAAC,MAAM,UAAU,GAA6C;IAClE,CAAC,OAAO,EAAE,wBAAwB,CAAC;IACnC,CAAC,UAAU,EAAE,UAAU,CAAC;IACxB,CAAC,aAAa,EAAE,6HAA6H,CAAC;IAC9I,CAAC,gBAAgB,EAAE,+GAA+G,CAAC;IACnI,CAAC,YAAY,EAAE,4KAA4K,CAAC;IAC5L,CAAC,WAAW,EAAE,8BAA8B,CAAC;CAC9C,CAAC;AAEF,sFAAsF;AACtF,MAAM,CAAC,MAAM,iBAAiB,GAC5B,4NAA4N,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The one thing the history needs from a ClickHouse server: run a statement,
3
+ * get rows back. Over chant's own HTTP client in use; an in-memory fake in
4
+ * the unit tests.
5
+ */
6
+ import type { ClickHouseEndpoint } from "@intentius/chant-lexicon-sql/clickhouse/http";
7
+ import { YodelError } from "../project.js";
8
+ export interface QueryOptions {
9
+ /** Server settings for this query alone. `database` sets the default database. */
10
+ settings?: Record<string, string>;
11
+ }
12
+ export interface ClickHousePort {
13
+ query<Row = Record<string, unknown>>(sql: string, options?: QueryOptions): Promise<Row[]>;
14
+ }
15
+ /** A port over chant's ClickHouse HTTP client. */
16
+ export declare function httpPort(endpoint: ClickHouseEndpoint): Promise<ClickHousePort>;
17
+ /**
18
+ * A server that did not answer at all (refused, no route, a name that does
19
+ * not resolve): fetch throws `TypeError: fetch failed` with the reason in
20
+ * its cause, and neither names the server. One line that does, instead of
21
+ * a stack trace.
22
+ */
23
+ export declare function unreachable(endpoint: ClickHouseEndpoint, e: unknown): YodelError | undefined;
24
+ /** The server's message for an error from a port, first line. */
25
+ export declare function serverMessage(e: unknown): string;
@@ -0,0 +1,42 @@
1
+ /**
2
+ * The one thing the history needs from a ClickHouse server: run a statement,
3
+ * get rows back. Over chant's own HTTP client in use; an in-memory fake in
4
+ * the unit tests.
5
+ */
6
+ import { YodelError } from "../project.js";
7
+ /** A port over chant's ClickHouse HTTP client. */
8
+ export async function httpPort(endpoint) {
9
+ const { clickhouseQuery } = await import("@intentius/chant-lexicon-sql/clickhouse/http");
10
+ return {
11
+ query: async (sql, options = {}) => {
12
+ try {
13
+ return await clickhouseQuery(endpoint, sql, options.settings ? { settings: options.settings } : {});
14
+ }
15
+ catch (e) {
16
+ throw unreachable(endpoint, e) ?? e;
17
+ }
18
+ },
19
+ };
20
+ }
21
+ /**
22
+ * A server that did not answer at all (refused, no route, a name that does
23
+ * not resolve): fetch throws `TypeError: fetch failed` with the reason in
24
+ * its cause, and neither names the server. One line that does, instead of
25
+ * a stack trace.
26
+ */
27
+ export function unreachable(endpoint, e) {
28
+ if (!(e instanceof TypeError) || !/fetch failed/i.test(e.message))
29
+ return undefined;
30
+ const cause = e.cause;
31
+ const c = cause && typeof cause === "object" ? cause : undefined;
32
+ const why = typeof c?.code === "string" ? c.code : typeof c?.message === "string" ? c.message : e.message;
33
+ return new YodelError(`the ClickHouse server at ${redact(endpoint.url)} did not answer (${why}); is it running, and is that the right URL?`);
34
+ }
35
+ const redact = (url) => url.replace(/\/\/[^@/]*@/, "//");
36
+ /** The server's message for an error from a port, first line. */
37
+ export function serverMessage(e) {
38
+ if (e && typeof e === "object" && "serverMessage" in e && typeof e.serverMessage === "string")
39
+ return e.serverMessage.trim();
40
+ return e instanceof Error ? e.message : String(e);
41
+ }
42
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/history/client.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAW3C,kDAAkD;AAClD,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,QAA4B;IACzD,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,8CAA8C,CAAC,CAAC;IACzF,OAAO;QACL,KAAK,EAAE,KAAK,EAAO,GAAW,EAAE,UAAwB,EAAE,EAAE,EAAE;YAC5D,IAAI,CAAC;gBACH,OAAO,MAAM,eAAe,CAAM,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC3G,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,QAA4B,EAAE,CAAU;IAClE,IAAI,CAAC,CAAC,CAAC,YAAY,SAAS,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC;QAAE,OAAO,SAAS,CAAC;IACpF,MAAM,KAAK,GAAI,CAAyB,CAAC,KAAK,CAAC;IAC/C,MAAM,CAAC,GAAG,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAE,KAA+C,CAAC,CAAC,CAAC,SAAS,CAAC;IAC5G,MAAM,GAAG,GAAG,OAAO,CAAC,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;IAC1G,OAAO,IAAI,UAAU,CAAC,4BAA4B,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,oBAAoB,GAAG,8CAA8C,CAAC,CAAC;AAC/I,CAAC;AAED,MAAM,MAAM,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,aAAa,EAAE,IAAI,CAAC,CAAC;AAEzE,iEAAiE;AACjE,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,eAAe,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,aAAa,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC;IAC7H,OAAO,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AACpD,CAAC"}