@maschinenlesbar.org/bundeshaushalt-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 (65) hide show
  1. package/CONTRIBUTING.md +25 -0
  2. package/LICENSE +661 -0
  3. package/LICENSING.md +47 -0
  4. package/README.md +203 -0
  5. package/dist/src/cli/commands/budget.d.ts +4 -0
  6. package/dist/src/cli/commands/budget.d.ts.map +1 -0
  7. package/dist/src/cli/commands/budget.js +86 -0
  8. package/dist/src/cli/commands/budget.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 +6 -0
  12. package/dist/src/cli/index.js.map +1 -0
  13. package/dist/src/cli/io.d.ts +13 -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 +48 -0
  24. package/dist/src/cli/run.js.map +1 -0
  25. package/dist/src/cli/shared.d.ts +51 -0
  26. package/dist/src/cli/shared.d.ts.map +1 -0
  27. package/dist/src/cli/shared.js +81 -0
  28. package/dist/src/cli/shared.js.map +1 -0
  29. package/dist/src/client/client.d.ts +9 -0
  30. package/dist/src/client/client.d.ts.map +1 -0
  31. package/dist/src/client/client.js +32 -0
  32. package/dist/src/client/client.js.map +1 -0
  33. package/dist/src/client/engine.d.ts +56 -0
  34. package/dist/src/client/engine.d.ts.map +1 -0
  35. package/dist/src/client/engine.js +159 -0
  36. package/dist/src/client/engine.js.map +1 -0
  37. package/dist/src/client/enums.d.ts +17 -0
  38. package/dist/src/client/enums.d.ts.map +1 -0
  39. package/dist/src/client/enums.js +16 -0
  40. package/dist/src/client/enums.js.map +1 -0
  41. package/dist/src/client/errors.d.ts +33 -0
  42. package/dist/src/client/errors.d.ts.map +1 -0
  43. package/dist/src/client/errors.js +40 -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 +89 -0
  48. package/dist/src/client/http.js.map +1 -0
  49. package/dist/src/client/index.d.ts +11 -0
  50. package/dist/src/client/index.d.ts.map +1 -0
  51. package/dist/src/client/index.js +9 -0
  52. package/dist/src/client/index.js.map +1 -0
  53. package/dist/src/client/query.d.ts +9 -0
  54. package/dist/src/client/query.d.ts.map +1 -0
  55. package/dist/src/client/query.js +33 -0
  56. package/dist/src/client/query.js.map +1 -0
  57. package/dist/src/client/types.d.ts +66 -0
  58. package/dist/src/client/types.d.ts.map +1 -0
  59. package/dist/src/client/types.js +4 -0
  60. package/dist/src/client/types.js.map +1 -0
  61. package/dist/src/index.d.ts +2 -0
  62. package/dist/src/index.d.ts.map +1 -0
  63. package/dist/src/index.js +3 -0
  64. package/dist/src/index.js.map +1 -0
  65. package/package.json +66 -0
