@maschinenlesbar.org/regionalatlas-cli 0.0.1

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 (73) hide show
  1. package/CONTRIBUTING.md +25 -0
  2. package/LICENSE +661 -0
  3. package/LICENSING.md +47 -0
  4. package/README.md +85 -0
  5. package/dist/src/cli/commands/regions.d.ts +4 -0
  6. package/dist/src/cli/commands/regions.d.ts.map +1 -0
  7. package/dist/src/cli/commands/regions.js +66 -0
  8. package/dist/src/cli/commands/regions.js.map +1 -0
  9. package/dist/src/cli/index.d.ts +3 -0
  10. package/dist/src/cli/index.d.ts.map +1 -0
  11. package/dist/src/cli/index.js +11 -0
  12. package/dist/src/cli/index.js.map +1 -0
  13. package/dist/src/cli/io.d.ts +12 -0
  14. package/dist/src/cli/io.d.ts.map +1 -0
  15. package/dist/src/cli/io.js +7 -0
  16. package/dist/src/cli/io.js.map +1 -0
  17. package/dist/src/cli/program.d.ts +7 -0
  18. package/dist/src/cli/program.d.ts.map +1 -0
  19. package/dist/src/cli/program.js +54 -0
  20. package/dist/src/cli/program.js.map +1 -0
  21. package/dist/src/cli/run.d.ts +3 -0
  22. package/dist/src/cli/run.d.ts.map +1 -0
  23. package/dist/src/cli/run.js +85 -0
  24. package/dist/src/cli/run.js.map +1 -0
  25. package/dist/src/cli/shared.d.ts +73 -0
  26. package/dist/src/cli/shared.d.ts.map +1 -0
  27. package/dist/src/cli/shared.js +154 -0
  28. package/dist/src/cli/shared.js.map +1 -0
  29. package/dist/src/client/catalog.d.ts +32 -0
  30. package/dist/src/client/catalog.d.ts.map +1 -0
  31. package/dist/src/client/catalog.js +127 -0
  32. package/dist/src/client/catalog.js.map +1 -0
  33. package/dist/src/client/client.d.ts +56 -0
  34. package/dist/src/client/client.d.ts.map +1 -0
  35. package/dist/src/client/client.js +195 -0
  36. package/dist/src/client/client.js.map +1 -0
  37. package/dist/src/client/engine.d.ts +77 -0
  38. package/dist/src/client/engine.d.ts.map +1 -0
  39. package/dist/src/client/engine.js +167 -0
  40. package/dist/src/client/engine.js.map +1 -0
  41. package/dist/src/client/errors.d.ts +51 -0
  42. package/dist/src/client/errors.d.ts.map +1 -0
  43. package/dist/src/client/errors.js +63 -0
  44. package/dist/src/client/errors.js.map +1 -0
  45. package/dist/src/client/http.d.ts +26 -0
  46. package/dist/src/client/http.d.ts.map +1 -0
  47. package/dist/src/client/http.js +80 -0
  48. package/dist/src/client/http.js.map +1 -0
  49. package/dist/src/client/index.d.ts +15 -0
  50. package/dist/src/client/index.d.ts.map +1 -0
  51. package/dist/src/client/index.js +11 -0
  52. package/dist/src/client/index.js.map +1 -0
  53. package/dist/src/client/levels.d.ts +16 -0
  54. package/dist/src/client/levels.d.ts.map +1 -0
  55. package/dist/src/client/levels.js +59 -0
  56. package/dist/src/client/levels.js.map +1 -0
  57. package/dist/src/client/query.d.ts +9 -0
  58. package/dist/src/client/query.d.ts.map +1 -0
  59. package/dist/src/client/query.js +33 -0
  60. package/dist/src/client/query.js.map +1 -0
  61. package/dist/src/client/sql.d.ts +12 -0
  62. package/dist/src/client/sql.d.ts.map +1 -0
  63. package/dist/src/client/sql.js +64 -0
  64. package/dist/src/client/sql.js.map +1 -0
  65. package/dist/src/client/types.d.ts +137 -0
  66. package/dist/src/client/types.d.ts.map +1 -0
  67. package/dist/src/client/types.js +5 -0
  68. package/dist/src/client/types.js.map +1 -0
  69. package/dist/src/index.d.ts +2 -0
  70. package/dist/src/index.d.ts.map +1 -0
  71. package/dist/src/index.js +3 -0
  72. package/dist/src/index.js.map +1 -0
  73. package/package.json +71 -0
