@intentius/chant-lexicon-sql 0.124.31 → 0.124.32

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 (322) hide show
  1. package/dist/change-set.js +250 -0
  2. package/dist/clickhouse/access.js +722 -0
  3. package/dist/clickhouse/apply/apply.js +243 -0
  4. package/dist/clickhouse/apply/mutations.js +66 -0
  5. package/dist/clickhouse/apply/statements.js +545 -0
  6. package/dist/clickhouse/catalog-types.js +7 -0
  7. package/dist/clickhouse/container.js +152 -0
  8. package/dist/clickhouse/engine-syntax.js +159 -0
  9. package/dist/clickhouse/entities.js +593 -0
  10. package/dist/clickhouse/expressions.js +107 -0
  11. package/dist/clickhouse/http.js +55 -0
  12. package/dist/clickhouse/import/generator.js +192 -0
  13. package/dist/clickhouse/import/inlined.js +207 -0
  14. package/dist/clickhouse/import/ir.js +160 -0
  15. package/dist/clickhouse/import/live-export.js +131 -0
  16. package/dist/clickhouse/import/parser.js +17 -0
  17. package/dist/clickhouse/live/bind.js +116 -0
  18. package/dist/clickhouse/live/catalog.js +223 -0
  19. package/dist/clickhouse/live/describe-resources.js +91 -0
  20. package/dist/clickhouse/live/undeclarable.js +59 -0
  21. package/dist/clickhouse/overlays/codecs.js +57 -0
  22. package/dist/clickhouse/overlays/engines.js +101 -0
  23. package/dist/clickhouse/overlays/kinds.js +1 -0
  24. package/dist/clickhouse/overlays/projections.js +26 -0
  25. package/dist/clickhouse/overlays/skip-indexes.js +40 -0
  26. package/dist/clickhouse/overlays/ttl.js +34 -0
  27. package/dist/clickhouse/overlays/types.js +59 -0
  28. package/dist/clickhouse/ownership.js +83 -0
  29. package/dist/clickhouse/parser.js +674 -0
  30. package/dist/clickhouse/plan/commands.js +159 -0
  31. package/dist/clickhouse/plan/deep.js +345 -0
  32. package/dist/clickhouse/plan/diff.js +312 -0
  33. package/dist/clickhouse/plan/disruption.js +73 -0
  34. package/dist/clickhouse/plan/normalize.js +545 -0
  35. package/dist/clickhouse/plan/rebuild-handoff.js +57 -0
  36. package/dist/clickhouse/plan/report.js +26 -0
  37. package/dist/clickhouse/plan/rules.js +72 -0
  38. package/dist/clickhouse/plan/schema.js +67 -0
  39. package/dist/clickhouse/plan/server-format.js +35 -0
  40. package/dist/clickhouse/rebuild/backfill.js +265 -0
  41. package/dist/clickhouse/rebuild/engines.js +146 -0
  42. package/dist/clickhouse/rebuild/observe.js +260 -0
  43. package/dist/clickhouse/rebuild/op.js +152 -0
  44. package/dist/clickhouse/rebuild/partitions.js +65 -0
  45. package/dist/clickhouse/rebuild/receipts.js +120 -0
  46. package/dist/clickhouse/rebuild/replicas.js +121 -0
  47. package/dist/clickhouse/rebuild/shards.js +76 -0
  48. package/dist/clickhouse/rebuild/steps.js +383 -0
  49. package/dist/clickhouse/rebuild/verify.js +279 -0
  50. package/dist/clickhouse/row-types.js +151 -0
  51. package/dist/clickhouse/testing/fake-server.js +47 -0
  52. package/dist/clickhouse/testing/roundtrip-schema.js +25 -0
  53. package/dist/clickhouse/testing/writable-server.js +123 -0
  54. package/dist/clickhouse/tokens.js +23 -0
  55. package/dist/clickhouse/topology.js +463 -0
  56. package/dist/clickhouse/type-syntax.js +73 -0
  57. package/dist/clickhouse.js +25 -0
  58. package/dist/codegen/classifier-page.js +93 -0
  59. package/dist/codegen/clickhouse-module.js +249 -0
  60. package/dist/codegen/coverage-page.js +70 -0
  61. package/dist/codegen/docs-cli.js +3 -0
  62. package/dist/codegen/docs.js +222 -0
  63. package/dist/codegen/generate-cli.js +13 -0
  64. package/dist/codegen/generate.js +97 -0
  65. package/dist/codegen/package.js +28 -0
  66. package/dist/codegen/postgres-classifier-page.js +95 -0
  67. package/dist/codegen/postgres-module.js +418 -0
  68. package/dist/codegen/registry.js +52 -0
  69. package/dist/composites/audit-log-table.js +35 -0
  70. package/dist/composites/catalog.js +524 -0
  71. package/dist/composites/cdc-mirror.js +32 -0
  72. package/dist/composites/clickhouse.js +6 -0
  73. package/dist/composites/events-table.js +26 -0
  74. package/dist/composites/index.js +8 -0
  75. package/dist/composites/join-table.js +25 -0
  76. package/dist/composites/postgres.js +6 -0
  77. package/dist/composites/refreshed-view.js +24 -0
  78. package/dist/composites/replacing-table.js +28 -0
  79. package/dist/composites/rollup-view.js +29 -0
  80. package/dist/composites/sharded-table.js +27 -0
  81. package/dist/composites/soft-delete-table.js +34 -0
  82. package/dist/composites/tenant-table.js +26 -0
  83. package/dist/composites/typed.js +8 -0
  84. package/dist/config.js +206 -0
  85. package/dist/core/apply.js +93 -0
  86. package/dist/core/classifier.js +115 -0
  87. package/dist/core/container.js +69 -0
  88. package/dist/core/cursor.js +261 -0
  89. package/dist/core/diff.js +48 -0
  90. package/dist/core/entity.js +58 -0
  91. package/dist/core/find-templates.js +118 -0
  92. package/dist/core/foreign-tables.js +27 -0
  93. package/dist/core/handoff.js +32 -0
  94. package/dist/core/index.js +64 -0
  95. package/dist/core/interpolation.js +191 -0
  96. package/dist/core/normalize.js +43 -0
  97. package/dist/core/ownership.js +119 -0
  98. package/dist/core/receipts.js +22 -0
  99. package/dist/core/references.js +61 -0
  100. package/dist/core/statements.js +42 -0
  101. package/dist/core/template.js +79 -0
  102. package/dist/core/testing/http-stub.js +21 -0
  103. package/dist/core/tokens.js +202 -0
  104. package/dist/core/typed.js +40 -0
  105. package/dist/core/undeclarable.js +46 -0
  106. package/dist/coverage.js +161 -0
  107. package/dist/detect.js +32 -0
  108. package/dist/dialects.js +18 -0
  109. package/dist/files/build-root.js +72 -0
  110. package/dist/files/clickhouse.js +138 -0
  111. package/dist/files/common.js +58 -0
  112. package/dist/files/postgres.js +389 -0
  113. package/dist/generated/clickhouse-types.js +5 -0
  114. package/dist/generated/clickhouse.js +4361 -0
  115. package/dist/generated/postgres-types.js +227 -0
  116. package/dist/generated/postgres.js +3667 -0
  117. package/dist/import-generator.js +14 -0
  118. package/dist/import-parser.js +71 -0
  119. package/dist/index.js +24 -0
  120. package/dist/init-templates.js +290 -0
  121. package/dist/integrity.json +2 -2
  122. package/dist/lint/audit-catalog.js +31 -0
  123. package/dist/lint/audit-lineage.js +22 -0
  124. package/dist/lint/post-synth/audit-entries.js +34 -0
  125. package/dist/lint/post-synth/clickhouse-helpers.js +79 -0
  126. package/dist/lint/post-synth/clickhouse-type-check.js +162 -0
  127. package/dist/lint/post-synth/index.js +112 -0
  128. package/dist/lint/post-synth/postgres-audit-entries.js +35 -0
  129. package/dist/lint/post-synth/postgres-helpers.js +65 -0
  130. package/dist/lint/post-synth/postgres-names.js +507 -0
  131. package/dist/lint/post-synth/sql-helpers.js +23 -0
  132. package/dist/lint/post-synth/sql101.js +59 -0
  133. package/dist/lint/post-synth/sql102.js +34 -0
  134. package/dist/lint/post-synth/sqlch101.js +34 -0
  135. package/dist/lint/post-synth/sqlch102.js +23 -0
  136. package/dist/lint/post-synth/sqlch103.js +45 -0
  137. package/dist/lint/post-synth/sqlch104.js +41 -0
  138. package/dist/lint/post-synth/sqlch105.js +36 -0
  139. package/dist/lint/post-synth/sqlch106.js +27 -0
  140. package/dist/lint/post-synth/sqlch107.js +39 -0
  141. package/dist/lint/post-synth/sqlch108.js +28 -0
  142. package/dist/lint/post-synth/sqlch109.js +21 -0
  143. package/dist/lint/post-synth/sqlch110.js +31 -0
  144. package/dist/lint/post-synth/sqlch111.js +41 -0
  145. package/dist/lint/post-synth/sqlch112.js +28 -0
  146. package/dist/lint/post-synth/sqlch113.js +19 -0
  147. package/dist/lint/post-synth/sqlch114.js +26 -0
  148. package/dist/lint/post-synth/sqlch115.js +30 -0
  149. package/dist/lint/post-synth/sqlch116.js +22 -0
  150. package/dist/lint/post-synth/sqlch117.js +26 -0
  151. package/dist/lint/post-synth/sqlch118.js +27 -0
  152. package/dist/lint/post-synth/sqlch119.js +32 -0
  153. package/dist/lint/post-synth/sqlch120.js +20 -0
  154. package/dist/lint/post-synth/sqlch121.js +11 -0
  155. package/dist/lint/post-synth/sqlch122.js +11 -0
  156. package/dist/lint/post-synth/sqlch123.js +10 -0
  157. package/dist/lint/post-synth/sqlch124.js +21 -0
  158. package/dist/lint/post-synth/sqlch125.js +55 -0
  159. package/dist/lint/post-synth/sqlch126.js +62 -0
  160. package/dist/lint/post-synth/sqlch127.js +132 -0
  161. package/dist/lint/post-synth/sqlpg101.js +25 -0
  162. package/dist/lint/post-synth/sqlpg102.js +35 -0
  163. package/dist/lint/post-synth/sqlpg103.js +23 -0
  164. package/dist/lint/post-synth/sqlpg104.js +23 -0
  165. package/dist/lint/post-synth/sqlpg105.js +22 -0
  166. package/dist/lint/post-synth/sqlpg106.js +22 -0
  167. package/dist/lint/post-synth/sqlpg107.js +22 -0
  168. package/dist/lint/post-synth/sqlpg108.js +28 -0
  169. package/dist/lint/post-synth/sqlpg109.js +39 -0
  170. package/dist/lint/post-synth/sqlpg110.js +38 -0
  171. package/dist/lint/post-synth/sqlpg111.js +23 -0
  172. package/dist/lint/post-synth/sqlpg112.js +25 -0
  173. package/dist/lint/post-synth/sqlpg113.js +29 -0
  174. package/dist/lint/post-synth/sqlpg114.js +39 -0
  175. package/dist/lint/post-synth/sqlpg115.js +48 -0
  176. package/dist/lint/post-synth/sqlpg116.js +26 -0
  177. package/dist/lint/post-synth/sqlpg117.js +24 -0
  178. package/dist/lint/post-synth/sqlpg118.js +22 -0
  179. package/dist/lint/post-synth/sqlpg119.js +41 -0
  180. package/dist/lint/post-synth/sqlpg120.js +83 -0
  181. package/dist/lint/post-synth/sqlpg121.js +33 -0
  182. package/dist/lint/post-synth/sqlpg122.js +27 -0
  183. package/dist/lint/post-synth/sqlpg123.js +69 -0
  184. package/dist/lint/post-synth/sqlpg124.js +50 -0
  185. package/dist/lint/post-synth/sqlpg125.js +41 -0
  186. package/dist/lint/post-synth/sqlpg126.js +38 -0
  187. package/dist/lint/rules/index.js +12 -0
  188. package/dist/lint/rules/postgres-templates.js +27 -0
  189. package/dist/lint/rules/sqlch001.js +79 -0
  190. package/dist/lint/rules/sqlch002.js +124 -0
  191. package/dist/lint/rules/sqlch003.js +69 -0
  192. package/dist/lint/rules/sqlch004.js +83 -0
  193. package/dist/lint/rules/sqlpg001.js +68 -0
  194. package/dist/lint/rules/sqlpg002.js +69 -0
  195. package/dist/lint/rules/sqlpg003.js +58 -0
  196. package/dist/lint/rules/sqlpg004.js +77 -0
  197. package/dist/lint/rules/sqlpg005.js +86 -0
  198. package/dist/lint/rules/templates.js +25 -0
  199. package/dist/lint/rules/typed-names.js +132 -0
  200. package/dist/live-dialect.js +32 -0
  201. package/dist/lsp/catalog.js +44 -0
  202. package/dist/lsp/completions.js +136 -0
  203. package/dist/lsp/hover.js +115 -0
  204. package/dist/lsp/postgres-catalog.js +176 -0
  205. package/dist/lsp/postgres-template.js +171 -0
  206. package/dist/lsp/postgres.js +266 -0
  207. package/dist/lsp/refs.js +60 -0
  208. package/dist/lsp/registry.d.ts.map +1 -1
  209. package/dist/lsp/registry.js +19 -0
  210. package/dist/lsp/template.js +143 -0
  211. package/dist/manifest.json +1 -1
  212. package/dist/mcp/index.d.ts.map +1 -1
  213. package/dist/mcp/index.js +293 -0
  214. package/dist/mcp/postgres.js +117 -0
  215. package/dist/migration-statements.js +243 -0
  216. package/dist/op/activities/clickhouse-apply.js +83 -0
  217. package/dist/op/activities/clickhouse-emulator.js +53 -0
  218. package/dist/op/activities/clickhouse-rebuild.js +119 -0
  219. package/dist/op/activities/index.js +26 -0
  220. package/dist/op/activities/postgres-apply.js +126 -0
  221. package/dist/op/activities/postgres-emulator.js +70 -0
  222. package/dist/op/activities/postgres-migration.js +156 -0
  223. package/dist/op/activities/sql-exec.js +57 -0
  224. package/dist/op/activity-contracts.js +103 -0
  225. package/dist/package-cli.js +14 -0
  226. package/dist/plugin.js +259 -0
  227. package/dist/postgres/access/acl.js +344 -0
  228. package/dist/postgres/access/changes.js +30 -0
  229. package/dist/postgres/access/import.js +61 -0
  230. package/dist/postgres/access/live.js +96 -0
  231. package/dist/postgres/apply/apply.js +557 -0
  232. package/dist/postgres/apply/statements.js +882 -0
  233. package/dist/postgres/catalog-types.js +18 -0
  234. package/dist/postgres/container.js +58 -0
  235. package/dist/postgres/entities.js +1390 -0
  236. package/dist/postgres/entity-types.js +28 -0
  237. package/dist/postgres/import/generator.js +283 -0
  238. package/dist/postgres/import/ir.js +53 -0
  239. package/dist/postgres/import/live-export.js +83 -0
  240. package/dist/postgres/keywords.js +32 -0
  241. package/dist/postgres/live/bind.js +130 -0
  242. package/dist/postgres/live/catalog-kinds.js +301 -0
  243. package/dist/postgres/live/catalog.js +644 -0
  244. package/dist/postgres/live/client.js +151 -0
  245. package/dist/postgres/live/describe-resources.js +135 -0
  246. package/dist/postgres/live/undeclarable.js +111 -0
  247. package/dist/postgres/migrate/backfill.js +170 -0
  248. package/dist/postgres/migrate/batches.js +122 -0
  249. package/dist/postgres/migrate/carry.js +518 -0
  250. package/dist/postgres/migrate/handoff.js +59 -0
  251. package/dist/postgres/migrate/names.js +61 -0
  252. package/dist/postgres/migrate/observe.js +360 -0
  253. package/dist/postgres/migrate/op.js +178 -0
  254. package/dist/postgres/migrate/receipts.js +117 -0
  255. package/dist/postgres/migrate/replication.js +106 -0
  256. package/dist/postgres/migrate/steps.js +514 -0
  257. package/dist/postgres/overlays/columns.js +31 -0
  258. package/dist/postgres/overlays/constraints.js +52 -0
  259. package/dist/postgres/overlays/extension-objects.js +88 -0
  260. package/dist/postgres/overlays/indexes.js +25 -0
  261. package/dist/postgres/overlays/kinds.js +2 -0
  262. package/dist/postgres/overlays/partitioning.js +23 -0
  263. package/dist/postgres/overlays/relations.js +25 -0
  264. package/dist/postgres/overlays/storage.js +65 -0
  265. package/dist/postgres/overlays/type-ddl.js +36 -0
  266. package/dist/postgres/overlays/types.js +74 -0
  267. package/dist/postgres/parser.js +1824 -0
  268. package/dist/postgres/plan/commands.js +137 -0
  269. package/dist/postgres/plan/deep.js +324 -0
  270. package/dist/postgres/plan/diff.js +499 -0
  271. package/dist/postgres/plan/disruption.js +64 -0
  272. package/dist/postgres/plan/normalize.js +889 -0
  273. package/dist/postgres/plan/report.js +21 -0
  274. package/dist/postgres/plan/rules.js +115 -0
  275. package/dist/postgres/plan/schema.js +105 -0
  276. package/dist/postgres/plan/server-normalize.js +166 -0
  277. package/dist/postgres/providers/aurora.js +44 -0
  278. package/dist/postgres/providers/azure.js +53 -0
  279. package/dist/postgres/providers/cloud-sql.js +41 -0
  280. package/dist/postgres/providers/index.js +73 -0
  281. package/dist/postgres/providers/neon.js +44 -0
  282. package/dist/postgres/providers/rds.js +47 -0
  283. package/dist/postgres/providers/supabase.js +45 -0
  284. package/dist/postgres/providers/types.js +21 -0
  285. package/dist/postgres/row-types.js +107 -0
  286. package/dist/postgres/testing/fake-client.js +34 -0
  287. package/dist/postgres/testing/migration.js +48 -0
  288. package/dist/postgres/testing/roundtrip-schema.js +64 -0
  289. package/dist/postgres/testing/server.js +47 -0
  290. package/dist/postgres/testing/writable-server.js +160 -0
  291. package/dist/postgres/tokens.js +41 -0
  292. package/dist/postgres.js +15 -0
  293. package/dist/read/clickhouse.js +82 -0
  294. package/dist/read/objects.js +44 -0
  295. package/dist/read/postgres.js +104 -0
  296. package/dist/read.js +52 -0
  297. package/dist/receipts.js +207 -0
  298. package/dist/serializer.js +172 -0
  299. package/dist/skill-defs.js +93 -0
  300. package/dist/spec/catalog.js +191 -0
  301. package/dist/spec/fetch.d.ts.map +1 -1
  302. package/dist/spec/fetch.js +90 -0
  303. package/dist/spec/pin.js +42 -0
  304. package/dist/spec/postgres-catalog.js +171 -0
  305. package/dist/spec/postgres-fetch.js +91 -0
  306. package/dist/spec/postgres-pin.js +82 -0
  307. package/dist/sql-files.js +206 -0
  308. package/dist/sql-types-command.js +97 -0
  309. package/dist/sql-types.js +323 -0
  310. package/dist/token-source.js +156 -0
  311. package/dist/validate-cli.js +5 -0
  312. package/dist/validate.js +151 -0
  313. package/dist/workspace-outputs.js +191 -0
  314. package/package.json +7 -7
  315. package/src/codegen/package.ts +2 -2
  316. package/src/lint/rules/typescript-7.test.ts +2 -1
  317. package/src/lsp/catalog.ts +2 -2
  318. package/src/lsp/postgres-catalog.ts +2 -2
  319. package/src/lsp/registry.ts +2 -1
  320. package/src/mcp/index.ts +4 -2
  321. package/src/spec/fetch.ts +2 -2
  322. package/src/spec/postgres-fetch.ts +2 -2
