@caracal-lynx/sluice 0.1.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 (281) hide show
  1. package/CLAUDE.md +1822 -0
  2. package/LICENCE-FAQ.md +74 -0
  3. package/LICENSE +92 -0
  4. package/README.md +582 -0
  5. package/dist/adapters/source/csv.d.ts +10 -0
  6. package/dist/adapters/source/csv.d.ts.map +1 -0
  7. package/dist/adapters/source/csv.js +110 -0
  8. package/dist/adapters/source/csv.js.map +1 -0
  9. package/dist/adapters/source/index.d.ts +9 -0
  10. package/dist/adapters/source/index.d.ts.map +1 -0
  11. package/dist/adapters/source/index.js +26 -0
  12. package/dist/adapters/source/index.js.map +1 -0
  13. package/dist/adapters/source/mssql.d.ts +11 -0
  14. package/dist/adapters/source/mssql.d.ts.map +1 -0
  15. package/dist/adapters/source/mssql.js +230 -0
  16. package/dist/adapters/source/mssql.js.map +1 -0
  17. package/dist/adapters/source/pg.d.ts +11 -0
  18. package/dist/adapters/source/pg.d.ts.map +1 -0
  19. package/dist/adapters/source/pg.js +88 -0
  20. package/dist/adapters/source/pg.js.map +1 -0
  21. package/dist/adapters/source/registry.d.ts +10 -0
  22. package/dist/adapters/source/registry.d.ts.map +1 -0
  23. package/dist/adapters/source/registry.js +36 -0
  24. package/dist/adapters/source/registry.js.map +1 -0
  25. package/dist/adapters/source/rest.d.ts +16 -0
  26. package/dist/adapters/source/rest.d.ts.map +1 -0
  27. package/dist/adapters/source/rest.js +182 -0
  28. package/dist/adapters/source/rest.js.map +1 -0
  29. package/dist/adapters/source/rest.types.d.ts +15 -0
  30. package/dist/adapters/source/rest.types.d.ts.map +1 -0
  31. package/dist/adapters/source/rest.types.js +6 -0
  32. package/dist/adapters/source/rest.types.js.map +1 -0
  33. package/dist/adapters/source/types.d.ts +23 -0
  34. package/dist/adapters/source/types.d.ts.map +1 -0
  35. package/dist/adapters/source/types.js +4 -0
  36. package/dist/adapters/source/types.js.map +1 -0
  37. package/dist/adapters/source/xlsx.d.ts +10 -0
  38. package/dist/adapters/source/xlsx.d.ts.map +1 -0
  39. package/dist/adapters/source/xlsx.js +71 -0
  40. package/dist/adapters/source/xlsx.js.map +1 -0
  41. package/dist/adapters/target/bc.d.ts +21 -0
  42. package/dist/adapters/target/bc.d.ts.map +1 -0
  43. package/dist/adapters/target/bc.js +188 -0
  44. package/dist/adapters/target/bc.js.map +1 -0
  45. package/dist/adapters/target/bluecherry.d.ts +10 -0
  46. package/dist/adapters/target/bluecherry.d.ts.map +1 -0
  47. package/dist/adapters/target/bluecherry.js +127 -0
  48. package/dist/adapters/target/bluecherry.js.map +1 -0
  49. package/dist/adapters/target/csv.d.ts +10 -0
  50. package/dist/adapters/target/csv.d.ts.map +1 -0
  51. package/dist/adapters/target/csv.js +40 -0
  52. package/dist/adapters/target/csv.js.map +1 -0
  53. package/dist/adapters/target/ifs.d.ts +10 -0
  54. package/dist/adapters/target/ifs.d.ts.map +1 -0
  55. package/dist/adapters/target/ifs.js +55 -0
  56. package/dist/adapters/target/ifs.js.map +1 -0
  57. package/dist/adapters/target/index.d.ts +8 -0
  58. package/dist/adapters/target/index.d.ts.map +1 -0
  59. package/dist/adapters/target/index.js +22 -0
  60. package/dist/adapters/target/index.js.map +1 -0
  61. package/dist/adapters/target/pg.d.ts +11 -0
  62. package/dist/adapters/target/pg.d.ts.map +1 -0
  63. package/dist/adapters/target/pg.js +103 -0
  64. package/dist/adapters/target/pg.js.map +1 -0
  65. package/dist/adapters/target/registry.d.ts +9 -0
  66. package/dist/adapters/target/registry.d.ts.map +1 -0
  67. package/dist/adapters/target/registry.js +29 -0
  68. package/dist/adapters/target/registry.js.map +1 -0
  69. package/dist/adapters/target/types.d.ts +15 -0
  70. package/dist/adapters/target/types.d.ts.map +1 -0
  71. package/dist/adapters/target/types.js +4 -0
  72. package/dist/adapters/target/types.js.map +1 -0
  73. package/dist/cli.d.ts +25 -0
  74. package/dist/cli.d.ts.map +1 -0
  75. package/dist/cli.js +354 -0
  76. package/dist/cli.js.map +1 -0
  77. package/dist/config/index.d.ts +4 -0
  78. package/dist/config/index.d.ts.map +1 -0
  79. package/dist/config/index.js +6 -0
  80. package/dist/config/index.js.map +1 -0
  81. package/dist/config/loader.d.ts +5 -0
  82. package/dist/config/loader.d.ts.map +1 -0
  83. package/dist/config/loader.js +135 -0
  84. package/dist/config/loader.js.map +1 -0
  85. package/dist/config/schema.d.ts +4162 -0
  86. package/dist/config/schema.d.ts.map +1 -0
  87. package/dist/config/schema.js +263 -0
  88. package/dist/config/schema.js.map +1 -0
  89. package/dist/config/types.d.ts +3 -0
  90. package/dist/config/types.d.ts.map +1 -0
  91. package/dist/config/types.js +4 -0
  92. package/dist/config/types.js.map +1 -0
  93. package/dist/dq/engine.d.ts +10 -0
  94. package/dist/dq/engine.d.ts.map +1 -0
  95. package/dist/dq/engine.js +114 -0
  96. package/dist/dq/engine.js.map +1 -0
  97. package/dist/dq/index.d.ts +6 -0
  98. package/dist/dq/index.d.ts.map +1 -0
  99. package/dist/dq/index.js +6 -0
  100. package/dist/dq/index.js.map +1 -0
  101. package/dist/dq/reporter.d.ts +5 -0
  102. package/dist/dq/reporter.d.ts.map +1 -0
  103. package/dist/dq/reporter.js +41 -0
  104. package/dist/dq/reporter.js.map +1 -0
  105. package/dist/dq/rules/allowedValues.d.ts +7 -0
  106. package/dist/dq/rules/allowedValues.d.ts.map +1 -0
  107. package/dist/dq/rules/allowedValues.js +26 -0
  108. package/dist/dq/rules/allowedValues.js.map +1 -0
  109. package/dist/dq/rules/email.d.ts +7 -0
  110. package/dist/dq/rules/email.d.ts.map +1 -0
  111. package/dist/dq/rules/email.js +24 -0
  112. package/dist/dq/rules/email.js.map +1 -0
  113. package/dist/dq/rules/index.d.ts +15 -0
  114. package/dist/dq/rules/index.d.ts.map +1 -0
  115. package/dist/dq/rules/index.js +30 -0
  116. package/dist/dq/rules/index.js.map +1 -0
  117. package/dist/dq/rules/maxLength.d.ts +7 -0
  118. package/dist/dq/rules/maxLength.d.ts.map +1 -0
  119. package/dist/dq/rules/maxLength.js +25 -0
  120. package/dist/dq/rules/maxLength.js.map +1 -0
  121. package/dist/dq/rules/minMax.d.ts +11 -0
  122. package/dist/dq/rules/minMax.d.ts.map +1 -0
  123. package/dist/dq/rules/minMax.js +52 -0
  124. package/dist/dq/rules/minMax.js.map +1 -0
  125. package/dist/dq/rules/notNull.d.ts +7 -0
  126. package/dist/dq/rules/notNull.d.ts.map +1 -0
  127. package/dist/dq/rules/notNull.js +21 -0
  128. package/dist/dq/rules/notNull.js.map +1 -0
  129. package/dist/dq/rules/pattern.d.ts +7 -0
  130. package/dist/dq/rules/pattern.d.ts.map +1 -0
  131. package/dist/dq/rules/pattern.js +31 -0
  132. package/dist/dq/rules/pattern.js.map +1 -0
  133. package/dist/dq/rules/types.d.ts +6 -0
  134. package/dist/dq/rules/types.d.ts.map +1 -0
  135. package/dist/dq/rules/types.js +4 -0
  136. package/dist/dq/rules/types.js.map +1 -0
  137. package/dist/dq/rules/ukPostcode.d.ts +7 -0
  138. package/dist/dq/rules/ukPostcode.d.ts.map +1 -0
  139. package/dist/dq/rules/ukPostcode.js +24 -0
  140. package/dist/dq/rules/ukPostcode.js.map +1 -0
  141. package/dist/dq/rules/unique.d.ts +14 -0
  142. package/dist/dq/rules/unique.d.ts.map +1 -0
  143. package/dist/dq/rules/unique.js +9 -0
  144. package/dist/dq/rules/unique.js.map +1 -0
  145. package/dist/dq/types.d.ts +29 -0
  146. package/dist/dq/types.d.ts.map +1 -0
  147. package/dist/dq/types.js +4 -0
  148. package/dist/dq/types.js.map +1 -0
  149. package/dist/enrich/types.d.ts +87 -0
  150. package/dist/enrich/types.d.ts.map +1 -0
  151. package/dist/enrich/types.js +4 -0
  152. package/dist/enrich/types.js.map +1 -0
  153. package/dist/index.d.ts +17 -0
  154. package/dist/index.d.ts.map +1 -0
  155. package/dist/index.js +17 -0
  156. package/dist/index.js.map +1 -0
  157. package/dist/merge/conflict-log.d.ts +9 -0
  158. package/dist/merge/conflict-log.d.ts.map +1 -0
  159. package/dist/merge/conflict-log.js +28 -0
  160. package/dist/merge/conflict-log.js.map +1 -0
  161. package/dist/merge/engine.d.ts +7 -0
  162. package/dist/merge/engine.d.ts.map +1 -0
  163. package/dist/merge/engine.js +19 -0
  164. package/dist/merge/engine.js.map +1 -0
  165. package/dist/merge/index.d.ts +11 -0
  166. package/dist/merge/index.d.ts.map +1 -0
  167. package/dist/merge/index.js +34 -0
  168. package/dist/merge/index.js.map +1 -0
  169. package/dist/merge/sql-builder.d.ts +19 -0
  170. package/dist/merge/sql-builder.d.ts.map +1 -0
  171. package/dist/merge/sql-builder.js +148 -0
  172. package/dist/merge/sql-builder.js.map +1 -0
  173. package/dist/merge/strategies/coalesce.d.ts +17 -0
  174. package/dist/merge/strategies/coalesce.d.ts.map +1 -0
  175. package/dist/merge/strategies/coalesce.js +77 -0
  176. package/dist/merge/strategies/coalesce.js.map +1 -0
  177. package/dist/merge/strategies/index.d.ts +5 -0
  178. package/dist/merge/strategies/index.d.ts.map +1 -0
  179. package/dist/merge/strategies/index.js +7 -0
  180. package/dist/merge/strategies/index.js.map +1 -0
  181. package/dist/merge/strategies/intersect.d.ts +17 -0
  182. package/dist/merge/strategies/intersect.d.ts.map +1 -0
  183. package/dist/merge/strategies/intersect.js +75 -0
  184. package/dist/merge/strategies/intersect.js.map +1 -0
  185. package/dist/merge/strategies/priority-override.d.ts +16 -0
  186. package/dist/merge/strategies/priority-override.d.ts.map +1 -0
  187. package/dist/merge/strategies/priority-override.js +78 -0
  188. package/dist/merge/strategies/priority-override.js.map +1 -0
  189. package/dist/merge/strategies/registry.d.ts +8 -0
  190. package/dist/merge/strategies/registry.d.ts.map +1 -0
  191. package/dist/merge/strategies/registry.js +19 -0
  192. package/dist/merge/strategies/registry.js.map +1 -0
  193. package/dist/merge/strategies/union.d.ts +15 -0
  194. package/dist/merge/strategies/union.d.ts.map +1 -0
  195. package/dist/merge/strategies/union.js +75 -0
  196. package/dist/merge/strategies/union.js.map +1 -0
  197. package/dist/merge/types.d.ts +24 -0
  198. package/dist/merge/types.d.ts.map +1 -0
  199. package/dist/merge/types.js +4 -0
  200. package/dist/merge/types.js.map +1 -0
  201. package/dist/multi-source-runner.d.ts +22 -0
  202. package/dist/multi-source-runner.d.ts.map +1 -0
  203. package/dist/multi-source-runner.js +398 -0
  204. package/dist/multi-source-runner.js.map +1 -0
  205. package/dist/plugins/index.d.ts +4 -0
  206. package/dist/plugins/index.d.ts.map +1 -0
  207. package/dist/plugins/index.js +5 -0
  208. package/dist/plugins/index.js.map +1 -0
  209. package/dist/plugins/loader.d.ts +22 -0
  210. package/dist/plugins/loader.d.ts.map +1 -0
  211. package/dist/plugins/loader.js +151 -0
  212. package/dist/plugins/loader.js.map +1 -0
  213. package/dist/plugins/registry.d.ts +25 -0
  214. package/dist/plugins/registry.d.ts.map +1 -0
  215. package/dist/plugins/registry.js +42 -0
  216. package/dist/plugins/registry.js.map +1 -0
  217. package/dist/plugins/types.d.ts +61 -0
  218. package/dist/plugins/types.d.ts.map +1 -0
  219. package/dist/plugins/types.js +4 -0
  220. package/dist/plugins/types.js.map +1 -0
  221. package/dist/runner.d.ts +97 -0
  222. package/dist/runner.d.ts.map +1 -0
  223. package/dist/runner.js +520 -0
  224. package/dist/runner.js.map +1 -0
  225. package/dist/staging/index.d.ts +3 -0
  226. package/dist/staging/index.d.ts.map +1 -0
  227. package/dist/staging/index.js +5 -0
  228. package/dist/staging/index.js.map +1 -0
  229. package/dist/staging/schema.d.ts +19 -0
  230. package/dist/staging/schema.d.ts.map +1 -0
  231. package/dist/staging/schema.js +15 -0
  232. package/dist/staging/schema.js.map +1 -0
  233. package/dist/staging/store.d.ts +71 -0
  234. package/dist/staging/store.d.ts.map +1 -0
  235. package/dist/staging/store.js +270 -0
  236. package/dist/staging/store.js.map +1 -0
  237. package/dist/transform/cleanse.d.ts +2 -0
  238. package/dist/transform/cleanse.d.ts.map +1 -0
  239. package/dist/transform/cleanse.js +59 -0
  240. package/dist/transform/cleanse.js.map +1 -0
  241. package/dist/transform/engine.d.ts +10 -0
  242. package/dist/transform/engine.d.ts.map +1 -0
  243. package/dist/transform/engine.js +225 -0
  244. package/dist/transform/engine.js.map +1 -0
  245. package/dist/transform/expression.d.ts +5 -0
  246. package/dist/transform/expression.d.ts.map +1 -0
  247. package/dist/transform/expression.js +52 -0
  248. package/dist/transform/expression.js.map +1 -0
  249. package/dist/transform/index.d.ts +6 -0
  250. package/dist/transform/index.d.ts.map +1 -0
  251. package/dist/transform/index.js +7 -0
  252. package/dist/transform/index.js.map +1 -0
  253. package/dist/transform/lookup.d.ts +10 -0
  254. package/dist/transform/lookup.d.ts.map +1 -0
  255. package/dist/transform/lookup.js +66 -0
  256. package/dist/transform/lookup.js.map +1 -0
  257. package/dist/transform/types.d.ts +10 -0
  258. package/dist/transform/types.d.ts.map +1 -0
  259. package/dist/transform/types.js +4 -0
  260. package/dist/transform/types.js.map +1 -0
  261. package/dist/utils/env.d.ts +3 -0
  262. package/dist/utils/env.d.ts.map +1 -0
  263. package/dist/utils/env.js +26 -0
  264. package/dist/utils/env.js.map +1 -0
  265. package/dist/utils/errors.d.ts +26 -0
  266. package/dist/utils/errors.d.ts.map +1 -0
  267. package/dist/utils/errors.js +39 -0
  268. package/dist/utils/errors.js.map +1 -0
  269. package/dist/utils/index.d.ts +5 -0
  270. package/dist/utils/index.d.ts.map +1 -0
  271. package/dist/utils/index.js +7 -0
  272. package/dist/utils/index.js.map +1 -0
  273. package/dist/utils/logger.d.ts +14 -0
  274. package/dist/utils/logger.d.ts.map +1 -0
  275. package/dist/utils/logger.js +16 -0
  276. package/dist/utils/logger.js.map +1 -0
  277. package/dist/utils/progress.d.ts +66 -0
  278. package/dist/utils/progress.d.ts.map +1 -0
  279. package/dist/utils/progress.js +283 -0
  280. package/dist/utils/progress.js.map +1 -0
  281. package/package.json +92 -0