package/LICENSING.md ADDED
@@ -0,0 +1,47 @@
1
+ # Licensing
2
+
3
+ `regionalatlas-cli` is **dual-licensed**. You may use it under **either** of the
4
+ following, at your choice:
5
+
6
+ ## 1. Open source — AGPL-3.0-or-later (default)
7
+
8
+ Free to use, modify, and distribute under the
9
+ [GNU Affero General Public License v3.0 or later](LICENSE).
10
+
11
+ The key obligation is the AGPL's **§13 network clause**: if you run a modified
12
+ version of this software to provide a service to others over a network, you must
13
+ make the complete corresponding source code of your modified version available
14
+ to the users of that service. The usual copyleft terms also apply when you
15
+ distribute the software or works based on it.
16
+
17
+ This is the right option for open-source projects, internal and personal use,
18
+ evaluation, and anyone able to comply with the AGPL.
19
+
20
+ ## 2. Commercial license
21
+
22
+ If the AGPL's obligations do not fit your situation — for example, you want to:
23
+
24
+ - embed `regionalatlas-cli` in a **closed-source / proprietary product**, or
25
+ - run a **modified version as a proprietary network service (SaaS)** without
26
+ disclosing your source, or
27
+ - keep your modifications private,
28
+
29
+ then a separate **commercial license** is available. It grants use of the same
30
+ code without the AGPL's copyleft and network-disclosure obligations, under
31
+ negotiated terms.
32
+
33
+ **To obtain a commercial license, contact:** sebs@2xs.org
34
+
35
+ ## Why this is possible
36
+
37
+ The copyright holder owns 100% of the source code in this repository and can
38
+ therefore offer it under more than one license simultaneously. This project does
39
+ **not** accept external code contributions (see [CONTRIBUTING.md](CONTRIBUTING.md)),
40
+ which keeps copyright ownership single and unambiguous — a prerequisite for
41
+ offering the commercial option. The only third-party dependency that ships with
42
+ the package, [`commander`](https://github.com/tj/commander.js), is MIT-licensed
43
+ and compatible with both licensing options.
44
+
45
+ ---
46
+
47
+ Copyright © 2026 Sebastian Schürmann. All rights reserved.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # regionalatlas-cli
2
+
3
+ A dependency-light **TypeScript client + CLI** for the **Regionalatlas Deutschland** —
4
+ the regional-statistics indicators of the **Statistische Ämter des Bundes und der
5
+ Länder** (Destatis and the 16 Länder offices), broken down per **Bundesland /
6
+ Regierungsbezirk / Kreis / Gemeinde**. Backed by a public **ArcGIS MapServer** plus a
7
+ static indicator catalogue.
8
+
9
+ - **No API key.** The regional-statistics data is open.
10
+ - **Zero runtime HTTP dependencies.** Built on `node:http`/`https`; the CLI's only
11
+ runtime dependency is `commander`.
12
+ - **Library + CLI.** Use the typed `RegionalatlasClient`, or the `regionalatlas` command.
13
+
14
+ > **We provide the tool, not the data.** The data is © the **Statistische Ämter des
15
+ > Bundes und der Länder** under **Datenlizenz Deutschland – Namensnennung 2.0**
16
+ > (dl-de/by-2.0) — free to use with attribution. See [DATA_LICENSE.md](DATA_LICENSE.md).
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ npm install -g @maschinenlesbar.org/regionalatlas-cli # the `regionalatlas` command
22
+ # or as a library:
23
+ npm install @maschinenlesbar.org/regionalatlas-cli
24
+ ```
25
+
26
+ ## CLI
27
+
28
+ ```bash
29
+ regionalatlas themes # the 21 subject areas
30
+ regionalatlas indicators --search bevölkerung # matching indicators
31
+ regionalatlas indicators --theme Bevölkerung --year 2024 # filter by theme + year
32
+ regionalatlas query AI002-1-5 --level land --year 2020 # 16 Bundesländer rows
33
+ regionalatlas query AI002-1-5 --level kreis # ~400 Kreise (latest year)
34
+ regionalatlas query AI002-1-5 --level land --region Bayern # one region
35
+ regionalatlas query AI002-1-5 --level land --fields ai0201 # project value fields
36
+ ```
37
+
38
+ - **`themes`** lists the subject areas (Themenbereiche) and their indicator counts.
39
+ - **`indicators`** lists the indicators — `code`, short title, year range — with
40
+ `--theme` / `--year` / `--search` filters.
41
+ - **`query <code>`** fetches the data rows for an indicator at a geo level (`--level`,
42
+ default `land`), for a year (`--year`, default the indicator's latest). `--region`
43
+ and `--fields` filter and project **client-side**.
44
+
45
+ Global flags: `--base-url`, `--catalog-url`, `--timeout`, `--user-agent`,
46
+ `--max-retries`, `--max-response-bytes`, `--compact`. See [Usage.md](Usage.md).
47
+
48
+ ## Library
49
+
50
+ ```ts
51
+ import { RegionalatlasClient } from "@maschinenlesbar.org/regionalatlas-cli";
52
+
53
+ const c = new RegionalatlasClient();
54
+ await c.themes(); // the subject areas
55
+ await c.indicators({ search: "bevölkerung" }); // matching indicators
56
+ const rows = await c.query({ indicator: "AI002-1-5", level: "land", year: 2020 });
57
+ ```
58
+
59
+ ## Two hosts
60
+
61
+ Unlike most siblings, this CLI talks to **two** upstreams (documented in
62
+ [DEVELOPING.md](DEVELOPING.md)):
63
+
64
+ 1. the **indicator catalogue** (`services.json` on statistikportal.de), and
65
+ 2. the **ArcGIS MapServer** data query on gis-idmz.nrw.de, whose `dynamicLayer`
66
+ runs a raw SQL join.
67
+
68
+ Because the data query embeds raw SQL, the indicator, geo level, and year are all
69
+ **validated against the catalogue allowlist before any SQL is built** — a bogus
70
+ indicator never reaches the server. See the injection-guard section in
71
+ [DEVELOPING.md](DEVELOPING.md).
72
+
73
+ ## Documentation
74
+
75
+ - [Usage.md](Usage.md) — commands, options, the geo levels, exit codes
76
+ - [DEVELOPING.md](DEVELOPING.md) — architecture, the two-host split, the SQL guard
77
+ - [GLOSSARY.md](GLOSSARY.md) — AGS, typ / geo levels, Indikator, table code, precision flags
78
+ - [DATA_LICENSE.md](DATA_LICENSE.md) — the dl-de/by-2.0 data terms
79
+ - [SKILLS.md](SKILLS.md) — the Claude Code skills this repo ships
80
+
81
+ ## Licence
82
+
83
+ Code is dual-licensed **AGPL-3.0-or-later OR commercial** — see
84
+ [LICENSING.md](LICENSING.md). No external code contributions are accepted (see
85
+ [CONTRIBUTING.md](CONTRIBUTING.md)); bug reports and AGPL forks are welcome.
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { CliDeps } from "../io.js";
3
+ export declare function registerCommands(program: Command, deps: CliDeps): void;
4
+ //# sourceMappingURL=regions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/regions.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAoBxC,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CA8DtE"}
@@ -0,0 +1,66 @@
1
+ // Command group for the Regionalatlas CLI:
2
+ // - `themes` list the 21 subject areas (title + indicator count)
3
+ // - `indicators` list indicators (code, short title, years), with filters
4
+ // - `query` fetch data rows for an indicator at a chosen geo level
5
+ import { action, parseFieldList, parseLevel, parseNonEmpty, parseYear, renderJson, } from "../shared.js";
6
+ /** A one-line year range summary (e.g. "2000–2024" or a single year). */
7
+ function yearRange(years) {
8
+ if (years.length === 0)
9
+ return "—";
10
+ const first = years[0];
11
+ const last = years[years.length - 1];
12
+ return first === last ? String(first) : `${first}–${last}`;
13
+ }
14
+ export function registerCommands(program, deps) {
15
+ program
16
+ .command("themes")
17
+ .description("List the subject areas (Themenbereiche) with their indicator counts")
18
+ .action(action(deps, async ({ client, global }) => {
19
+ renderJson(deps, global, await client.themes());
20
+ }));
21
+ program
22
+ .command("indicators")
23
+ .description("List indicators (Indikatoren): code, short title, available years")
24
+ .option("--theme <substr>", "filter by theme title (case-insensitive substring)", parseNonEmpty)
25
+ .option("--year <yyyy>", "only indicators offering this year", parseYear)
26
+ .option("--search <substr>", "filter over code + short + long title (case-insensitive)", parseNonEmpty)
27
+ .action(action(deps, async ({ client, global, opts }) => {
28
+ const filter = {};
29
+ if (typeof opts["theme"] === "string")
30
+ filter.theme = opts["theme"];
31
+ if (typeof opts["year"] === "number")
32
+ filter.year = opts["year"];
33
+ if (typeof opts["search"] === "string")
34
+ filter.search = opts["search"];
35
+ const indicators = await client.indicators(filter);
36
+ renderJson(deps, global, indicators.map((ind) => ({
37
+ code: ind.code,
38
+ table: ind.table,
39
+ theme: ind.theme,
40
+ titleShort: ind.titleShort,
41
+ years: yearRange(ind.years),
42
+ })));
43
+ }));
44
+ program
45
+ .command("query")
46
+ .description("Fetch indicator data rows per region (Bundesland / Kreis / Gemeinde)")
47
+ .argument("<indicator-code>", "indicator code (AI002-1-5) or table form (ai002_1_5)", parseNonEmpty)
48
+ .option("--level <level>", "geo level: land | regierungsbezirk | kreis | gemeinde", parseLevel, "land")
49
+ .option("--year <yyyy>", "reporting year (defaults to the indicator's latest)", parseYear)
50
+ .option("--region <name|ags>", "keep only rows matching this name (substring) or AGS", parseNonEmpty)
51
+ .option("--fields <a,b,c>", "keep only these value fields (comma-separated)", parseFieldList)
52
+ .action(action(deps, async ({ client, global, opts }, [indicator]) => {
53
+ const query = {
54
+ indicator: indicator,
55
+ level: typeof opts["level"] === "string" ? opts["level"] : "land",
56
+ };
57
+ if (typeof opts["year"] === "number")
58
+ query.year = opts["year"];
59
+ if (typeof opts["region"] === "string")
60
+ query.region = opts["region"];
61
+ if (Array.isArray(opts["fields"]))
62
+ query.fields = opts["fields"];
63
+ renderJson(deps, global, await client.query(query));
64
+ }));
65
+ }
66
+ //# sourceMappingURL=regions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regions.js","sourceRoot":"","sources":["../../../../src/cli/commands/regions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":""}
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env node
2
+ // Bin shim: parse argv, run the CLI, and set the process exit code. All real
3
+ // logic lives in run.ts (testable without spawning a subprocess).
4
+ import { run } from "./run.js";
5
+ run(process.argv.slice(2)).then((code) => {
6
+ process.exitCode = code;
7
+ }, (err) => {
8
+ process.stderr.write(`Unexpected error: ${err instanceof Error ? err.message : String(err)}\n`);
9
+ process.exitCode = 1;
10
+ });
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AACA,6EAA6E;AAC7E,kEAAkE;AAElE,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAC7B,CAAC,IAAI,EAAE,EAAE;IACP,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;AAC1B,CAAC,EACD,CAAC,GAAY,EAAE,EAAE;IACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAChG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;AACvB,CAAC,CACF,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { RegionalatlasClient, RegionalatlasClientOptions } from "../client/client.js";
2
+ export interface CliIO {
3
+ out(text: string): void;
4
+ err(text: string): void;
5
+ }
6
+ export interface CliDeps {
7
+ io: CliIO;
8
+ /** Build a client from the resolved global options (injectable for tests). */
9
+ createClient(options: RegionalatlasClientOptions): RegionalatlasClient;
10
+ }
11
+ export declare const defaultIO: CliIO;
12
+ //# sourceMappingURL=io.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.d.ts","sourceRoot":"","sources":["../../../src/cli/io.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAE3F,MAAM,WAAW,KAAK;IACpB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACzB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,KAAK,CAAC;IACV,8EAA8E;IAC9E,YAAY,CAAC,OAAO,EAAE,0BAA0B,GAAG,mBAAmB,CAAC;CACxE;AAED,eAAO,MAAM,SAAS,EAAE,KAGvB,CAAC"}
@@ -0,0 +1,7 @@
1
+ // I/O seam for the CLI. Everything the CLI writes goes through a CliIO object so
2
+ // tests can capture output instead of hitting the real stdout/stderr.
3
+ export const defaultIO = {
4
+ out: (text) => process.stdout.write(text + "\n"),
5
+ err: (text) => process.stderr.write(text + "\n"),
6
+ };
7
+ //# sourceMappingURL=io.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"io.js","sourceRoot":"","sources":["../../../src/cli/io.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,sEAAsE;AAetE,MAAM,CAAC,MAAM,SAAS,GAAU;IAC9B,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;IAChD,GAAG,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC;CACjD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { Command } from "commander";
2
+ import type { CliDeps } from "./io.js";
3
+ export declare const VERSION: string;
4
+ /** Default dependencies: real client + real stdout/stderr. */
5
+ export declare const defaultDeps: CliDeps;
6
+ export declare function buildProgram(deps?: CliDeps): Command;
7
+ //# sourceMappingURL=program.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.d.ts","sourceRoot":"","sources":["../../../src/cli/program.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAsBvC,eAAO,MAAM,OAAO,QAAgB,CAAC;AAErC,8DAA8D;AAC9D,eAAO,MAAM,WAAW,EAAE,OAGzB,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,GAAE,OAAqB,GAAG,OAAO,CAuCjE"}
@@ -0,0 +1,54 @@
1
+ // Assemble the full commander program. The program is built around an injectable
2
+ // CliDeps so the entire CLI can be driven in tests with a mocked client and
3
+ // captured output.
4
+ import { readFileSync } from "node:fs";
5
+ import { fileURLToPath } from "node:url";
6
+ import { Command } from "commander";
7
+ import { defaultIO } from "./io.js";
8
+ import { RegionalatlasClient } from "../client/client.js";
9
+ import { parseIntArg, parseBoundedInt, parseHeaderValue, parseHttpUrl } from "./shared.js";
10
+ import { registerCommands } from "./commands/regions.js";
11
+ /**
12
+ * Single source of truth for the version: read from package.json at runtime
13
+ * rather than duplicating a literal that can silently drift after a release bump.
14
+ * From the compiled location (dist/src/cli/program.js) package.json is three
15
+ * directories up; the same offset holds for the source under src/cli.
16
+ */
17
+ function readVersion() {
18
+ try {
19
+ const pkgUrl = new URL("../../../package.json", import.meta.url);
20
+ const pkg = JSON.parse(readFileSync(fileURLToPath(pkgUrl), "utf8"));
21
+ return pkg.version ?? "0.0.0";
22
+ }
23
+ catch {
24
+ return "0.0.0";
25
+ }
26
+ }
27
+ export const VERSION = readVersion();
28
+ /** Default dependencies: real client + real stdout/stderr. */
29
+ export const defaultDeps = {
30
+ io: defaultIO,
31
+ createClient: (options) => new RegionalatlasClient(options),
32
+ };
33
+ export function buildProgram(deps = defaultDeps) {
34
+ const program = new Command();
35
+ program
36
+ .name("regionalatlas")
37
+ .description("CLI for the Regionalatlas Deutschland — regional-statistics indicators of the " +
38
+ "Statistische Ämter des Bundes und der Länder, per Bundesland / Regierungsbezirk / " +
39
+ "Kreis / Gemeinde. No API key needed. `themes` lists the subject areas; `indicators` " +
40
+ "lists the indicators (with --theme/--year/--search filters); `query <code> --level " +
41
+ "<land|kreis|…>` fetches the data rows for a year.")
42
+ .version(VERSION)
43
+ .option("--base-url <url>", "ArcGIS data host base URL", parseHttpUrl, "https://www.gis-idmz.nrw.de")
44
+ .option("--catalog-url <url>", "indicator catalogue URL (services.json)", parseHttpUrl, "https://regionalatlas.statistikportal.de/taskrunner/services.json")
45
+ .option("--timeout <ms>", "per-request timeout in ms (0 = no timeout)", parseIntArg)
46
+ .option("--user-agent <ua>", "User-Agent header value", parseHeaderValue)
47
+ .option("--max-retries <n>", "retries for transient 429/503 responses (0..10)", parseBoundedInt(0, 10))
48
+ .option("--max-response-bytes <n>", "cap response body size in bytes (0 = unlimited; default 100 MiB)", parseIntArg)
49
+ .option("--compact", "print JSON on a single line instead of pretty-printed")
50
+ .showHelpAfterError();
51
+ registerCommands(program, deps);
52
+ return program;
53
+ }
54
+ //# sourceMappingURL=program.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"program.js","sourceRoot":"","sources":["../../../src/cli/program.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,4EAA4E;AAC5E,mBAAmB;AAEnB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3F,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD;;;;;GAKG;AACH,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAyB,CAAC;QAC5F,OAAO,GAAG,CAAC,OAAO,IAAI,OAAO,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;AAErC,8DAA8D;AAC9D,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,EAAE,EAAE,SAAS;IACb,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,OAAO,CAAC;CAC5D,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB,WAAW;IACtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,eAAe,CAAC;SACrB,WAAW,CACV,gFAAgF;QAC9E,oFAAoF;QACpF,sFAAsF;QACtF,qFAAqF;QACrF,mDAAmD,CACtD;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CACL,kBAAkB,EAClB,2BAA2B,EAC3B,YAAY,EACZ,6BAA6B,CAC9B;SACA,MAAM,CACL,qBAAqB,EACrB,yCAAyC,EACzC,YAAY,EACZ,mEAAmE,CACpE;SACA,MAAM,CAAC,gBAAgB,EAAE,4CAA4C,EAAE,WAAW,CAAC;SACnF,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,EAAE,gBAAgB,CAAC;SACxE,MAAM,CAAC,mBAAmB,EAAE,iDAAiD,EAAE,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;SACtG,MAAM,CACL,0BAA0B,EAC1B,kEAAkE,EAClE,WAAW,CACZ;SACA,MAAM,CAAC,WAAW,EAAE,uDAAuD,CAAC;SAC5E,kBAAkB,EAAE,CAAC;IAExB,gBAAgB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEhC,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CliDeps } from "./io.js";
2
+ export declare function run(argv: string[], deps?: CliDeps): Promise<number>;
3
+ //# sourceMappingURL=run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAqCvC,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,OAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAkDtF"}
@@ -0,0 +1,85 @@
1
+ // Run the CLI and resolve to a process exit code. Kept separate from the bin
2
+ // shim so tests can call run() directly with injected deps and assert on the
3
+ // captured output and exit code without spawning a subprocess.
4
+ import { CommanderError } from "commander";
5
+ import { buildProgram, defaultDeps } from "./program.js";
6
+ import { RegionalatlasApiError, RegionalatlasError, RegionalatlasNetworkError, RegionalatlasValidationError, } from "../client/errors.js";
7
+ /**
8
+ * Process exit codes. Distinct codes let scripts tell apart a usage error, a
9
+ * missing resource, a transport failure, and a catch-all.
10
+ */
11
+ const EXIT = {
12
+ /** Usage / parse / client-side validation error. */
13
+ USAGE: 2,
14
+ /** HTTP 404 — resource not found. */
15
+ NOT_FOUND: 4,
16
+ /** Network / transport failure (DNS, connection, timeout, size-cap). */
17
+ NETWORK: 6,
18
+ /** Any other error. */
19
+ OTHER: 1,
20
+ };
21
+ /**
22
+ * Apply exitOverride + output redirection to every command in the tree.
23
+ * commander does not propagate these to subcommands, so a parse error on a
24
+ * subcommand would otherwise call process.exit() and bypass our error handling.
25
+ */
26
+ function configureTree(command, deps) {
27
+ command.exitOverride();
28
+ command.configureOutput({
29
+ writeOut: (str) => deps.io.out(str.replace(/\n$/, "")),
30
+ writeErr: (str) => deps.io.err(str.replace(/\n$/, "")),
31
+ });
32
+ for (const child of command.commands)
33
+ configureTree(child, deps);
34
+ }
35
+ export async function run(argv, deps = defaultDeps) {
36
+ const program = buildProgram(deps);
37
+ configureTree(program, deps);
38
+ // A bare invocation (no command) is a help request, not an error: print help
39
+ // to stdout and exit 0, matching `--help`.
40
+ if (argv.length === 0) {
41
+ deps.io.out(program.helpInformation().replace(/\n$/, ""));
42
+ return 0;
43
+ }
44
+ try {
45
+ await program.parseAsync(argv, { from: "user" });
46
+ return 0;
47
+ }
48
+ catch (err) {
49
+ if (err instanceof CommanderError) {
50
+ // Help/version requests exit 0; every genuine usage/parse error maps to a
51
+ // single USAGE code (commander's own exitCode is 1, indistinguishable from
52
+ // the catch-all).
53
+ return err.exitCode === 0 ? 0 : EXIT.USAGE;
54
+ }
55
+ if (err instanceof RegionalatlasValidationError) {
56
+ deps.io.err(`Error: ${err.message}`);
57
+ return EXIT.USAGE;
58
+ }
59
+ if (err instanceof RegionalatlasApiError) {
60
+ deps.io.err(`Error: ${err.message}`);
61
+ if (err.status === 404)
62
+ return EXIT.NOT_FOUND;
63
+ // A 3xx means the base URL redirected (the canonical host answers directly),
64
+ // so it is a base-URL misconfiguration — a usage error.
65
+ if (err.status !== undefined && err.status >= 300 && err.status < 400)
66
+ return EXIT.USAGE;
67
+ return EXIT.OTHER;
68
+ }
69
+ if (err instanceof RegionalatlasNetworkError) {
70
+ deps.io.err(`Error: ${err.message}`);
71
+ if (/maxResponseBytes/.test(err.message)) {
72
+ deps.io.err("Hint: the response exceeded the size cap. Narrow the query (a coarser --level) or " +
73
+ "raise --max-response-bytes <n> (0 = unlimited).");
74
+ }
75
+ return EXIT.NETWORK;
76
+ }
77
+ if (err instanceof RegionalatlasError) {
78
+ deps.io.err(`Error: ${err.message}`);
79
+ return EXIT.OTHER;
80
+ }
81
+ deps.io.err(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);
82
+ return EXIT.OTHER;
83
+ }
84
+ }
85
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,73 @@
1
+ import type { CliDeps } from "./io.js";
2
+ import type { RegionalatlasClientOptions } from "../client/client.js";
3
+ /**
4
+ * commander value-parser: a plain base-10 non-negative integer.
5
+ *
6
+ * Uses a strict regex rather than `Number()` coercion, which would otherwise
7
+ * accept empty/whitespace strings (`Number("") === 0`), hex/binary/scientific
8
+ * literals, signs, padding and decimals.
9
+ */
10
+ export declare function parseIntArg(value: string): number;
11
+ /** commander value-parser: a 4-digit year (integer 1000..9999). */
12
+ export declare function parseYear(value: string): number;
13
+ /** commander value-parser: a non-empty (after trimming) string. */
14
+ export declare function parseNonEmpty(value: string): string;
15
+ /**
16
+ * commander value-parser for `--level`: resolves a friendly name/alias to the
17
+ * canonical level name, rejecting an unknown level at parse time (exit 2) with a
18
+ * clear message. The client re-resolves it (defence in depth) and only the fixed
19
+ * integer `typ` ever enters SQL.
20
+ */
21
+ export declare function parseLevel(value: string): string;
22
+ /**
23
+ * commander value-parser for a comma-separated field list. Splits on commas,
24
+ * trims, and drops empty entries. Field names are validated/projected client-side
25
+ * later, so this only produces a clean array.
26
+ */
27
+ export declare function parseFieldList(value: string): string[];
28
+ /**
29
+ * commander value-parser for `--base-url` / `--catalog-url`: a non-empty,
30
+ * well-formed URL whose scheme is `http:` or `https:`. Validating here (parse time)
31
+ * rejects a bad scheme (`file:`, `ftp:`, ...) as a usage error (exit 2) with a clear
32
+ * message, rather than letting it reach the transport and surface as a network error
33
+ * (exit 6). The transport re-checks the scheme as defence in depth.
34
+ */
35
+ export declare function parseHttpUrl(value: string): string;
36
+ /** Build a commander value-parser for an integer constrained to [min, max]. */
37
+ export declare function parseBoundedInt(min: number, max: number): (value: string) => number;
38
+ /**
39
+ * commander value-parser for a value that ends up in an HTTP header (User-Agent).
40
+ * Rejects control characters — a CR/LF (or other C0/DEL byte) would otherwise reach
41
+ * Node's HTTP layer and throw an opaque `ERR_INVALID_CHAR`. Tab (0x09) is allowed;
42
+ * checked by char code so the source stays free of control bytes.
43
+ */
44
+ export declare function parseHeaderValue(value: string): string;
45
+ export interface GlobalOptions {
46
+ baseUrl?: string;
47
+ catalogUrl?: string;
48
+ timeout?: number;
49
+ userAgent?: string;
50
+ maxRetries?: number;
51
+ maxResponseBytes?: number;
52
+ compact?: boolean;
53
+ }
54
+ /** Translate resolved global CLI options into client options. */
55
+ export declare function toEngineOptions(global: GlobalOptions): RegionalatlasClientOptions;
56
+ /** Render a JSON value to stdout, pretty by default, compact with --compact. */
57
+ export declare function renderJson(deps: CliDeps, global: GlobalOptions, value: unknown): void;
58
+ export interface ActionContext {
59
+ client: ReturnType<CliDeps["createClient"]>;
60
+ global: GlobalOptions;
61
+ /** This command's own parsed options. */
62
+ opts: Record<string, unknown>;
63
+ }
64
+ /**
65
+ * Wrap an async command action with consistent global-option resolution and
66
+ * client construction. The callback receives a context (client + resolved global
67
+ * options + this command's options) and the command's positional arguments.
68
+ *
69
+ * Commander invokes actions as (arg1, ..., argN, options, command); we slice off
70
+ * the trailing options object and command instance to recover the positionals.
71
+ */
72
+ export declare function action(deps: CliDeps, fn: (ctx: ActionContext, positionals: string[]) => Promise<void>): (...args: unknown[]) => Promise<void>;
73
+ //# sourceMappingURL=shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAGtE;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASjD;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAK/C;AAED,mEAAmE;AACnE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKnD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAShD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,CAStD;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAelD;AAED,+EAA+E;AAC/E,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAOnF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQtD;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,iEAAiE;AACjE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,0BAA0B,CASjF;AAED,gFAAgF;AAChF,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAGrF;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,UAAU,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC,CAAC;IAC5C,MAAM,EAAE,aAAa,CAAC;IACtB,yCAAyC;IACzC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,OAAO,EACb,EAAE,EAAE,CAAC,GAAG,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAC/D,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAQvC"}