@@ -0,0 +1,156 @@
1
+ /**
2
+ * Short-lived database credentials (#3685): a profile's `password` can name a
3
+ * token source instead of an environment variable, and the token is minted
4
+ * when a connection needs it.
5
+ *
6
+ * ```ts
7
+ * profiles: {
8
+ * prod: { url: "postgres://db.abc.us-east-1.rds.amazonaws.com:5432/shop", user: { env: "PG_USER" }, password: { token: "rds-iam" } },
9
+ * ci: { url: "postgres://db.internal:5432/shop", password: { token: "command", command: ["./mint-token.sh"], ttlSeconds: 600 } },
10
+ * }
11
+ * ```
12
+ *
13
+ * Each cloud source runs that cloud's own command line, which reads the job's
14
+ * ambient identity (an OIDC-federated role in CI, a workload identity, a
15
+ * logged-in developer), so chant holds no cloud SDK and no long-lived secret:
16
+ *
17
+ * - `rds-iam`: `aws rds generate-db-auth-token`, for RDS and Aurora. The host
18
+ * and port come from the profile's URL, the user from its `user`, the region
19
+ * from `region`, else `AWS_REGION`, else the RDS host name.
20
+ * - `cloud-sql-iam`: `gcloud sql generate-login-token`.
21
+ * - `entra`: `az account get-access-token` for Azure Database for PostgreSQL.
22
+ * - `command`: any command that prints a password on its standard output.
23
+ *
24
+ * A token is reused until most of its lifetime has passed and minted again
25
+ * after, so a long apply, whose ClickHouse requests each carry the password
26
+ * and whose Postgres connections each authenticate when opened, never sends
27
+ * an expired one. A token is never written to a message, an outcome or a log.
28
+ */
29
+ import { execFile } from "node:child_process";
30
+ import { z } from "zod";
31
+ const ttl = z.number().int().positive().optional();
32
+ /** The token sources a profile's `password` can name. */
33
+ export const tokenSourceSchema = z.discriminatedUnion("token", [
34
+ z.strictObject({
35
+ token: z.literal("rds-iam"),
36
+ /** The AWS region. `AWS_REGION`, `AWS_DEFAULT_REGION`, else the RDS host name's, when omitted. */
37
+ region: z.string().min(1).optional(),
38
+ /** How long a token is valid, in seconds. 900, the RDS lifetime, when omitted. */
39
+ ttlSeconds: ttl,
40
+ }),
41
+ z.strictObject({
42
+ token: z.literal("cloud-sql-iam"),
43
+ /** How long a token is valid, in seconds. 3600 when omitted. */
44
+ ttlSeconds: ttl,
45
+ }),
46
+ z.strictObject({
47
+ token: z.literal("entra"),
48
+ /** How long a token is valid, in seconds. 3600 when omitted. */
49
+ ttlSeconds: ttl,
50
+ }),
51
+ z.strictObject({
52
+ token: z.literal("command"),
53
+ /** The program and its arguments, run without a shell; its standard output, trimmed, is the password. */
54
+ command: z.array(z.string().min(1)).min(1),
55
+ /** How long a token is valid, in seconds. 300 when omitted. */
56
+ ttlSeconds: ttl,
57
+ }),
58
+ ]);
59
+ /** The cloud sources, which mint for a Postgres server only. */
60
+ export const POSTGRES_ONLY_TOKEN_SOURCES = new Set(["rds-iam", "cloud-sql-iam", "entra"]);
61
+ const DEFAULT_TTL_SECONDS = {
62
+ "rds-iam": 900,
63
+ "cloud-sql-iam": 3600,
64
+ entra: 3600,
65
+ command: 300,
66
+ };
67
+ /** A token reused past this share of its lifetime is minted again. */
68
+ const REUSE_FRACTION = 0.8;
69
+ /** A token source that could not mint. The message names the source and the command, never what it printed. */
70
+ export class TokenSourceError extends Error {
71
+ constructor(message) {
72
+ super(message);
73
+ this.name = "TokenSourceError";
74
+ }
75
+ }
76
+ const runCommand = (argv, env) => new Promise((resolve, reject) => {
77
+ execFile(argv[0], argv.slice(1), { env: env, timeout: 60000, maxBuffer: 1 << 20 }, (err, stdout) => {
78
+ if (err)
79
+ reject(err);
80
+ else
81
+ resolve(String(stdout));
82
+ });
83
+ });
84
+ /** The program a source runs. Pure, for tests. */
85
+ export function tokenCommand(config, input) {
86
+ switch (config.token) {
87
+ case "command":
88
+ return config.command;
89
+ case "cloud-sql-iam":
90
+ return ["gcloud", "sql", "generate-login-token"];
91
+ case "entra":
92
+ return ["az", "account", "get-access-token", "--resource-type", "oss-rdbms", "--query", "accessToken", "--output", "tsv"];
93
+ case "rds-iam": {
94
+ const url = new URL(input.url);
95
+ if (input.user === undefined)
96
+ throw new TokenSourceError("rds-iam mints a token for one database user; the profile names no user");
97
+ const region = config.region ?? input.env.AWS_REGION ?? input.env.AWS_DEFAULT_REGION ?? /\.([a-z]{2}(?:-[a-z]+)+-\d+)\.rds\.amazonaws\.com$/.exec(url.hostname)?.[1];
98
+ return [
99
+ "aws",
100
+ "rds",
101
+ "generate-db-auth-token",
102
+ "--hostname",
103
+ url.hostname,
104
+ "--port",
105
+ url.port || "5432",
106
+ "--username",
107
+ input.user,
108
+ ...(region !== undefined ? ["--region", region] : []),
109
+ ];
110
+ }
111
+ }
112
+ }
113
+ /**
114
+ * A source that mints with `config` when asked. Nothing runs until `get()`.
115
+ * `now` and `run` are for tests.
116
+ */
117
+ export function credentialSource(config, input) {
118
+ const run = input.run ?? runCommand;
119
+ const now = input.now ?? Date.now;
120
+ const lifetimeMs = (config.ttlSeconds ?? DEFAULT_TTL_SECONDS[config.token]) * 1000 * REUSE_FRACTION;
121
+ const source = `${input.source} (${config.token})`;
122
+ let cached;
123
+ let pending;
124
+ const mint = async () => {
125
+ const argv = tokenCommand(config, input);
126
+ let out;
127
+ try {
128
+ out = await run(argv, input.env);
129
+ }
130
+ catch (err) {
131
+ const e = err;
132
+ const why = e.code === "ENOENT" ? `${argv[0]} is not installed` : `it exited with ${String(e.code ?? "an error")}`;
133
+ throw new TokenSourceError(`${source} could not mint a token: \`${argv[0]}\` failed, ${why}`);
134
+ }
135
+ const token = out.trim();
136
+ if (token === "")
137
+ throw new TokenSourceError(`${source} could not mint a token: \`${argv[0]}\` printed nothing`);
138
+ cached = { token, until: now() + lifetimeMs };
139
+ return token;
140
+ };
141
+ return {
142
+ source,
143
+ async get() {
144
+ if (cached && now() < cached.until)
145
+ return cached.token;
146
+ // Requests that ask at once share one mint.
147
+ pending ?? (pending = mint().finally(() => {
148
+ pending = undefined;
149
+ }));
150
+ return pending;
151
+ },
152
+ invalidate() {
153
+ cached = undefined;
154
+ },
155
+ };
156
+ }
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env tsx
2
+ import { printValidationResult } from "@intentius/chant/codegen/validate";
3
+ import { validate } from "./validate.js";
4
+ // printValidationResult throws when a check failed, so `npm run validate` (and prepack) exits non-zero.
5
+ printValidationResult(await validate());
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Validate the sql lexicon's generated artifacts.
3
+ *
4
+ * The core checks (the registry parses, `index.d.ts` exists and compiles), plus
5
+ * the ClickHouse catalog's own: the generated tables exist, the committed
6
+ * snapshot is at the pin, and the names a schema leans on hardest are still
7
+ * in it. A pin move that drops one of those would otherwise surface as lint
8
+ * going quiet, not as a failure.
9
+ */
10
+ import { existsSync, readFileSync } from "fs";
11
+ import { dirname, join } from "path";
12
+ import { fileURLToPath } from "url";
13
+ import { validateLexiconArtifacts } from "@intentius/chant/codegen/validate";
14
+ import { CLICKHOUSE_VERSION } from "./spec/pin.js";
15
+ import { parseCatalog } from "./spec/catalog.js";
16
+ import { POSTGRES_PINS } from "./spec/postgres-pin.js";
17
+ import { parseCatalog as parsePostgresCatalog } from "./spec/postgres-catalog.js";
18
+ /** The entity kinds the registry must carry. */
19
+ const REQUIRED_ENTITIES = [
20
+ "Database",
21
+ "Table",
22
+ "View",
23
+ "MaterializedView",
24
+ "Dictionary",
25
+ "Function",
26
+ "User",
27
+ "Role",
28
+ "RowPolicy",
29
+ "Grant",
30
+ "Quota",
31
+ "SettingsProfile",
32
+ "PostgresSchema",
33
+ "PostgresTable",
34
+ "PostgresIndex",
35
+ "PostgresView",
36
+ "PostgresMaterializedView",
37
+ "PostgresSequence",
38
+ "PostgresEnum",
39
+ "PostgresCompositeType",
40
+ "PostgresRangeType",
41
+ "PostgresDomain",
42
+ "PostgresAggregate",
43
+ "PostgresCollation",
44
+ "PostgresCast",
45
+ "PostgresEventTrigger",
46
+ "PostgresExtension",
47
+ "PostgresFunction",
48
+ "PostgresProcedure",
49
+ "PostgresTrigger",
50
+ "PostgresPolicy",
51
+ "PostgresRole",
52
+ "PostgresGrant",
53
+ "PostgresDefaultPrivileges",
54
+ ];
55
+ /** Engines a ClickHouse schema declares most: the MergeTree family and the engines beside it. */
56
+ const REQUIRED_ENGINES = [
57
+ "MergeTree",
58
+ "ReplacingMergeTree",
59
+ "SummingMergeTree",
60
+ "AggregatingMergeTree",
61
+ "CollapsingMergeTree",
62
+ "VersionedCollapsingMergeTree",
63
+ "ReplicatedMergeTree",
64
+ "ReplicatedReplacingMergeTree",
65
+ "Distributed",
66
+ "Buffer",
67
+ "Memory",
68
+ "Null",
69
+ "MaterializedView",
70
+ "View",
71
+ ];
72
+ /** Column type families the parser and the sort-key rules reason about. */
73
+ const REQUIRED_TYPE_FAMILIES = [
74
+ "String",
75
+ "UInt64",
76
+ "Int64",
77
+ "Float64",
78
+ "DateTime",
79
+ "DateTime64",
80
+ "Date",
81
+ "UUID",
82
+ "Decimal",
83
+ "Nullable",
84
+ "LowCardinality",
85
+ "Array",
86
+ "Map",
87
+ "Tuple",
88
+ "Enum8",
89
+ "AggregateFunction",
90
+ "SimpleAggregateFunction",
91
+ ];
92
+ /** Codecs the codec overlay types parameters for. */
93
+ const REQUIRED_CODECS = ["ZSTD", "LZ4", "LZ4HC", "Delta", "DoubleDelta", "Gorilla", "T64"];
94
+ export async function validate(opts) {
95
+ const basePath = opts?.basePath ?? dirname(dirname(fileURLToPath(import.meta.url)));
96
+ const core = await validateLexiconArtifacts({
97
+ lexiconJsonFilename: "lexicon-sql.json",
98
+ requiredNames: REQUIRED_ENTITIES,
99
+ basePath,
100
+ // Generation reads the committed catalog snapshot, so the surface is deterministic: a pin move that
101
+ // changes it fails here until `chant dev surface-diff lexicons/sql --update-snapshot --bump` accepts it.
102
+ checkSurfaceSnapshot: "always",
103
+ });
104
+ const checks = [...core.checks];
105
+ const tables = join(basePath, "src", "generated", "clickhouse.ts");
106
+ checks.push(existsSync(tables)
107
+ ? { name: "clickhouse-tables-exist", ok: true }
108
+ : { name: "clickhouse-tables-exist", ok: false, error: "src/generated/clickhouse.ts not found; run npm run generate" });
109
+ try {
110
+ const catalog = parseCatalog(readFileSync(join(basePath, "src", "spec", "clickhouse-catalog.snapshot.json"), "utf-8"));
111
+ checks.push(catalog.version === CLICKHOUSE_VERSION
112
+ ? { name: "clickhouse-snapshot-at-pin", ok: true }
113
+ : {
114
+ name: "clickhouse-snapshot-at-pin",
115
+ ok: false,
116
+ error: `the snapshot is ${catalog.version}, the pin is ${CLICKHOUSE_VERSION}; run npm run generate to refresh it`,
117
+ });
118
+ const missing = (names, have) => {
119
+ const set = new Set(have);
120
+ return names.filter((n) => !set.has(n));
121
+ };
122
+ const gaps = [
123
+ ...missing(REQUIRED_ENGINES, catalog.tableEngines.map((e) => e.name)).map((n) => `engine ${n}`),
124
+ ...missing(REQUIRED_TYPE_FAMILIES, catalog.typeFamilies.map((t) => t.name)).map((n) => `type ${n}`),
125
+ ...missing(REQUIRED_CODECS, catalog.codecs.map((c) => c.name)).map((n) => `codec ${n}`),
126
+ ];
127
+ checks.push(gaps.length === 0
128
+ ? { name: "clickhouse-required-names", ok: true }
129
+ : { name: "clickhouse-required-names", ok: false, error: `missing at the pin: ${gaps.join(", ")}` });
130
+ }
131
+ catch (err) {
132
+ checks.push({
133
+ name: "clickhouse-snapshot-readable",
134
+ ok: false,
135
+ error: err instanceof Error ? err.message : String(err),
136
+ });
137
+ }
138
+ try {
139
+ const behind = POSTGRES_PINS.flatMap((pin) => {
140
+ const snapshot = parsePostgresCatalog(readFileSync(join(basePath, "src", "spec", `postgres-catalog-${pin.major}.snapshot.json`), "utf-8"));
141
+ return snapshot.version === pin.version ? [] : [`${pin.major}: snapshot ${snapshot.version}, pin ${pin.version}`];
142
+ });
143
+ checks.push(behind.length === 0
144
+ ? { name: "postgres-snapshots-at-pins", ok: true }
145
+ : { name: "postgres-snapshots-at-pins", ok: false, error: `${behind.join("; ")}; run npm run generate to refresh` });
146
+ }
147
+ catch (err) {
148
+ checks.push({ name: "postgres-snapshots-readable", ok: false, error: err instanceof Error ? err.message : String(err) });
149
+ }
150
+ return { success: checks.every((c) => c.ok), checks };
151
+ }
@@ -0,0 +1,191 @@
1
+ /**
2
+ * The workspace outputs a sql member exposes (#3931): each table and view,
3
+ * and each of their columns, as names another member's link may target.
4
+ *
5
+ * | Dialect | Relation | Column |
6
+ * |---|---|---|
7
+ * | Postgres | `<schema>.<table>` | `<schema>.<table>.<column>` |
8
+ * | ClickHouse | `<database>.<table>` | `<database>.<table>.<column>` |
9
+ *
10
+ * The schema is `public` when the DDL does not qualify the name, and the
11
+ * database `default`. Views and materialized views are relations too.
12
+ *
13
+ * Names are the declared ones, read from the entities the member's source
14
+ * folds to, never an environment's or a profile's rendering: a member that
15
+ * renames its database per environment or tenant at deploy time exposes the
16
+ * same outputs everywhere.
17
+ *
18
+ * Identifiers are written unquoted, in the case the dialect keeps:
19
+ *
20
+ * - Postgres folds an unquoted identifier to lower case and keeps a quoted
21
+ * one exactly, so `CREATE TABLE Orders` is `public.orders` and `CREATE
22
+ * TABLE "Orders"` is `public.Orders`, a different output;
23
+ * - ClickHouse is case-sensitive, so a name is kept as written, quoted or not.
24
+ *
25
+ * A link's near-name hint compares names case-insensitively, so a link to
26
+ * `public.orders` when only `public.Orders` exists is pointed at it.
27
+ *
28
+ * A view's columns are its declared column list, or else the names of its
29
+ * select list (an alias, or the column a bare reference reads). A select
30
+ * list item with no name chant can derive, or a `*`, leaves the view's
31
+ * columns incomplete: that is a gap, so a link to one of them is unresolved
32
+ * rather than missing.
33
+ *
34
+ * A `-- previously: <old>` rename hint, on a column's line or before the
35
+ * CREATE, is reported as the output's previous name, so a link to the old
36
+ * name says where it went.
37
+ */
38
+ import { CLICKHOUSE_ENTITY_TYPES, isClickHouseObject } from "./clickhouse/entities.js";
39
+ import { canonicalObject } from "./clickhouse/plan/normalize.js";
40
+ import { isPostgresObject, POSTGRES_ENTITY_TYPES } from "./postgres/entities.js";
41
+ import { renameHints } from "./postgres/plan/schema.js";
42
+ /** The schema an unqualified Postgres name is created in. */
43
+ export const POSTGRES_DEFAULT_SCHEMA = "public";
44
+ /** The database an unqualified ClickHouse name is created in. */
45
+ export const CLICKHOUSE_DEFAULT_DATABASE = "default";
46
+ /** A module the sql lexicon's declarations import from. */
47
+ const SQL_MODULE = /from\s+["']@intentius\/chant-lexicon-sql(\/(postgres|clickhouse|sql-files))?["']/;
48
+ function add(c, name, entity, previously = []) {
49
+ const prev = c.outputs.get(name);
50
+ const before = [...new Set([...(prev?.previously ?? []), ...previously.filter((p) => p !== name)])].sort();
51
+ c.outputs.set(name, { name, entity: prev?.entity ?? entity, ...(before.length ? { previously: before } : {}) });
52
+ }
53
+ /** A relation and its columns, with the rename hints that apply. */
54
+ function addRelation(c, key, qualifier, name, columns, hints) {
55
+ const relation = `${qualifier}.${name}`;
56
+ // A relation's hint names its old name, bare or qualified.
57
+ const oldRelation = hints.previously ? (hints.previously.includes(".") ? hints.previously : `${qualifier}.${hints.previously}`) : undefined;
58
+ add(c, relation, key, oldRelation ? [oldRelation] : []);
59
+ for (const col of columns) {
60
+ const prevCol = hints.columns[col];
61
+ const previously = [
62
+ ...(prevCol ? [`${relation}.${prevCol}`] : []),
63
+ ...(oldRelation ? [`${oldRelation}.${col}`, ...(prevCol ? [`${oldRelation}.${prevCol}`] : [])] : []),
64
+ ];
65
+ add(c, `${relation}.${col}`, key, previously);
66
+ }
67
+ }
68
+ /** A view's output columns from its select list, and whether they are all known. */
69
+ function lineageColumns(lineage, unnamed) {
70
+ const columns = [];
71
+ let complete = true;
72
+ lineage.forEach((e, i) => {
73
+ if (/(^|\.)\s*\*$/.test(e.expr.trim()) || unnamed(e.output, i + 1))
74
+ complete = false;
75
+ else
76
+ columns.push(e.output);
77
+ });
78
+ return { columns, complete };
79
+ }
80
+ function postgres(c, key, e) {
81
+ const type = e.entityType;
82
+ if (type === POSTGRES_ENTITY_TYPES.table) {
83
+ const props = e.props;
84
+ const schema = props.schema ?? POSTGRES_DEFAULT_SCHEMA;
85
+ const columns = props.columns.map((col) => col.name);
86
+ const inherited = (parent) => isPostgresObject(parent) && parent.entityType === POSTGRES_ENTITY_TYPES.table ? parent.props.columns.map((col) => col.name) : undefined;
87
+ // A partition takes its parent's columns; INHERITS adds the parents'.
88
+ if (props.partitionOf !== undefined) {
89
+ const fromParent = inherited(props.partitionOf);
90
+ if (fromParent)
91
+ columns.push(...fromParent.filter((n) => !columns.includes(n)));
92
+ else
93
+ c.gaps.push(`table ${schema}.${props.name} (${key}) is a partition of ${String(props.partitionOf)}, which this member does not declare, so its columns are not known`);
94
+ }
95
+ for (const parent of props.inherits) {
96
+ const fromParent = inherited(parent);
97
+ if (fromParent)
98
+ columns.push(...fromParent.filter((n) => !columns.includes(n)));
99
+ else
100
+ c.gaps.push(`table ${schema}.${props.name} (${key}) inherits ${String(parent)}, which this member does not declare, so its columns are not all known`);
101
+ }
102
+ if (props.ofType !== undefined) {
103
+ const attrs = isPostgresObject(props.ofType) ? props.ofType.props.attributes : undefined;
104
+ if (attrs)
105
+ columns.push(...attrs.map((a) => a.name).filter((n) => !columns.includes(n)));
106
+ else
107
+ c.gaps.push(`table ${schema}.${props.name} (${key}) is OF ${String(props.ofType)}, which this member does not declare, so its columns are not known`);
108
+ }
109
+ if (props.like.length > 0)
110
+ c.gaps.push(`table ${schema}.${props.name} (${key}) copies columns with LIKE, which are not read`);
111
+ addRelation(c, key, schema, props.name, columns, renameHints(props.ddl));
112
+ return;
113
+ }
114
+ if (type === POSTGRES_ENTITY_TYPES.view || type === POSTGRES_ENTITY_TYPES.materializedView) {
115
+ const props = e.props;
116
+ const schema = props.schema ?? POSTGRES_DEFAULT_SCHEMA;
117
+ let columns = [...props.columns];
118
+ if (columns.length === 0) {
119
+ const derived = lineageColumns(props.lineage, (output) => output === "?column?");
120
+ columns = derived.columns;
121
+ if (!derived.complete)
122
+ c.gaps.push(`view ${schema}.${props.name} (${key}) has a select list item whose name can't be read without a server (a * or an unnamed expression), so its columns are not all known`);
123
+ }
124
+ addRelation(c, key, schema, props.name, columns, renameHints(props.ddl));
125
+ }
126
+ }
127
+ function clickhouseHints(ddl) {
128
+ try {
129
+ const o = canonicalObject(ddl, CLICKHOUSE_DEFAULT_DATABASE);
130
+ const columns = {};
131
+ for (const col of o.columns)
132
+ if (col.previously)
133
+ columns[col.name] = col.previously;
134
+ return { ...(o.previously ? { previously: o.previously } : {}), columns };
135
+ }
136
+ catch {
137
+ return { columns: {} };
138
+ }
139
+ }
140
+ function clickhouse(c, key, e) {
141
+ const type = e.entityType;
142
+ if (type === CLICKHOUSE_ENTITY_TYPES.table) {
143
+ const props = e.props;
144
+ const database = props.database ?? CLICKHOUSE_DEFAULT_DATABASE;
145
+ if (props.columns.length === 0)
146
+ c.gaps.push(`table ${database}.${props.name} (${key}) declares no columns, so the server's are not known`);
147
+ addRelation(c, key, database, props.name, props.columns.map((col) => col.name), clickhouseHints(props.ddl));
148
+ return;
149
+ }
150
+ if (type === CLICKHOUSE_ENTITY_TYPES.view || type === CLICKHOUSE_ENTITY_TYPES.materializedView) {
151
+ const props = e.props;
152
+ const database = props.database ?? CLICKHOUSE_DEFAULT_DATABASE;
153
+ let columns = props.columns.map((col) => col.name);
154
+ if (columns.length === 0) {
155
+ const derived = lineageColumns(props.lineage, (output, n) => output === `_${n}`);
156
+ columns = derived.columns;
157
+ if (!derived.complete)
158
+ c.gaps.push(`view ${database}.${props.name} (${key}) has a select list item whose name can't be read without a server (a * or an unaliased expression), so its columns are not all known`);
159
+ }
160
+ addRelation(c, key, database, props.name, columns, clickhouseHints(props.ddl));
161
+ }
162
+ }
163
+ /**
164
+ * The `workspaceOutputs` hook: every table and view the entities declare,
165
+ * and their columns. `unread` names the member's files that did not fold;
166
+ * one that imports the sql lexicon may declare tables, so it is a gap.
167
+ */
168
+ export function sqlWorkspaceOutputs(entities, unread = []) {
169
+ const c = { outputs: new Map(), gaps: [] };
170
+ let any = false;
171
+ for (const [key, e] of entities) {
172
+ if (isPostgresObject(e)) {
173
+ any = true;
174
+ postgres(c, key, e);
175
+ }
176
+ else if (isClickHouseObject(e)) {
177
+ any = true;
178
+ clickhouse(c, key, e);
179
+ }
180
+ }
181
+ for (const u of unread) {
182
+ if (!SQL_MODULE.test(u.text))
183
+ continue;
184
+ any = true;
185
+ c.gaps.push(`${u.file} imports the sql lexicon and does not fold, so the tables it declares were not read: ${u.reason}`);
186
+ }
187
+ if (!any)
188
+ return undefined;
189
+ const outputs = [...c.outputs.values()].sort((a, b) => (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
190
+ return { outputs, ...(c.gaps.length ? { gaps: c.gaps } : {}) };
191
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@intentius/chant-lexicon-sql",
3
- "version": "0.124.31",
3
+ "version": "0.124.32",
4
4
  "description": "SQL lexicon for chant — database schema as typed declarations, one dialect at a time; ClickHouse first, with types read from a pinned server's catalog",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://intentius.io/chant",
@@ -31,23 +31,23 @@
31
31
  ".": {
32
32
  "development": "./src/index.ts",
33
33
  "types": "./dist/index.d.ts",
34
- "default": "./src/index.ts"
34
+ "default": "./dist/index.js"
35
35
  },
36
36
  "./workspace-kinds": "./workspace-kinds.json",
37
37
  "./*": {
38
38
  "development": "./src/*.ts",
39
39
  "types": "./dist/*.d.ts",
40
- "default": "./src/*.ts"
40
+ "default": "./dist/*.js"
41
41
  },
42
42
  "./op/activities": {
43
43
  "development": "./src/op/activities/index.ts",
44
44
  "types": "./dist/op/activities/index.d.ts",
45
- "default": "./src/op/activities/index.ts"
45
+ "default": "./dist/op/activities/index.js"
46
46
  },
47
47
  "./lint/post-synth": {
48
48
  "development": "./src/lint/post-synth/index.ts",
49
49
  "types": "./dist/lint/post-synth/index.d.ts",
50
- "default": "./src/lint/post-synth/index.ts"
50
+ "default": "./dist/lint/post-synth/index.js"
51
51
  },
52
52
  "./manifest": "./dist/manifest.json",
53
53
  "./meta": "./dist/meta.json",
@@ -59,7 +59,7 @@
59
59
  "validate": "tsx src/validate-cli.ts",
60
60
  "docs": "tsx src/codegen/docs-cli.ts",
61
61
  "prepack": "npm run generate && npm run bundle && npm run validate && npm run build",
62
- "build": "tsc -p tsconfig.build.json && tsc-alias -p tsconfig.build.json && find dist -type f \\( -name \"*.js\" -o -name \"*.js.map\" \\) -delete"
62
+ "build": "tsc -p tsconfig.build.json --sourceMap false && tsc-alias -p tsconfig.build.json"
63
63
  },
64
64
  "dependencies": {
65
65
  "pg": "^8.23.1",
@@ -72,6 +72,6 @@
72
72
  "typescript": "^5.9.3"
73
73
  },
74
74
  "peerDependencies": {
75
- "@intentius/chant": "^0.124.31"
75
+ "@intentius/chant": "^0.124.32"
76
76
  }
77
77
  }
@@ -4,14 +4,14 @@
4
4
 
5
5
  import { readFileSync } from "fs";
6
6
  import { join, dirname } from "path";
7
- import { fileURLToPath } from "url";
7
+ import { moduleSourceDir } from "@intentius/chant/module-source";
8
8
  import { packagePipeline, type PackageOptions, type PackageResult } from "@intentius/chant/codegen/package";
9
9
  import { generate } from "./generate";
10
10
 
11
11
  export type { PackageOptions, PackageResult };
12
12
 
13
13
  // src/codegen/package.ts -> src/
14
- const srcDir = dirname(dirname(fileURLToPath(import.meta.url)));
14
+ const srcDir = dirname(moduleSourceDir(import.meta.url));
15
15
 
16
16
  export async function packageLexicon(opts: PackageOptions = {}): Promise<PackageResult> {
17
17
  const pkgJson = JSON.parse(readFileSync(join(srcDir, "..", "package.json"), "utf-8"));
@@ -88,7 +88,8 @@ describe.skipIf(!ready)("sql lint rules in a TypeScript 7 project (#3864)", () =
88
88
 
89
89
  test("no rule throws, and the lexicon really sees TypeScript 7", () => {
90
90
  for (const dir of examples) expect(readdirSync(dir).length).toBeGreaterThan(0);
91
- const out = execFileSync(process.execPath, ["--import", `file://${tsxLoader}`, join(project, "run.mts"), JSON.stringify(examples), lexiconPackageJson], {
91
+ // The copy carries src/ only, so the lexicon resolves through its `development` export (#3981).
92
+ const out = execFileSync(process.execPath, ["--conditions=development", "--import", `file://${tsxLoader}`, join(project, "run.mts"), JSON.stringify(examples), lexiconPackageJson], {
92
93
  cwd: project,
93
94
  encoding: "utf-8",
94
95
  env: { ...process.env, TSX_DISABLE_CACHE: "1" },
@@ -6,10 +6,10 @@
6
6
 
7
7
  import { readFileSync } from "fs";
8
8
  import { dirname, join } from "path";
9
- import { fileURLToPath } from "url";
9
+ import { moduleSourceDir } from "@intentius/chant/module-source";
10
10
  import { parseCatalog, type ClickHouseCatalog, type SettingRow } from "../spec/catalog";
11
11
 
12
- const SNAPSHOT = join(dirname(fileURLToPath(import.meta.url)), "..", "spec", "clickhouse-catalog.snapshot.json");
12
+ const SNAPSHOT = join(moduleSourceDir(import.meta.url), "..", "spec", "clickhouse-catalog.snapshot.json");
13
13
 
14
14
  export interface CatalogIndex {
15
15
  catalog: ClickHouseCatalog;
@@ -10,12 +10,12 @@
10
10
 
11
11
  import { existsSync, readFileSync } from "fs";
12
12
  import { dirname, join, resolve } from "path";
13
- import { fileURLToPath } from "url";
13
+ import { moduleSourceDir } from "@intentius/chant/module-source";
14
14
  import { parseCatalog, type PostgresCatalog } from "../spec/postgres-catalog";
15
15
  import { POSTGRES_LATEST_MAJOR, POSTGRES_MAJORS } from "../spec/postgres-pin";
16
16
  import { STORAGE_PARAMETER_TYPES } from "../postgres/overlays/storage";
17
17
 
18
- const SPEC = join(dirname(fileURLToPath(import.meta.url)), "..", "spec");
18
+ const SPEC = join(moduleSourceDir(import.meta.url), "..", "spec");
19
19
 
20
20
  let cached: Map<number, PostgresCatalog> | null = null;
21
21
 
@@ -1,7 +1,8 @@
1
1
  import { createRequire } from "module";
2
+ import { moduleSourceUrl } from "@intentius/chant/module-source";
2
3
  import { LexiconIndex, type LexiconEntry } from "@intentius/chant/lsp/lexicon-providers";
3
4
 
4
- const require = createRequire(import.meta.url);
5
+ const require = createRequire(moduleSourceUrl(import.meta.url));
5
6
 
6
7
  let cached: LexiconIndex | null = null;
7
8
 
package/src/mcp/index.ts CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  import type { McpResourceContribution, McpToolContribution } from "@intentius/chant/mcp/types";
10
10
  import { createCatalogResource, createDiffTool } from "@intentius/chant/lexicon-plugin-helpers";
11
+ import { moduleSourceUrl } from "@intentius/chant/module-source";
11
12
  import { sqlSerializer } from "../serializer";
12
13
  import { catalogIndex } from "../lsp/catalog";
13
14
  import { database, dictionary, func, grant, policy, quota, role, settingsProfile, table, user, view } from "../clickhouse/entities";
@@ -272,9 +273,10 @@ const need = () => {
272
273
  /** The resources the sql lexicon contributes. */
273
274
  export function sqlMcpResources(): McpResourceContribution[] {
274
275
  return [
275
- // `generated/` sits beside plugin.ts, which is where the helper looks.
276
+ // `generated/` sits beside plugin.ts, which is where the helper looks. The
277
+ // source URL, so a compiled module names src/plugin.ts too (#3981).
276
278
  createCatalogResource(
277
- new URL("../plugin.ts", import.meta.url).href,
279
+ new URL("../plugin.ts", moduleSourceUrl(import.meta.url)).href,
278
280
  "SQL Entity Catalog",
279
281
  "The entity kinds the sql lexicon declares (database, table, view, materialized view, dictionary, function, user, role, row policy, grant)",
280
282
  "lexicon-sql.json",
package/src/spec/fetch.ts CHANGED
@@ -19,13 +19,13 @@
19
19
 
20
20
  import { readFileSync, writeFileSync } from "node:fs";
21
21
  import { dirname, join } from "node:path";
22
- import { fileURLToPath } from "node:url";
22
+ import { moduleSourceDir } from "@intentius/chant/module-source";
23
23
  import { CLICKHOUSE_VERSION, clickhouseImage } from "./pin";
24
24
  import { parseCatalog, readCatalog, stringifyCatalog, type ClickHouseCatalog } from "./catalog";
25
25
  import { startScratchServer } from "../clickhouse/container";
26
26
  import type { ClickHouseEndpoint } from "../clickhouse/http";
27
27
 
28
- export const SNAPSHOT_FILE = join(dirname(fileURLToPath(import.meta.url)), "clickhouse-catalog.snapshot.json");
28
+ export const SNAPSHOT_FILE = join(moduleSourceDir(import.meta.url), "clickhouse-catalog.snapshot.json");
29
29
 
30
30
  /** The key the single catalog document is filed under in the pipeline's schema map. */
31
31
  export const CATALOG_KEY = "ClickHouse::Catalog";