package/dist/cli.js ADDED
@@ -0,0 +1,354 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: Elastic-2.0
3
+ // Copyright (c) 2026 Caracal Lynx Ltd.
4
+ /**
5
+ * Sluice CLI.
6
+ *
7
+ * Commands (per CLAUDE.md):
8
+ * sluice run <pipeline.yaml> Full pipeline run
9
+ * sluice validate <pipeline.yaml> DQ + transform only; no load
10
+ * sluice profile <pipeline.yaml> Extract + column profiling; no DQ
11
+ * sluice check <pipeline.yaml> Config validation only; no execution
12
+ *
13
+ * Exit codes:
14
+ * 0 success
15
+ * 1 pipeline error
16
+ * 2 DQ critical violations
17
+ * 3 config error
18
+ * 4 enrich error (Phase 4)
19
+ */
20
+ import { Command } from 'commander';
21
+ import * as path from 'node:path';
22
+ import { ConfigLoader } from './config/loader.js';
23
+ import { isMultiSource } from './config/types.js';
24
+ import { MultiSourcePipelineRunner } from './multi-source-runner.js';
25
+ import { PipelineRunner, _isEnrichPhaseRegistered, } from './runner.js';
26
+ import { RuleRegistry, TransformRegistry, loadPlugins, loadNpmPlugins } from './plugins/index.js';
27
+ import { MergeStrategyRegistry } from './merge/index.js';
28
+ import { loadEnv } from './utils/env.js';
29
+ import { ConfigError, EnrichError, PipelineDQError, PipelineError } from './utils/errors.js';
30
+ import { logger } from './utils/logger.js';
31
+ import { ProgressReporter } from './utils/progress.js';
32
+ export function resolvePluginDirs(cwd, pluginDirs = []) {
33
+ return Array.from(new Set([
34
+ path.resolve(cwd, 'plugins'),
35
+ ...pluginDirs.map((dir) => path.resolve(cwd, dir)),
36
+ ]));
37
+ }
38
+ export function exitCodeFor(err) {
39
+ if (err instanceof PipelineDQError)
40
+ return 2;
41
+ if (err instanceof ConfigError)
42
+ return 3;
43
+ if (err instanceof EnrichError)
44
+ return 4;
45
+ if (err instanceof PipelineError)
46
+ return 1;
47
+ return 1;
48
+ }
49
+ function applyGlobals(opts) {
50
+ loadEnv(opts.env);
51
+ if (opts.logLevel)
52
+ logger.level = opts.logLevel;
53
+ if (opts.silent) {
54
+ // Errors still reach stderr via the logger's multistream; info/warn are dropped.
55
+ logger.level = 'error';
56
+ }
57
+ const overrides = {};
58
+ if (opts.output !== undefined)
59
+ overrides.outputDir = opts.output;
60
+ if (opts.dryRun)
61
+ overrides.dryRun = true;
62
+ if (opts.plugins?.length)
63
+ overrides.pluginDirs = opts.plugins;
64
+ return overrides;
65
+ }
66
+ function phaseCountForRun(config, skipEnrich) {
67
+ const willLoad = !(config.run.dryRun || config.run.mode === 'validate-only');
68
+ // Enrich runs only when: enrich block configured, run isn't validate/dry-run,
69
+ // --no-enrich wasn't passed, and the private package has registered a factory.
70
+ const willEnrich = Boolean(config.enrich) &&
71
+ willLoad &&
72
+ !skipEnrich &&
73
+ _isEnrichPhaseRegistered();
74
+ const enrichPhases = willEnrich ? 1 : 0;
75
+ if (isMultiSource(config)) {
76
+ const sourcesWithPreMergeRules = new Set(config.dq.rules.filter((r) => r.sourceId).map((r) => r.sourceId));
77
+ // Extract per source + DQ per source with rules + Merge [+ Enrich] + post-merge DQ + Transform [+ Load]
78
+ return (config.sources.length +
79
+ sourcesWithPreMergeRules.size +
80
+ 1 + // merge
81
+ enrichPhases +
82
+ 1 + // post-merge DQ
83
+ 1 + // transform
84
+ (willLoad ? 1 : 0));
85
+ }
86
+ // Single source: Extract [+ Enrich] + DQ + Transform [+ Load]
87
+ return 3 + enrichPhases + (willLoad ? 1 : 0);
88
+ }
89
+ function buildProgressReporter(opts, config, skipEnrich = false) {
90
+ return new ProgressReporter({
91
+ silent: opts.silent ?? false,
92
+ totalPhases: phaseCountForRun(config, skipEnrich),
93
+ logLevel: (opts.logLevel ?? 'info'),
94
+ });
95
+ }
96
+ export async function createRunnerForPipeline(yaml) {
97
+ const config = await ConfigLoader.load(yaml);
98
+ return isMultiSource(config)
99
+ ? new MultiSourcePipelineRunner()
100
+ : new PipelineRunner();
101
+ }
102
+ async function cmdRun(yaml, program, cmdOpts = {}) {
103
+ const opts = program.opts();
104
+ const overrides = applyGlobals(opts);
105
+ if (cmdOpts.enrich === false)
106
+ overrides.skipEnrich = true;
107
+ let progress;
108
+ try {
109
+ const runner = await createRunnerForPipeline(yaml);
110
+ const config = await ConfigLoader.load(yaml);
111
+ progress = buildProgressReporter(opts, config, overrides.skipEnrich ?? false);
112
+ overrides.progress = progress;
113
+ const result = await runner.run(yaml, overrides);
114
+ logger.info({
115
+ pipeline: result.pipeline,
116
+ mode: result.mode,
117
+ rowsExtracted: result.extract.rowsExtracted,
118
+ rowsMerged: result.merge?.rowsMerged,
119
+ mergeConflicts: result.merge?.conflicts,
120
+ unmatchedRows: result.merge?.unmatched,
121
+ rowsLoaded: result.load?.rowsLoaded ?? 0,
122
+ stateFile: result.stateFilePath,
123
+ }, 'sluice run: complete');
124
+ process.exit(0);
125
+ }
126
+ catch (err) {
127
+ progress?.stop();
128
+ logger.error({ err }, 'sluice run: failed');
129
+ process.exit(exitCodeFor(err));
130
+ }
131
+ }
132
+ async function cmdValidate(yaml, program) {
133
+ const opts = program.opts();
134
+ const overrides = applyGlobals(opts);
135
+ overrides.mode = 'validate-only';
136
+ let progress;
137
+ try {
138
+ const runner = await createRunnerForPipeline(yaml);
139
+ const config = await ConfigLoader.load(yaml);
140
+ progress = buildProgressReporter(opts, { ...config, run: { ...config.run, mode: 'validate-only' } });
141
+ overrides.progress = progress;
142
+ const result = await runner.run(yaml, overrides);
143
+ logger.info({
144
+ pipeline: result.pipeline,
145
+ rowsMerged: result.merge?.rowsMerged,
146
+ rowsChecked: result.dq.rowsChecked,
147
+ critical: result.dq.violations.critical,
148
+ warnings: result.dq.violations.warning,
149
+ }, 'sluice validate: complete');
150
+ process.exit(0);
151
+ }
152
+ catch (err) {
153
+ progress?.stop();
154
+ logger.error({ err }, 'sluice validate: failed');
155
+ process.exit(exitCodeFor(err));
156
+ }
157
+ }
158
+ async function cmdProfile(yaml, program) {
159
+ const opts = program.opts();
160
+ const overrides = applyGlobals(opts);
161
+ let progress;
162
+ try {
163
+ const runner = await createRunnerForPipeline(yaml);
164
+ const config = await ConfigLoader.load(yaml);
165
+ // profile = extract-only for single-source; extract+merge for multi-source.
166
+ progress = new ProgressReporter({
167
+ silent: opts.silent ?? false,
168
+ totalPhases: isMultiSource(config) ? config.sources.length + 1 : 1,
169
+ logLevel: (opts.logLevel ?? 'info'),
170
+ });
171
+ overrides.progress = progress;
172
+ const result = await runner.profile(yaml, overrides);
173
+ logger.info({ pipeline: result.pipeline, rowsExtracted: result.extract.rowsExtracted, profilePath: result.profilePath }, 'sluice profile: complete');
174
+ process.exit(0);
175
+ }
176
+ catch (err) {
177
+ progress?.stop();
178
+ logger.error({ err }, 'sluice profile: failed');
179
+ process.exit(exitCodeFor(err));
180
+ }
181
+ }
182
+ async function cmdCheck(yaml, program) {
183
+ applyGlobals(program.opts());
184
+ try {
185
+ const config = await ConfigLoader.load(yaml);
186
+ const isMulti = isMultiSource(config);
187
+ logger.info({
188
+ pipeline: config.pipeline.name,
189
+ source: config.source?.adapter ?? 'multi',
190
+ sourceCount: isMulti ? config.sources.length : 1,
191
+ mergeStrategy: isMulti ? config.merge.strategy : undefined,
192
+ target: config.target.adapter,
193
+ rules: config.dq.rules.length,
194
+ fields: config.transform.fields.length,
195
+ }, 'sluice check: config is valid');
196
+ process.exit(0);
197
+ }
198
+ catch (err) {
199
+ logger.error({ err }, 'sluice check: failed');
200
+ process.exit(exitCodeFor(err));
201
+ }
202
+ }
203
+ async function cmdPlugins(program) {
204
+ const opts = program.opts();
205
+ const overrides = applyGlobals(opts);
206
+ try {
207
+ const cwd = process.cwd();
208
+ const ruleRegistry = new RuleRegistry();
209
+ const transformRegistry = new TransformRegistry();
210
+ const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
211
+ // Load both tier 2 (file-based) and tier 3 (npm) plugins
212
+ for (const dir of pluginDirs) {
213
+ await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
214
+ }
215
+ const configPath = path.join(cwd, 'sluice.config.yaml');
216
+ await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
217
+ const ruleIds = ruleRegistry.list();
218
+ const transformIds = transformRegistry.list();
219
+ const mergeStrategyIds = MergeStrategyRegistry.list();
220
+ logger.info({
221
+ rules: ruleIds,
222
+ transforms: transformIds,
223
+ mergeStrategies: mergeStrategyIds,
224
+ }, 'sluice plugins: loaded');
225
+ process.exit(0);
226
+ }
227
+ catch (err) {
228
+ logger.error({ err }, 'sluice plugins: failed');
229
+ process.exit(exitCodeFor(err));
230
+ }
231
+ }
232
+ async function cmdMergeListStrategies(program) {
233
+ const overrides = applyGlobals(program.opts());
234
+ try {
235
+ const cwd = process.cwd();
236
+ const ruleRegistry = new RuleRegistry();
237
+ const transformRegistry = new TransformRegistry();
238
+ const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
239
+ for (const dir of pluginDirs) {
240
+ await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
241
+ }
242
+ const configPath = path.join(cwd, 'sluice.config.yaml');
243
+ await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
244
+ const strategyIds = MergeStrategyRegistry.list();
245
+ const strategies = strategyIds.map((id) => {
246
+ const strategy = MergeStrategyRegistry.get(id);
247
+ return { id: strategy.id, description: strategy.description ?? strategy.id };
248
+ });
249
+ logger.info({ count: strategies.length, strategies }, 'sluice merge list-strategies: loaded');
250
+ process.exit(0);
251
+ }
252
+ catch (err) {
253
+ logger.error({ err }, 'sluice merge list-strategies: failed');
254
+ process.exit(exitCodeFor(err));
255
+ }
256
+ }
257
+ async function cmdMergeInfo(strategyId, program) {
258
+ const overrides = applyGlobals(program.opts());
259
+ try {
260
+ const cwd = process.cwd();
261
+ const ruleRegistry = new RuleRegistry();
262
+ const transformRegistry = new TransformRegistry();
263
+ const pluginDirs = resolvePluginDirs(cwd, overrides.pluginDirs ?? []);
264
+ for (const dir of pluginDirs) {
265
+ await loadPlugins(dir, ruleRegistry, transformRegistry, MergeStrategyRegistry);
266
+ }
267
+ const configPath = path.join(cwd, 'sluice.config.yaml');
268
+ await loadNpmPlugins(configPath, ruleRegistry, transformRegistry, MergeStrategyRegistry);
269
+ const strategy = MergeStrategyRegistry.get(strategyId);
270
+ logger.info({
271
+ strategy: strategy.id,
272
+ description: strategy.description ?? strategy.id,
273
+ }, 'sluice merge info: complete');
274
+ process.exit(0);
275
+ }
276
+ catch (err) {
277
+ logger.error({ err, strategyId }, 'sluice merge info: failed');
278
+ process.exit(exitCodeFor(err));
279
+ }
280
+ }
281
+ export function buildProgram() {
282
+ const program = new Command();
283
+ program
284
+ .name('sluice')
285
+ .description('Config-driven ETL toolkit for ERP data migrations')
286
+ .version('0.1.0')
287
+ .option('--log-level <level>', 'debug | info | warn | error')
288
+ .option('--env <file>', 'Path to .env file', './.env')
289
+ .option('--output <dir>', 'Override run.outputDir')
290
+ .option('--plugins <dir...>', 'Additional plugin directory/directories to load')
291
+ .option('--dry-run', 'Force run.dryRun = true')
292
+ .option('--silent', 'Suppress the progress bar on stdout (logs still go to stderr)');
293
+ program
294
+ .command('run <pipeline>')
295
+ .description('Execute a full pipeline run')
296
+ .option('--no-enrich', 'Skip the Phase 4a enrich phase even if enrich: is configured')
297
+ .action((yaml, cmdOpts) => {
298
+ void cmdRun(yaml, program, cmdOpts);
299
+ });
300
+ program
301
+ .command('validate <pipeline>')
302
+ .description('DQ + transform only; no load')
303
+ .action((yaml) => {
304
+ void cmdValidate(yaml, program);
305
+ });
306
+ program
307
+ .command('profile <pipeline>')
308
+ .description('Extract + column profiling; no DQ')
309
+ .action((yaml) => {
310
+ void cmdProfile(yaml, program);
311
+ });
312
+ program
313
+ .command('check <pipeline>')
314
+ .description('Validate config only; no execution')
315
+ .action((yaml) => {
316
+ void cmdCheck(yaml, program);
317
+ });
318
+ program
319
+ .command('plugins')
320
+ .description('List all loaded plugins (Tier 2 and Tier 3)')
321
+ .action(() => {
322
+ void cmdPlugins(program);
323
+ });
324
+ const mergeCmd = program
325
+ .command('merge')
326
+ .description('Merge strategy operations');
327
+ mergeCmd
328
+ .command('list-strategies')
329
+ .description('List all available merge strategies')
330
+ .action(() => {
331
+ void cmdMergeListStrategies(program);
332
+ });
333
+ mergeCmd
334
+ .command('info <strategy>')
335
+ .description('Show details about a specific merge strategy')
336
+ .action((strategyId) => {
337
+ void cmdMergeInfo(strategyId, program);
338
+ });
339
+ return program;
340
+ }
341
+ // Only parse when invoked as the entry point (not when imported from tests).
342
+ const invoked = process.argv[1] ?? '';
343
+ if (invoked.endsWith('cli.ts') ||
344
+ invoked.endsWith('cli.js') ||
345
+ invoked.endsWith('sluice') ||
346
+ invoked.endsWith('sluice.cmd')) {
347
+ buildProgram()
348
+ .parseAsync(process.argv)
349
+ .catch((err) => {
350
+ logger.error({ err }, 'sluice CLI: unexpected error');
351
+ process.exit(1);
352
+ });
353
+ }
354
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA,uCAAuC;AACvC,uCAAuC;AAEvC;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,aAAa,EAAiB,MAAM,mBAAmB,CAAC;AACjE,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AACrE,OAAO,EACL,cAAc,EACd,wBAAwB,GAEzB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAClG,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAC7F,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAyB,MAAM,qBAAqB,CAAC;AAW9E,MAAM,UAAU,iBAAiB,CAAC,GAAW,EAAE,aAAuB,EAAE;IACtE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC;QACxB,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,SAAS,CAAC;QAC5B,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;KACnD,CAAC,CAAC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,IAAI,GAAG,YAAY,eAAe;QAAE,OAAO,CAAC,CAAC;IAC7C,IAAI,GAAG,YAAY,WAAW;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,GAAG,YAAY,WAAW;QAAE,OAAO,CAAC,CAAC;IACzC,IAAI,GAAG,YAAY,aAAa;QAAE,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,CAAC;AACX,CAAC;AAED,SAAS,YAAY,CAAC,IAAgB;IACpC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAClB,IAAI,IAAI,CAAC,QAAQ;QAAE,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC;IAChD,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,iFAAiF;QACjF,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;IACzB,CAAC;IACD,MAAM,SAAS,GAAiB,EAAE,CAAC;IACnC,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS;QAAE,SAAS,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;IACjE,IAAI,IAAI,CAAC,MAAM;QAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC;IACzC,IAAI,IAAI,CAAC,OAAO,EAAE,MAAM;QAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC;IAC9D,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,SAAS,gBAAgB,CAAC,MAAgB,EAAE,UAAmB;IAC7D,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC;IAC7E,8EAA8E;IAC9E,+EAA+E;IAC/E,MAAM,UAAU,GACd,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC;QACtB,QAAQ;QACR,CAAC,UAAU;QACX,wBAAwB,EAAE,CAAC;IAC7B,MAAM,YAAY,GAAG,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAExC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,wBAAwB,GAAG,IAAI,GAAG,CACtC,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAkB,CAAC,CAC3E,CAAC;QACF,wGAAwG;QACxG,OAAO,CACL,MAAM,CAAC,OAAO,CAAC,MAAM;YACrB,wBAAwB,CAAC,IAAI;YAC7B,CAAC,GAAG,QAAQ;YACZ,YAAY;YACZ,CAAC,GAAG,gBAAgB;YACpB,CAAC,GAAG,YAAY;YAChB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CACnB,CAAC;IACJ,CAAC;IACD,8DAA8D;IAC9D,OAAO,CAAC,GAAG,YAAY,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,SAAS,qBAAqB,CAC5B,IAAgB,EAChB,MAAgB,EAChB,UAAU,GAAG,KAAK;IAElB,OAAO,IAAI,gBAAgB,CAAC;QAC1B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;QAC5B,WAAW,EAAE,gBAAgB,CAAC,MAAM,EAAE,UAAU,CAAC;QACjD,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAqB;KACxD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC7C,OAAO,aAAa,CAAC,MAAM,CAAC;QAC1B,CAAC,CAAC,IAAI,yBAAyB,EAAE;QACjC,CAAC,CAAC,IAAI,cAAc,EAAE,CAAC;AAC3B,CAAC;AAMD,KAAK,UAAU,MAAM,CACnB,IAAY,EACZ,OAAgB,EAChB,UAAsB,EAAE;IAExB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IACxC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;QAAE,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC;IAC1D,IAAI,QAAsC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,QAAQ,GAAG,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,UAAU,IAAI,KAAK,CAAC,CAAC;QAC9E,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CACT;YACE,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa;YAC3C,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU;YACpC,cAAc,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS;YACvC,aAAa,EAAE,MAAM,CAAC,KAAK,EAAE,SAAS;YACtC,UAAU,EAAE,MAAM,CAAC,IAAI,EAAE,UAAU,IAAI,CAAC;YACxC,SAAS,EAAE,MAAM,CAAC,aAAa;SAChC,EACD,sBAAsB,CACvB,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,IAAI,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,oBAAoB,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,IAAY,EAAE,OAAgB;IACvD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IACxC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,SAAS,CAAC,IAAI,GAAG,eAAe,CAAC;IACjC,IAAI,QAAsC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,QAAQ,GAAG,qBAAqB,CAAC,IAAI,EAAE,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE,EAAE,CAAC,CAAC;QACrG,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,IAAI,CACT;YACE,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,UAAU,EAAE,MAAM,CAAC,KAAK,EAAE,UAAU;YACpC,WAAW,EAAE,MAAM,CAAC,EAAE,CAAC,WAAW;YAClC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,QAAQ;YACvC,QAAQ,EAAE,MAAM,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO;SACvC,EACD,2BAA2B,CAC5B,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,IAAI,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,yBAAyB,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,IAAY,EAAE,OAAgB;IACtD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IACxC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,QAAsC,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,uBAAuB,CAAC,IAAI,CAAC,CAAC;QACnD,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,4EAA4E;QAC5E,QAAQ,GAAG,IAAI,gBAAgB,CAAC;YAC9B,MAAM,EAAE,IAAI,CAAC,MAAM,IAAI,KAAK;YAC5B,WAAW,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAClE,QAAQ,EAAE,CAAC,IAAI,CAAC,QAAQ,IAAI,MAAM,CAAqB;SACxD,CAAC,CAAC;QACH,SAAS,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAC9B,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACrD,MAAM,CAAC,IAAI,CACT,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,aAAa,EAAE,WAAW,EAAE,MAAM,CAAC,WAAW,EAAE,EAC3G,0BAA0B,CAC3B,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,QAAQ,EAAE,IAAI,EAAE,CAAC;QACjB,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,IAAY,EAAE,OAAgB;IACpD,YAAY,CAAC,OAAO,CAAC,IAAI,EAAc,CAAC,CAAC;IACzC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CACT;YACE,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,IAAI;YAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,IAAI,OAAO;YACzC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAChD,aAAa,EAAE,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS;YAC1D,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,OAAO;YAC7B,KAAK,EAAE,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,MAAM;YAC7B,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM;SACvC,EACD,+BAA+B,CAChC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sBAAsB,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,UAAU,CAAC,OAAgB;IACxC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,EAAc,CAAC;IACxC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAEtE,yDAAyD;QACzD,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;QACxD,MAAM,cAAc,CAAC,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QAEzF,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,EAAE,CAAC;QAC9C,MAAM,gBAAgB,GAAG,qBAAqB,CAAC,IAAI,EAAE,CAAC;QAEtD,MAAM,CAAC,IAAI,CACT;YACE,KAAK,EAAE,OAAO;YACd,UAAU,EAAE,YAAY;YACxB,eAAe,EAAE,gBAAgB;SAClC,EACD,wBAAwB,CACzB,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,wBAAwB,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,sBAAsB,CAAC,OAAgB;IACpD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAc,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAEtE,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;QACxD,MAAM,cAAc,CAAC,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QAEzF,MAAM,WAAW,GAAG,qBAAqB,CAAC,IAAI,EAAE,CAAC;QACjD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;YACxC,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/C,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,EAAE,EAAE,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;QAC/E,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CACT,EAAE,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,EACxC,sCAAsC,CACvC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,sCAAsC,CAAC,CAAC;QAC9D,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,UAAkB,EAAE,OAAgB;IAC9D,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAc,CAAC,CAAC;IAC3D,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;QAC1B,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;QACxC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC;QAClD,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,EAAE,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC,CAAC;QAEtE,KAAK,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;YAC7B,MAAM,WAAW,CAAC,GAAG,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QACjF,CAAC;QAED,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,oBAAoB,CAAC,CAAC;QACxD,MAAM,cAAc,CAAC,UAAU,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,CAAC,CAAC;QAEzF,MAAM,QAAQ,GAAG,qBAAqB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAEvD,MAAM,CAAC,IAAI,CACT;YACE,QAAQ,EAAE,QAAQ,CAAC,EAAE;YACrB,WAAW,EAAE,QAAQ,CAAC,WAAW,IAAI,QAAQ,CAAC,EAAE;SACjD,EACD,6BAA6B,CAC9B,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,UAAU,EAAE,EAAE,2BAA2B,CAAC,CAAC;QAC/D,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,mDAAmD,CAAC;SAChE,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,qBAAqB,EAAE,6BAA6B,CAAC;SAC5D,MAAM,CAAC,cAAc,EAAE,mBAAmB,EAAE,QAAQ,CAAC;SACrD,MAAM,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;SAClD,MAAM,CAAC,oBAAoB,EAAE,iDAAiD,CAAC;SAC/E,MAAM,CAAC,WAAW,EAAE,yBAAyB,CAAC;SAC9C,MAAM,CAAC,UAAU,EAAE,+DAA+D,CAAC,CAAC;IAEvF,OAAO;SACJ,OAAO,CAAC,gBAAgB,CAAC;SACzB,WAAW,CAAC,6BAA6B,CAAC;SAC1C,MAAM,CAAC,aAAa,EAAE,8DAA8D,CAAC;SACrF,MAAM,CAAC,CAAC,IAAY,EAAE,OAAmB,EAAE,EAAE;QAC5C,KAAK,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IACL,OAAO;SACJ,OAAO,CAAC,qBAAqB,CAAC;SAC9B,WAAW,CAAC,8BAA8B,CAAC;SAC3C,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACvB,KAAK,WAAW,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IACL,OAAO;SACJ,OAAO,CAAC,oBAAoB,CAAC;SAC7B,WAAW,CAAC,mCAAmC,CAAC;SAChD,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACvB,KAAK,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IACL,OAAO;SACJ,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,oCAAoC,CAAC;SACjD,MAAM,CAAC,CAAC,IAAY,EAAE,EAAE;QACvB,KAAK,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;IAEL,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,6CAA6C,CAAC;SAC1D,MAAM,CAAC,GAAG,EAAE;QACX,KAAK,UAAU,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;IAEL,MAAM,QAAQ,GAAG,OAAO;SACrB,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,2BAA2B,CAAC,CAAC;IAE5C,QAAQ;SACL,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,qCAAqC,CAAC;SAClD,MAAM,CAAC,GAAG,EAAE;QACX,KAAK,sBAAsB,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEL,QAAQ;SACL,OAAO,CAAC,iBAAiB,CAAC;SAC1B,WAAW,CAAC,8CAA8C,CAAC;SAC3D,MAAM,CAAC,CAAC,UAAkB,EAAE,EAAE;QAC7B,KAAK,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEL,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,6EAA6E;AAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;AACtC,IACE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC,EAC9B,CAAC;IACD,YAAY,EAAE;SACX,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC;SACxB,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACb,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,8BAA8B,CAAC,CAAC;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { ConfigLoader } from './loader.js';
2
+ export * from './types.js';
3
+ export * from './schema.js';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,6 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright (c) 2026 Caracal Lynx Ltd.
3
+ export { ConfigLoader } from './loader.js';
4
+ export * from './types.js';
5
+ export * from './schema.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,uCAAuC;AACvC,uCAAuC;AAEvC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { Pipeline } from './schema.js';
2
+ export declare class ConfigLoader {
3
+ static load(yamlPath: string): Promise<Pipeline>;
4
+ }
5
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAI5C,qBAAa,YAAY;WACV,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;CAmCvD"}
@@ -0,0 +1,135 @@
1
+ // SPDX-License-Identifier: Elastic-2.0
2
+ // Copyright (c) 2026 Caracal Lynx Ltd.
3
+ import path from 'node:path';
4
+ import { readFile } from 'node:fs/promises';
5
+ import { load as yamlLoad } from 'js-yaml';
6
+ import { PipelineSchema, CompositeRuleLibrarySchema, CheckType } from './schema.js';
7
+ import { ConfigError } from '../utils/errors.js';
8
+ import { requireEnv } from '../utils/env.js';
9
+ export class ConfigLoader {
10
+ static async load(yamlPath) {
11
+ // 1. Read file
12
+ let raw;
13
+ try {
14
+ raw = await readFile(yamlPath, 'utf-8');
15
+ }
16
+ catch (err) {
17
+ if (isEnoent(err)) {
18
+ throw new ConfigError(`Pipeline file not found: ${yamlPath}`, err);
19
+ }
20
+ throw err;
21
+ }
22
+ // 2. Interpolate ${ENV_VAR} tokens.
23
+ // Operates on the raw YAML text, so tokens anywhere — including inside
24
+ // comments or unrelated string values — are resolved. Missing vars throw
25
+ // ConfigError before the YAML is parsed. This is intentional: it keeps
26
+ // the resolver trivial and predictable for single-pass pipelines.
27
+ const interpolated = raw.replace(/\$\{([^}]+)\}/g, (_match, name) => requireEnv(name));
28
+ // 3. Parse YAML
29
+ let parsed;
30
+ try {
31
+ parsed = yamlLoad(interpolated);
32
+ }
33
+ catch (err) {
34
+ throw new ConfigError(`Invalid YAML in pipeline file: ${yamlPath}`, err);
35
+ }
36
+ // 4. Expand composite DQ rules (rulesFile → built-in checks)
37
+ parsed = await expandCompositeRules(parsed, yamlPath);
38
+ // 5. Validate with Zod schema (let ZodError propagate to the caller)
39
+ return PipelineSchema.parse(parsed);
40
+ }
41
+ }
42
+ /**
43
+ * If the raw parsed pipeline object references `dq.rulesFile`, load the
44
+ * composite rule library, build a map of id → checks, then walk
45
+ * `dq.rules[].checks[]` replacing any composite check entries with their
46
+ * constituent built-in checks (applying a severity override if present).
47
+ *
48
+ * Mutates and returns `raw` so downstream code sees built-in check types only.
49
+ */
50
+ async function expandCompositeRules(raw, pipelineYamlPath) {
51
+ const obj = raw;
52
+ const dq = obj['dq'];
53
+ if (!dq || !dq['rulesFile']) {
54
+ return raw;
55
+ }
56
+ const rulesFileRel = dq['rulesFile'];
57
+ const rulesFilePath = path.resolve(path.dirname(pipelineYamlPath), rulesFileRel);
58
+ // Load the composite rule library
59
+ let rulesFileContent;
60
+ try {
61
+ rulesFileContent = await readFile(rulesFilePath, 'utf-8');
62
+ }
63
+ catch (err) {
64
+ if (isEnoent(err)) {
65
+ throw new ConfigError(`rulesFile not found: ${rulesFilePath}`, err);
66
+ }
67
+ throw err;
68
+ }
69
+ let rawLibrary;
70
+ try {
71
+ rawLibrary = yamlLoad(rulesFileContent);
72
+ }
73
+ catch (err) {
74
+ throw new ConfigError(`Invalid YAML in rulesFile: ${rulesFilePath}`, err);
75
+ }
76
+ // Validate library schema (let ZodError propagate)
77
+ const library = CompositeRuleLibrarySchema.parse(rawLibrary);
78
+ // Reject duplicate ids explicitly — silently picking the last one would
79
+ // surprise anyone authoring a rules library.
80
+ const seen = new Set();
81
+ for (const r of library.rules) {
82
+ if (seen.has(r.id)) {
83
+ throw new ConfigError(`Duplicate composite rule id "${r.id}" in ${rulesFilePath}. ` +
84
+ `Each id in the rules library must be unique.`);
85
+ }
86
+ seen.add(r.id);
87
+ }
88
+ // Build composite map: id → checks[]
89
+ const compositeMap = new Map(library.rules.map(r => [r.id, r.checks]));
90
+ // Built-in check type names
91
+ const builtInTypes = new Set(CheckType.options);
92
+ // Expand checks in each dq rule
93
+ const rules = dq['rules'];
94
+ if (!Array.isArray(rules)) {
95
+ return raw;
96
+ }
97
+ // rulesFile has served its purpose — drop it so the post-expansion shape
98
+ // matches the engine's expectation that only built-in check types exist.
99
+ delete dq['rulesFile'];
100
+ dq['rules'] = rules.map((rule) => {
101
+ const r = rule;
102
+ const checks = r['checks'];
103
+ if (!Array.isArray(checks))
104
+ return r;
105
+ const expanded = [];
106
+ for (const check of checks) {
107
+ const c = check;
108
+ const checkType = c['type'];
109
+ if (builtInTypes.has(checkType)) {
110
+ // Built-in check — keep as-is
111
+ expanded.push(c);
112
+ }
113
+ else if (compositeMap.has(checkType)) {
114
+ // Composite rule — expand, applying severity override if present
115
+ const compositeChecks = compositeMap.get(checkType);
116
+ const severityOverride = c['severity'];
117
+ for (const cc of compositeChecks) {
118
+ expanded.push(severityOverride !== undefined
119
+ ? { ...cc, severity: severityOverride }
120
+ : { ...cc });
121
+ }
122
+ }
123
+ else {
124
+ throw new ConfigError(`Unknown rule type "${checkType}" in field rule — not a built-in check and not found in rulesFile. ` +
125
+ `Available composite rules: [${[...compositeMap.keys()].join(', ')}]`);
126
+ }
127
+ }
128
+ return { ...r, checks: expanded };
129
+ });
130
+ return raw;
131
+ }
132
+ function isEnoent(err) {
133
+ return err instanceof Error && err.code === 'ENOENT';
134
+ }
135
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}