package/LICENSING.md ADDED
@@ -0,0 +1,47 @@
1
+ # Licensing
2
+
3
+ `bundeshaushalt-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 `bundeshaushalt-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,203 @@
1
+ # bundeshaushalt-cli
2
+
3
+ A TypeScript **API client** and **command-line interface** for the open
4
+ [Bundeshaushalt](https://bundeshaushalt.de/) budget-data API (`bundeshaushalt.de`)
5
+ — the **German federal budget**: expenses and income by budget item, functional
6
+ area or economic group, planned vs. realised.
7
+
8
+ - **Zero runtime HTTP dependencies** — built on Node's built-in `http`/`https` (no axios, no fetch polyfill).
9
+ - **One small dependency** for the CLI: [`commander`](https://github.com/tj/commander.js).
10
+ - **Strongly typed** — typed budget elements, metadata and the account/quota/unit enums.
11
+ - **Well tested** — unit tests on Node's built-in test runner (`node --test`), every HTTP response mocked.
12
+ - **Read-only, no auth** — the budget-data API needs no key; this client only reads.
13
+
14
+ ## Requirements
15
+
16
+ - Node.js **>= 20** (uses the stable built-in test runner, ESM and top-level `await`).
17
+
18
+ ## Install
19
+
20
+ ```bash
21
+ npm install
22
+ npm run build # compiles TypeScript to dist/
23
+ ```
24
+
25
+ Run the CLI without a global install:
26
+
27
+ ```bash
28
+ node dist/src/cli/index.js --help
29
+ # or, after `npm link` / global install:
30
+ bundeshaushalt --help
31
+ ```
32
+
33
+ ---
34
+
35
+ ## How the data is shaped
36
+
37
+ A query is a **year** + **account** (`expenses` / `income`). Optionally narrow by:
38
+
39
+ - **quota** — `target` (planned) or `actual` (realised),
40
+ - **unit** — `single` (budget item), `function` (functional area) or `group` (economic group),
41
+ - **id** — drill into one element (a budget number; `G-` prefix for groups, `F-` for functions).
42
+
43
+ The response carries the selected `detail`, its `children` (so you can walk the
44
+ tree by passing a child's `id` back in), `parents`, and `related` cross-references.
45
+
46
+ > **Stability / data coverage.** This client talks to an **undocumented, internal
47
+ > endpoint** of the portal (`/internalapi/budgetData` — note the `internalapi`
48
+ > path). It is **not** a published, stable public API: it can change shape,
49
+ > rate-limit, or disappear **without notice**. The data is served without
50
+ > authentication and currently covers years from `2012` onward (the exact upper
51
+ > range depends on what the portal has published). Treat this dependency as
52
+ > best-effort, especially for any production or commercial use.
53
+
54
+ ### Global options
55
+
56
+ | Option | Description |
57
+ | --- | --- |
58
+ | `--base-url <url>` | API base URL (default `https://bundeshaushalt.de`) |
59
+ | `--timeout <ms>` | Per-request timeout (default `30000`) |
60
+ | `--user-agent <ua>` | `User-Agent` header value |
61
+ | `--max-retries <n>` | Retries for transient `429`/`503` responses (default `2`) |
62
+ | `--max-response-bytes <n>` | Cap response body size in bytes (`0` = unlimited; default 100 MiB) |
63
+ | `--compact` | Print JSON on a single line |
64
+
65
+ Global options may appear **before or after** the command, e.g. both
66
+ `bundeshaushalt --compact expenses 2024` and `bundeshaushalt expenses 2024 --compact`
67
+ work (they are resolved with commander's `optsWithGlobals`).
68
+
69
+ ### Commands
70
+
71
+ ```text
72
+ budget <year> <account> [--quota target|actual] [--unit single|function|group] [--id <id>]
73
+ expenses <year> [--quota] [--unit] [--id] shortcut for: budget <year> expenses
74
+ income <year> [--quota] [--unit] [--id] shortcut for: budget <year> income
75
+ ```
76
+
77
+ (`<year>` is a four-digit year between `2012` and the current year, inclusive;
78
+ the upper bound is derived from the current year so it stays meaningful over time.)
79
+
80
+ ### Examples
81
+
82
+ ```bash
83
+ # Top-level federal expenses for 2024
84
+ bundeshaushalt expenses 2024
85
+
86
+ # Realised income, 2023
87
+ bundeshaushalt income 2023 --quota actual
88
+
89
+ # Expenses grouped by economic group
90
+ bundeshaushalt budget 2024 expenses --unit group
91
+
92
+ # Drill into one budget element by id
93
+ bundeshaushalt budget 2024 expenses --id 090168301
94
+ ```
95
+
96
+ Exit codes: `0` success, `4` on a `404` from the API, `1` for any other error, non-zero for usage errors.
97
+
98
+ ---
99
+
100
+ ## Library usage
101
+
102
+ ```ts
103
+ import { BundeshaushaltClient, HaushaltApiError } from "@maschinenlesbar.org/bundeshaushalt-cli";
104
+
105
+ const client = new BundeshaushaltClient(); // defaults to https://bundeshaushalt.de
106
+
107
+ const top = await client.budgetData({ year: 2024, account: "expenses" });
108
+ console.log(top.meta.year, top.children.length, "children");
109
+
110
+ const drill = await client.budgetData({ year: 2024, account: "expenses", id: "090168301" });
111
+
112
+ try {
113
+ await client.budgetData({ year: 1999, account: "expenses" });
114
+ } catch (err) {
115
+ if (err instanceof HaushaltApiError) console.error(err.status, err.detail);
116
+ }
117
+ ```
118
+
119
+ ### Client options
120
+
121
+ ```ts
122
+ new BundeshaushaltClient({
123
+ baseUrl: "https://bundeshaushalt.de",
124
+ timeoutMs: 15_000,
125
+ maxRetries: 3, // 429 / 503 are retried with linear backoff
126
+ maxResponseBytes: 50 << 20, // abort responses larger than 50 MiB (0 = unlimited)
127
+ userAgent: "my-app/1.0",
128
+ transport: customTransport, // inject your own HTTP transport
129
+ });
130
+ ```
131
+
132
+ ### Methods
133
+
134
+ `client.budgetData({ year, account, quota?, unit?, id? })`. The `AccountValues` /
135
+ `QuotaValues` / `UnitValues` enums are exported for reference.
136
+
137
+ ---
138
+
139
+ ## Architecture
140
+
141
+ ```
142
+ src/
143
+ client/
144
+ enums.ts # Account / Quota / Unit value sets + MIN_YEAR
145
+ types.ts # BudgetData / BudgetElement / BudgetMeta + param object
146
+ query.ts # dependency-free query-string builder
147
+ http.ts # the Transport interface + default node:http/https transport
148
+ engine.ts # URL building, retry/backoff, redirects, JSON decoding, error mapping
149
+ errors.ts # HaushaltError / HaushaltApiError / HaushaltNetworkError / HaushaltParseError
150
+ client.ts # BundeshaushaltClient — the budget-data surface over the engine
151
+ cli/
152
+ io.ts # injectable I/O seam (stdout/stderr/file)
153
+ shared.ts # option parsers, global-option resolver, JSON renderer
154
+ commands/ # budget + expenses/income shortcuts
155
+ program.ts # assembles the commander program from injectable deps
156
+ run.ts # parses argv -> exit code (no process.exit; testable)
157
+ index.ts # #! bin shim
158
+ ```
159
+
160
+ **Design notes**
161
+
162
+ - The HTTP layer is a single `Transport` function (`(req) => Promise<HttpResponse>`). The default
163
+ uses `node:http`/`node:https`; tests inject a mock. This keeps the client free of any HTTP framework.
164
+ - The CLI is built around injectable `CliDeps` (client factory + I/O), so the whole program can be
165
+ driven in-process by tests with a mocked client and captured output — no subprocesses.
166
+ - `account`/`quota`/`unit` are validated against their enums and the year is range-checked before any request.
167
+
168
+ ---
169
+
170
+ ## Testing
171
+
172
+ ```bash
173
+ npm test # builds, then runs `node --test` over dist/test
174
+ ```
175
+
176
+ - **`query.test.ts`** — query-string serialisation.
177
+ - **`http.test.ts`** — the default transport against a real loopback `http.createServer`.
178
+ - **`engine.test.ts`** — URL building, JSON decoding, error mapping, 429/503 retry, redirects — mocked transport.
179
+ - **`client.test.ts`** — the budget-data URL/param mapping and optional-parameter pruning — mocked transport.
180
+ - **`cli.test.ts`** — command parsing, the expenses/income shortcuts, validation and exit codes — mocked client.
181
+
182
+ ## Continuous integration
183
+
184
+ GitHub Actions workflows under `.github/workflows/`:
185
+
186
+ - **ci.yml** — type-check, build and test on Node 20/22/24 for every push and PR.
187
+ - **release.yml** — on a `v*` tag: verify the tag matches `package.json`, test, `npm pack`, and create a GitHub Release with the tarball.
188
+ - **publish.yml** — manual dispatch: publish to npm via OIDC **Trusted Publishing** (no stored `NPM_TOKEN`) with provenance.
189
+ - **docs.yml** — build TypeDoc API docs and deploy to GitHub Pages on each `v*` tag.
190
+
191
+ ## License
192
+
193
+ **Dual-licensed** — use it under **either**:
194
+
195
+ - **[AGPL-3.0-or-later](LICENSE)** (default, free). Note the AGPL's §13 network
196
+ clause: if you run a modified version as a network service, you must offer that
197
+ modified source to the service's users.
198
+ - **Commercial license** (paid), for closed-source / proprietary or SaaS use
199
+ without the AGPL's obligations.
200
+
201
+ See **[LICENSING.md](LICENSING.md)** for details, and **[CONTRIBUTING.md](CONTRIBUTING.md)**
202
+ for the contribution policy (this project does not accept external code
203
+ contributions). Commercial enquiries: **sebs@2xs.org**.
@@ -0,0 +1,4 @@
1
+ import type { Command } from "commander";
2
+ import type { CliDeps } from "../io.js";
3
+ export declare function registerBudgetCommands(program: Command, deps: CliDeps): void;
4
+ //# sourceMappingURL=budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAgFxC,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAiC5E"}
@@ -0,0 +1,86 @@
1
+ import { action, assertEnum, renderJson } from "../shared.js";
2
+ import { HaushaltError } from "../../client/errors.js";
3
+ import { AccountValues, QuotaValues, UnitValues, MIN_YEAR } from "../../client/enums.js";
4
+ /**
5
+ * Upper bound for an accepted year. Derived from the current year (rather than a
6
+ * hard-coded literal) so the validator stays meaningful as years advance.
7
+ *
8
+ * Capped at the current year: the portal only serves data up to (and including)
9
+ * the current budget year. Allowing current year + 1 turned a predictable
10
+ * client-side rejection into a network round-trip that the API answers with 404.
11
+ */
12
+ function maxYear() {
13
+ return new Date().getUTCFullYear();
14
+ }
15
+ /** Parse + range-check a positional year (a four-digit integer in range). */
16
+ function requireYear(value) {
17
+ const ceiling = maxYear();
18
+ // Validate the raw four-digit shape before coercing, so loose inputs like
19
+ // "2024.0" or " 2024 " are rejected rather than silently normalised.
20
+ if (!/^\d{4}$/.test(value)) {
21
+ throw new HaushaltError(`Invalid year "${value}". Expected a four-digit year between ${MIN_YEAR} and ${ceiling}.`);
22
+ }
23
+ const n = Number(value);
24
+ if (n < MIN_YEAR || n > ceiling) {
25
+ throw new HaushaltError(`Invalid year "${value}". Expected a four-digit year between ${MIN_YEAR} and ${ceiling}.`);
26
+ }
27
+ return n;
28
+ }
29
+ /** Build the optional quota/unit/id params shared by all budget commands. */
30
+ function optionsFrom(opts) {
31
+ const params = {};
32
+ if (opts["quota"] !== undefined) {
33
+ params.quota = assertEnum(String(opts["quota"]), QuotaValues, "quota");
34
+ }
35
+ if (opts["unit"] !== undefined) {
36
+ params.unit = assertEnum(String(opts["unit"]), UnitValues, "unit");
37
+ }
38
+ if (opts["id"] !== undefined) {
39
+ const raw = String(opts["id"]);
40
+ // A value that looks like an option flag (e.g. `--id --quota`) is almost
41
+ // certainly a missing-value mistake: commander otherwise swallows the next
42
+ // flag as the id and sends `id=--quota` to the API. Reject it locally.
43
+ if (raw.startsWith("-")) {
44
+ throw new HaushaltError(`Invalid id "${raw}". The --id value looks like an option; did you forget to supply an id?`);
45
+ }
46
+ const id = raw.trim();
47
+ // Reject empty/whitespace ids so bad input fails locally with a clear
48
+ // message instead of producing an opaque API error (or `id=` in the query).
49
+ if (id.length === 0) {
50
+ throw new HaushaltError(`Invalid id "". Expected a non-empty budget number.`);
51
+ }
52
+ // Reject surrounding whitespace rather than silently trimming it: silent
53
+ // mutation can mask copy-paste errors and collapse two distinct inputs.
54
+ if (id !== raw) {
55
+ throw new HaushaltError(`Invalid id "${raw}". Surrounding whitespace is not allowed.`);
56
+ }
57
+ params.id = id;
58
+ }
59
+ return params;
60
+ }
61
+ function addBudgetOptions(cmd) {
62
+ return cmd
63
+ .option("--quota <quota>", `target | actual (default target)`)
64
+ .option("--unit <unit>", `single | function | group (default single)`)
65
+ .option("--id <id>", 'budget number id ("G-" prefix for groups, "F-" for functions)');
66
+ }
67
+ export function registerBudgetCommands(program, deps) {
68
+ addBudgetOptions(program
69
+ .command("budget <year> <account>")
70
+ .description(`Federal budget data (account: ${AccountValues.join(" | ")})`)).action(action(deps, async ({ client, global, opts }, [year, account]) => {
71
+ renderJson(deps, global, await client.budgetData({
72
+ year: requireYear(year),
73
+ account: assertEnum(account, AccountValues, "account"),
74
+ ...optionsFrom(opts),
75
+ }));
76
+ }));
77
+ // Convenience shortcuts that preset the account.
78
+ const shortcut = (name, account, desc) => {
79
+ addBudgetOptions(program.command(`${name} <year>`).description(desc)).action(action(deps, async ({ client, global, opts }, [year]) => {
80
+ renderJson(deps, global, await client.budgetData({ year: requireYear(year), account, ...optionsFrom(opts) }));
81
+ }));
82
+ };
83
+ shortcut("expenses", "expenses", "Federal expenses for a year (shortcut)");
84
+ shortcut("income", "income", "Federal income for a year (shortcut)");
85
+ }
86
+ //# sourceMappingURL=budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"budget.js","sourceRoot":"","sources":["../../../../src/cli/commands/budget.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,6 @@
1
+ #!/usr/bin/env node
2
+ // Binary entry point. Thin shim around run(); all logic lives in run.ts/program.ts.
3
+ import { run } from "./run.js";
4
+ const exitCode = await run(process.argv.slice(2));
5
+ process.exitCode = exitCode;
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":";AACA,oFAAoF;AAEpF,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAE/B,MAAM,QAAQ,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAClD,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { BundeshaushaltClient } from "../client/client.js";
2
+ import type { EngineOptions } from "../client/engine.js";
3
+ export interface CliIO {
4
+ out(text: string): void;
5
+ err(text: string): void;
6
+ }
7
+ export interface CliDeps {
8
+ io: CliIO;
9
+ /** Build a client from the resolved global options (injectable for tests). */
10
+ createClient(options: EngineOptions): BundeshaushaltClient;
11
+ }
12
+ export declare const defaultIO: CliIO;
13
+ //# 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,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD,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,aAAa,GAAG,oBAAoB,CAAC;CAC5D;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;AAgBtE,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/filesystem. */
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;AA4BvC,eAAO,MAAM,OAAO,QAAgB,CAAC;AAErC,yEAAyE;AACzE,eAAO,MAAM,WAAW,EAAE,OAGzB,CAAC;AAEF,wBAAgB,YAAY,CAAC,IAAI,GAAE,OAAqB,GAAG,OAAO,CA2BjE"}
@@ -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 { BundeshaushaltClient } from "../client/client.js";
9
+ import { parseIntArg, parseBoundedIntArg } from "./shared.js";
10
+ import { registerBudgetCommands } from "./commands/budget.js";
11
+ /**
12
+ * Sane upper bound for `--max-retries`. A larger value would let a transient
13
+ * 429/503 spin the retry loop (with growing backoff) for effectively forever.
14
+ */
15
+ const MAX_RETRIES_LIMIT = 100;
16
+ /**
17
+ * Single source of truth for the version: read from package.json at runtime
18
+ * rather than duplicating a literal that can silently drift after a release bump.
19
+ * From the compiled location (dist/src/cli/program.js) package.json is three
20
+ * directories up; the same offset holds for the source under src/cli.
21
+ */
22
+ function readVersion() {
23
+ try {
24
+ const pkgUrl = new URL("../../../package.json", import.meta.url);
25
+ const pkg = JSON.parse(readFileSync(fileURLToPath(pkgUrl), "utf8"));
26
+ return pkg.version ?? "0.0.0";
27
+ }
28
+ catch {
29
+ return "0.0.0";
30
+ }
31
+ }
32
+ export const VERSION = readVersion();
33
+ /** Default dependencies: real client + real stdout/stderr/filesystem. */
34
+ export const defaultDeps = {
35
+ io: defaultIO,
36
+ createClient: (options) => new BundeshaushaltClient(options),
37
+ };
38
+ export function buildProgram(deps = defaultDeps) {
39
+ const program = new Command();
40
+ program
41
+ .name("bundeshaushalt")
42
+ .description("CLI for the open German federal budget API (https://bundeshaushalt.de)")
43
+ .version(VERSION)
44
+ .option("--base-url <url>", "API base URL", "https://bundeshaushalt.de")
45
+ .option("--timeout <ms>", "per-request timeout in milliseconds", parseIntArg, 30_000)
46
+ .option("--user-agent <ua>", "User-Agent header value")
47
+ .option("--max-retries <n>", "retries for transient 429/503 responses", parseBoundedIntArg(MAX_RETRIES_LIMIT), 2)
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
+ registerBudgetCommands(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,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAE9D;;;GAGG;AACH,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAE9B;;;;;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,yEAAyE;AACzE,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,EAAE,EAAE,SAAS;IACb,YAAY,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,IAAI,oBAAoB,CAAC,OAAO,CAAC;CAC7D,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB,WAAW;IACtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,gBAAgB,CAAC;SACtB,WAAW,CAAC,wEAAwE,CAAC;SACrF,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,2BAA2B,CAAC;SACvE,MAAM,CAAC,gBAAgB,EAAE,qCAAqC,EAAE,WAAW,EAAE,MAAM,CAAC;SACpF,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;SACtD,MAAM,CACL,mBAAmB,EACnB,yCAAyC,EACzC,kBAAkB,CAAC,iBAAiB,CAAC,EACrC,CAAC,CACF;SACA,MAAM,CACL,0BAA0B,EAC1B,kEAAkE,EAClE,WAAW,CACZ;SACA,MAAM,CAAC,WAAW,EAAE,uDAAuD,CAAC;SAC5E,kBAAkB,EAAE,CAAC;IAExB,sBAAsB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEtC,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;AAiBvC,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,OAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBtF"}
@@ -0,0 +1,48 @@
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 { HaushaltApiError, HaushaltError } from "../client/errors.js";
7
+ /**
8
+ * Apply exitOverride + output redirection to every command in the tree.
9
+ * commander does not propagate these to subcommands, so a parse error on a
10
+ * subcommand would otherwise call process.exit() and bypass our error handling.
11
+ */
12
+ function configureTree(command, deps) {
13
+ command.exitOverride();
14
+ command.configureOutput({
15
+ writeOut: (str) => deps.io.out(str.replace(/\n$/, "")),
16
+ writeErr: (str) => deps.io.err(str.replace(/\n$/, "")),
17
+ });
18
+ for (const child of command.commands)
19
+ configureTree(child, deps);
20
+ }
21
+ export async function run(argv, deps = defaultDeps) {
22
+ const program = buildProgram(deps);
23
+ configureTree(program, deps);
24
+ try {
25
+ await program.parseAsync(argv, { from: "user" });
26
+ return 0;
27
+ }
28
+ catch (err) {
29
+ if (err instanceof CommanderError) {
30
+ // Help/version requests exit 0; genuine parse errors carry their own code.
31
+ return err.exitCode;
32
+ }
33
+ if (err instanceof HaushaltApiError) {
34
+ deps.io.err(`Error: ${err.message}`);
35
+ // Map a few notable statuses to distinct exit codes for scripting.
36
+ if (err.status === 404)
37
+ return 4;
38
+ return 1;
39
+ }
40
+ if (err instanceof HaushaltError) {
41
+ deps.io.err(`Error: ${err.message}`);
42
+ return 1;
43
+ }
44
+ deps.io.err(`Unexpected error: ${err instanceof Error ? err.message : String(err)}`);
45
+ return 1;
46
+ }
47
+ }
48
+ //# sourceMappingURL=run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,6EAA6E;AAC7E,+DAA+D;AAE/D,OAAO,EAAE,cAAc,EAAgB,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;;GAIG;AACH,SAAS,aAAa,CAAC,OAAgB,EAAE,IAAa;IACpD,OAAO,CAAC,YAAY,EAAE,CAAC;IACvB,OAAO,CAAC,eAAe,CAAC;QACtB,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACtD,QAAQ,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;KACvD,CAAC,CAAC;IACH,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,QAAQ;QAAE,aAAa,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc,EAAE,OAAgB,WAAW;IACnE,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IACnC,aAAa,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE7B,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACjD,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;YAClC,2EAA2E;YAC3E,OAAO,GAAG,CAAC,QAAQ,CAAC;QACtB,CAAC;QACD,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;YACpC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,mEAAmE;YACnE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;gBAAE,OAAO,CAAC,CAAC;YACjC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,GAAG,YAAY,aAAa,EAAE,CAAC;YACjC,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACrC,OAAO,CAAC,CAAC;QACX,CAAC;QACD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,qBAAqB,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrF,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
@@ -0,0 +1,51 @@
1
+ import type { CliDeps } from "./io.js";
2
+ import type { EngineOptions } from "../client/engine.js";
3
+ /**
4
+ * commander value-parser: a non-negative integer in plain decimal notation.
5
+ *
6
+ * Deliberately strict: only `/^\d+$/` is accepted. `Number()` would otherwise
7
+ * coerce empty strings (→0, which silently disables size/retry caps), hex/octal/
8
+ * binary (`0x10`→16), scientific (`1e9`), a leading `+`, and surrounding
9
+ * whitespace — none of which a user typing a "non-negative integer" intends.
10
+ */
11
+ export declare function parseIntArg(value: string): number;
12
+ /**
13
+ * commander value-parser: a non-negative integer with an inclusive upper bound.
14
+ * Used for options like `--max-retries` where an absurdly large value would turn
15
+ * a transient-error retry loop into an effective hang (DoS).
16
+ */
17
+ export declare function parseBoundedIntArg(max: number): (value: string) => number;
18
+ /**
19
+ * Validate a positional argument against an allowed set (commander does not
20
+ * support .choices() on positional args). Throws a HaushaltError so run() prints a
21
+ * clear message and exits 1.
22
+ */
23
+ export declare function assertEnum<T extends string>(value: string, allowed: readonly T[], argName: string): T;
24
+ export interface GlobalOptions {
25
+ baseUrl?: string;
26
+ timeout?: number;
27
+ userAgent?: string;
28
+ maxRetries?: number;
29
+ maxResponseBytes?: number;
30
+ compact?: boolean;
31
+ }
32
+ /** Translate resolved global CLI options into client EngineOptions. */
33
+ export declare function toEngineOptions(global: GlobalOptions): EngineOptions;
34
+ /** Render a JSON value to stdout, pretty by default, compact with --compact. */
35
+ export declare function renderJson(deps: CliDeps, global: GlobalOptions, value: unknown): void;
36
+ export interface ActionContext {
37
+ client: ReturnType<CliDeps["createClient"]>;
38
+ global: GlobalOptions;
39
+ /** This command's own parsed options. */
40
+ opts: Record<string, unknown>;
41
+ }
42
+ /**
43
+ * Wrap an async command action with consistent global-option resolution and
44
+ * client construction. The callback receives a context (client + resolved global
45
+ * options + this command's options) and the command's positional arguments.
46
+ *
47
+ * Commander invokes actions as (arg1, ..., argN, options, command); we slice off
48
+ * the trailing options object and command instance to recover the positionals.
49
+ */
50
+ export declare function action(deps: CliDeps, fn: (ctx: ActionContext, positionals: string[]) => Promise<void>): (...args: unknown[]) => Promise<void>;
51
+ //# 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;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEzD;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAQzE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,CAAC,SAAS,MAAM,EACzC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,SAAS,CAAC,EAAE,EACrB,OAAO,EAAE,MAAM,GACd,CAAC,CAKH;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,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,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAQpE;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"}