@maschinenlesbar.org/nina-warnungen-cli 0.0.2 → 0.0.3
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.
- package/README.md +146 -161
- package/dist/src/cli/program.js +3 -3
- package/dist/src/cli/program.js.map +1 -1
- package/dist/src/cli/run.d.ts.map +1 -1
- package/dist/src/cli/run.js +34 -15
- package/dist/src/cli/run.js.map +1 -1
- package/dist/src/cli/shared.d.ts +17 -4
- package/dist/src/cli/shared.d.ts.map +1 -1
- package/dist/src/cli/shared.js +26 -4
- package/dist/src/cli/shared.js.map +1 -1
- package/dist/src/client/engine.d.ts.map +1 -1
- package/dist/src/client/engine.js +48 -2
- package/dist/src/client/engine.js.map +1 -1
- package/dist/src/client/http.d.ts.map +1 -1
- package/dist/src/client/http.js +28 -3
- package/dist/src/client/http.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,216 +1,201 @@
|
|
|
1
1
|
# nina-warnungen-cli
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
[](https://github.com/maschinenlesbar-org/nina-warnungen-cli/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/maschinenlesbar-org/nina-warnungen-cli/actions/workflows/release.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/@maschinenlesbar.org/nina-warnungen-cli)
|
|
6
|
+
|
|
7
|
+
Query Germany's **federal civil-protection warning system** from your terminal.
|
|
8
|
+
`nina` is a command-line tool over the open
|
|
9
|
+
[NINA API](https://nina.api.bund.dev/) (`warnung.bund.de`): fetch current
|
|
10
|
+
warnings by source, look up the full detail or geometry of any alert, check a
|
|
11
|
+
region by its official key, and browse the MoWaS archive — as clean JSON you
|
|
12
|
+
can pipe straight into [`jq`](https://jqlang.github.io/jq/).
|
|
13
|
+
|
|
14
|
+
- **Works out of the box** — no account, no API key, no configuration. Install and query.
|
|
15
|
+
- **All sources in one tool** — MoWaS, KATWARN, BIWAPP, DWD severe-weather, flood (LHP) and police.
|
|
16
|
+
- **Clean JSON output** — pretty-printed by default, `--compact` for one-line/scripting.
|
|
17
|
+
- **GeoJSON support** — download a warning's affected-area geometry directly to a file.
|
|
18
|
+
- **Cheap polling** — a lightweight data-version endpoint tells you whether anything changed without pulling full feeds.
|
|
19
|
+
|
|
20
|
+
> Want to use this as a TypeScript library or understand how it's built?
|
|
21
|
+
> See **[DEVELOPING.md](DEVELOPING.md)**.
|
|
22
22
|
|
|
23
23
|
## Install
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
npm
|
|
27
|
-
npm run build # compiles TypeScript to dist/
|
|
26
|
+
npm i -g @maschinenlesbar.org/nina-warnungen-cli
|
|
28
27
|
```
|
|
29
28
|
|
|
30
|
-
|
|
29
|
+
This installs the **`nina`** command. Requires **Node.js 20+**.
|
|
30
|
+
|
|
31
|
+
Check it works:
|
|
31
32
|
|
|
32
33
|
```bash
|
|
33
|
-
node dist/src/cli/index.js --help
|
|
34
|
-
# or, after `npm link` / global install:
|
|
35
34
|
nina --help
|
|
36
35
|
```
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
## CLI usage
|
|
37
|
+
## Quickstart
|
|
41
38
|
|
|
42
|
-
|
|
43
|
-
GeoJSON bytes to stdout or to a file via `-o/--output`. The body is buffered in
|
|
44
|
-
memory (bounded by `--max-response-bytes`), not streamed. As a sanity check, if the
|
|
45
|
-
server returns a body whose `Content-Type` does not contain `json` (e.g. a
|
|
46
|
-
`text/html` gateway error page served with a `200` status), the CLI prints a
|
|
47
|
-
warning to stderr before writing it. This is a `Content-Type`-only check — the live
|
|
48
|
-
API serves GeoJSON as `application/json`, so it does not (and cannot) verify that
|
|
49
|
-
the bytes are actually valid GeoJSON, only that the type string looks JSON-ish.
|
|
39
|
+
No setup needed — the API is open and read-only. Your first query:
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
| --- | --- |
|
|
55
|
-
| `--base-url <url>` | API base URL (default `https://warnung.bund.de`) |
|
|
56
|
-
| `--timeout <ms>` | Per-request timeout (default `30000`; `0` disables the timeout — waits indefinitely) |
|
|
57
|
-
| `--user-agent <ua>` | `User-Agent` header value |
|
|
58
|
-
| `--max-retries <n>` | Retries for transient `429`/`503` responses (default `2`, capped at `10`) |
|
|
59
|
-
| `--max-response-bytes <n>` | Cap response body size in bytes (`0` = unlimited; default 100 MiB) |
|
|
60
|
-
| `--compact` | Print JSON on a single line |
|
|
61
|
-
| `-o, --output <file>` | For downloads: write bytes to a file instead of stdout |
|
|
41
|
+
```bash
|
|
42
|
+
nina map-data dwd
|
|
43
|
+
```
|
|
62
44
|
|
|
63
|
-
|
|
64
|
-
|
|
45
|
+
Returns the current severe-weather warnings from the DWD (Deutscher
|
|
46
|
+
Wetterdienst). Pull out just the headlines and severity levels with `jq`:
|
|
65
47
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
48
|
+
```bash
|
|
49
|
+
nina map-data dwd | jq '.[] | {id, severity: .severity, headline: .i18nTitle.de}'
|
|
50
|
+
```
|
|
69
51
|
|
|
70
|
-
|
|
71
|
-
plain non-negative decimal integers; values like `5.0`, `0x10`, `1e3`, `-1` or a
|
|
72
|
-
leading/trailing space are rejected as usage errors.
|
|
52
|
+
Take a warning `id` from those results and fetch its full CAP record:
|
|
73
53
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
> (`file:`/`ftp:` are rejected) and redirects are **never followed**, but point it
|
|
78
|
-
> only at hosts you trust. Setting `--max-response-bytes 0` disables the in-memory
|
|
79
|
-
> response-size guard entirely (including the 100 MiB default).
|
|
54
|
+
```bash
|
|
55
|
+
nina warning get mow.DE-BY-A-W083-20240101
|
|
56
|
+
```
|
|
80
57
|
|
|
81
|
-
|
|
58
|
+
## Commands
|
|
82
59
|
|
|
83
60
|
```text
|
|
84
|
-
sources
|
|
85
|
-
map-data <source>
|
|
86
|
-
|
|
87
|
-
warning
|
|
88
|
-
warning
|
|
89
|
-
dashboard <ars>
|
|
90
|
-
archive
|
|
91
|
-
|
|
61
|
+
sources list the valid warning sources
|
|
62
|
+
map-data <source> current warnings from a source
|
|
63
|
+
(mowas | katwarn | biwapp | dwd | lhp | police)
|
|
64
|
+
warning get <id> full CAP warning by identifier
|
|
65
|
+
warning geojson <id> warning geometry as GeoJSON (-o to save)
|
|
66
|
+
dashboard <ars> warnings for a region (ARS/AGS key)
|
|
67
|
+
archive mapping <id> MoWaS revision history for an identifier
|
|
68
|
+
archive get <id> a specific archived MoWaS warning
|
|
69
|
+
reference notfalltipps emergency-preparedness tips (German)
|
|
70
|
+
reference event-codes CAP event-code catalogue
|
|
71
|
+
reference data-version current data-version hash (for polling)
|
|
92
72
|
```
|
|
93
73
|
|
|
94
|
-
###
|
|
74
|
+
### `map-data` sources
|
|
95
75
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
76
|
+
| Value | Warning type |
|
|
77
|
+
| --- | --- |
|
|
78
|
+
| `mowas` | MoWaS — modular civil-protection alerts |
|
|
79
|
+
| `katwarn` | KATWARN — municipal/regional alerts |
|
|
80
|
+
| `biwapp` | BIWAPP — municipal alerts |
|
|
81
|
+
| `dwd` | DWD — severe-weather (national met service) |
|
|
82
|
+
| `lhp` | LHP — cross-state flood warnings |
|
|
83
|
+
| `police` | Police incident reports |
|
|
99
84
|
|
|
100
|
-
|
|
101
|
-
nina warning get mow.DE-BY-A-W083-20240101
|
|
85
|
+
The canonical list is always available at runtime via `nina sources`.
|
|
102
86
|
|
|
103
|
-
|
|
104
|
-
nina -o warn.geojson warning geojson mow.DE-BY-A-W083-20240101
|
|
87
|
+
## Common tasks
|
|
105
88
|
|
|
106
|
-
|
|
107
|
-
|
|
89
|
+
A few recipes to get going — see **[Usage.md](Usage.md)** for the full,
|
|
90
|
+
use-case-driven set.
|
|
108
91
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
92
|
+
```bash
|
|
93
|
+
# Current flood warnings
|
|
94
|
+
nina map-data lhp
|
|
112
95
|
|
|
113
|
-
|
|
96
|
+
# Filter to only Severe or Extreme warnings across a source
|
|
97
|
+
nina map-data mowas | jq '[.[] | select(.severity == "Severe" or .severity == "Extreme")]'
|
|
114
98
|
|
|
115
|
-
|
|
99
|
+
# Full detail for one warning (id from a map-data entry)
|
|
100
|
+
nina warning get mow.DE-SL-SLS-W038-20260113-000
|
|
116
101
|
|
|
117
|
-
|
|
102
|
+
# Save the affected-area geometry as a GeoJSON file
|
|
103
|
+
nina warning geojson mow.DE-SL-SLS-W038-20260113-000 -o warn.geojson
|
|
118
104
|
|
|
119
|
-
|
|
120
|
-
|
|
105
|
+
# All warnings currently affecting a district (regional key ARS/AGS)
|
|
106
|
+
nina dashboard 055150000000
|
|
121
107
|
|
|
122
|
-
|
|
108
|
+
# Cheap polling — only fetch full feeds when the version hash changes
|
|
109
|
+
nina --compact reference data-version
|
|
110
|
+
```
|
|
123
111
|
|
|
124
|
-
|
|
125
|
-
const full = await client.warnings.get(alerts[0]!.id);
|
|
126
|
-
const region = await client.dashboard("055150000000");
|
|
112
|
+
## Output & scripting
|
|
127
113
|
|
|
128
|
-
|
|
129
|
-
|
|
114
|
+
Every command prints **pretty JSON to stdout**. Errors and diagnostics go to
|
|
115
|
+
stderr, so piping stdout into `jq` stays clean.
|
|
130
116
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (err instanceof NinaApiError) console.error(err.status, err.detail);
|
|
135
|
-
}
|
|
136
|
-
```
|
|
117
|
+
```bash
|
|
118
|
+
# Count warnings for a region
|
|
119
|
+
nina dashboard 055150000000 | jq 'length'
|
|
137
120
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
new NinaClient({
|
|
142
|
-
baseUrl: "https://warnung.bund.de",
|
|
143
|
-
timeoutMs: 15_000,
|
|
144
|
-
maxRetries: 3, // 429 / 503 are retried with linear backoff
|
|
145
|
-
maxResponseBytes: 50 << 20, // abort responses larger than 50 MiB (0 = unlimited)
|
|
146
|
-
userAgent: "my-app/1.0",
|
|
147
|
-
transport: customTransport, // inject your own HTTP transport
|
|
148
|
-
});
|
|
121
|
+
# Extract severity + headline from all DWD entries
|
|
122
|
+
nina map-data dwd | jq '.[] | {severity, title: .i18nTitle.de}'
|
|
149
123
|
```
|
|
150
124
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
`client.mapData(source)`, `client.dashboard(ars)`, `client.warnings` (`.get` / `.geojson`),
|
|
154
|
-
`client.archive` (`.mapping` / `.get`), `client.reference` (`.notfalltipps` / `.eventCodes` / `.dataVersion`).
|
|
125
|
+
Use `--compact` for single-line JSON in pipelines and logs:
|
|
155
126
|
|
|
156
|
-
|
|
127
|
+
```bash
|
|
128
|
+
nina --compact map-data dwd | jq -c '.[]'
|
|
129
|
+
```
|
|
157
130
|
|
|
158
|
-
|
|
131
|
+
`--compact` (and every global option) works **before or after** the command —
|
|
132
|
+
both `nina --compact map-data dwd` and `nina map-data dwd --compact` do the same
|
|
133
|
+
thing.
|
|
159
134
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
client/
|
|
163
|
-
enums.ts # NinaSource + severity value sets (runtime + type)
|
|
164
|
-
types.ts # response interfaces (typed summaries; full warnings as JsonObject)
|
|
165
|
-
query.ts # dependency-free query-string builder
|
|
166
|
-
http.ts # the Transport interface + default node:http/https transport
|
|
167
|
-
engine.ts # URL building, retry/backoff, JSON/raw decoding, error mapping
|
|
168
|
-
errors.ts # NinaError / NinaApiError / NinaNetworkError / NinaParseError
|
|
169
|
-
client.ts # NinaClient — resource groups over the engine
|
|
170
|
-
cli/
|
|
171
|
-
io.ts # injectable I/O seam (stdout/stderr/file)
|
|
172
|
-
shared.ts # option parsers, global-option resolver, JSON/raw renderers
|
|
173
|
-
commands/ # warnings + archive/reference (misc) command groups
|
|
174
|
-
program.ts # assembles the commander program from injectable deps
|
|
175
|
-
run.ts # parses argv -> exit code (no process.exit; testable)
|
|
176
|
-
index.ts # #! bin shim
|
|
177
|
-
```
|
|
135
|
+
An identifier that begins with `-` would be parsed as an option; pass it after a
|
|
136
|
+
`--` separator: `nina warning get -- -odd.identifier`.
|
|
178
137
|
|
|
179
|
-
**
|
|
138
|
+
**Exit codes** make the CLI easy to use in scripts:
|
|
180
139
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
140
|
+
| Code | Meaning |
|
|
141
|
+
| --- | --- |
|
|
142
|
+
| `0` | success (also `--help` / `--version`) |
|
|
143
|
+
| `1` | error — network failure, parse error, unexpected problem |
|
|
144
|
+
| `4` | warning not found (`404`) |
|
|
145
|
+
| non-zero | bad usage / invalid argument (commander parse error) |
|
|
146
|
+
|
|
147
|
+
## Troubleshooting
|
|
148
|
+
|
|
149
|
+
- **`command not found: nina`** — the global npm bin directory isn't on your
|
|
150
|
+
`PATH`. Run `npm bin -g` to find it and add it, or run via
|
|
151
|
+
`npx @maschinenlesbar.org/nina-warnungen-cli …`.
|
|
152
|
+
- **Exit `4` / "not found"** — the warning identifier doesn't exist or has
|
|
153
|
+
expired. Re-fetch it from a fresh `map-data` or `dashboard` result; identifiers
|
|
154
|
+
change as warnings are issued and cancelled.
|
|
155
|
+
- **Exit `1` / network error** — connectivity, DNS, or a timeout. Try again, or
|
|
156
|
+
raise the limit with `--timeout 60000`. For flaky networks increase retries:
|
|
157
|
+
`--max-retries 5`.
|
|
158
|
+
- **Empty result from `map-data`** — the source has no active warnings right now.
|
|
159
|
+
Try a different source or come back later.
|
|
160
|
+
- **`warning geojson` prints non-JSON content-type warning** — the API returned
|
|
161
|
+
an unexpected content-type (e.g. a gateway error page). The bytes are still
|
|
162
|
+
written, but check whether the identifier is valid.
|
|
163
|
+
|
|
164
|
+
## Global options
|
|
165
|
+
|
|
166
|
+
These apply to every command and may be given before *or* after it:
|
|
190
167
|
|
|
191
|
-
|
|
168
|
+
| Option | Description |
|
|
169
|
+
| --- | --- |
|
|
170
|
+
| `-V, --version` | Print the version number |
|
|
171
|
+
| `-h, --help` | Show help for the program or a command |
|
|
172
|
+
| `--compact` | Print JSON on a single line instead of pretty-printed |
|
|
173
|
+
| `-o, --output <file>` | Write the command's output to a file instead of stdout (JSON commands and downloads alike) |
|
|
174
|
+
| `--base-url <url>` | API base URL (default `https://warnung.bund.de`) |
|
|
175
|
+
| `--timeout <ms>` | Per-request timeout (default `30000`; `0` waits indefinitely) |
|
|
176
|
+
| `--user-agent <ua>` | `User-Agent` header value |
|
|
177
|
+
| `--max-retries <n>` | Retries for transient `429`/`503` responses (default `2`, max `10` — higher is rejected) |
|
|
178
|
+
| `--max-response-bytes <n>` | Cap response body size in bytes (`0` = unlimited; default 100 MiB) |
|
|
192
179
|
|
|
193
|
-
|
|
180
|
+
Numeric options accept only plain non-negative decimal integers — values like
|
|
181
|
+
`5.0`, `0x10`, `1e3`, or `-1` are rejected as usage errors.
|
|
194
182
|
|
|
195
|
-
|
|
196
|
-
npm test # builds, then runs `node --test` over dist/test
|
|
197
|
-
```
|
|
183
|
+
## Learn more
|
|
198
184
|
|
|
199
|
-
-
|
|
200
|
-
-
|
|
201
|
-
-
|
|
202
|
-
-
|
|
203
|
-
- **`cli.test.ts`** — end-to-end command parsing, rendering, file output and exit codes, plus negative paths (network/parse/API errors, write failures, content-type warning) — mocked client.
|
|
204
|
-
- **`shared.test.ts`** — the `parseIntArg` value parser (accepts plain decimals, rejects everything else).
|
|
185
|
+
- **[SKILLS.md](SKILLS.md)** — Claude Code Agent Skills that drive this CLI for live warning briefings, region watches and GeoJSON maps.
|
|
186
|
+
- **[Usage.md](Usage.md)** — full use-case-driven cookbook.
|
|
187
|
+
- **[GLOSSARY.md](GLOSSARY.md)** — every command, source, domain term and exit code explained.
|
|
188
|
+
- **[DEVELOPING.md](DEVELOPING.md)** — TypeScript library usage, architecture, testing, CI.
|
|
205
189
|
|
|
206
|
-
##
|
|
190
|
+
## Data license
|
|
207
191
|
|
|
208
|
-
|
|
192
|
+
This CLI is a **client** — it accesses data it does not own or redistribute. The
|
|
193
|
+
upstream data is © its provider and licensed **separately from this tool's code**.
|
|
194
|
+
See **[DATA_LICENSE.md](DATA_LICENSE.md)**.
|
|
209
195
|
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
- **docs.yml** — build TypeDoc API docs and deploy to GitHub Pages on each `v*` tag.
|
|
196
|
+
> **BBK** — official federal warnings are amtliche Werke (§ 5 Abs. 2 UrhG): may be
|
|
197
|
+
> redistributed **unaltered** with a source credit. Aggregates third-party sources
|
|
198
|
+
> (DWD, Länder flood portals) that carry their own terms.
|
|
214
199
|
|
|
215
200
|
## License
|
|
216
201
|
|
package/dist/src/cli/program.js
CHANGED
|
@@ -6,7 +6,7 @@ import { fileURLToPath } from "node:url";
|
|
|
6
6
|
import { Command } from "commander";
|
|
7
7
|
import { defaultIO } from "./io.js";
|
|
8
8
|
import { NinaClient } from "../client/client.js";
|
|
9
|
-
import { parseIntArg } from "./shared.js";
|
|
9
|
+
import { parseIntArg, parseMaxRetries } from "./shared.js";
|
|
10
10
|
import { registerWarningCommands } from "./commands/warnings.js";
|
|
11
11
|
import { registerMiscCommands } from "./commands/misc.js";
|
|
12
12
|
/**
|
|
@@ -41,10 +41,10 @@ export function buildProgram(deps = defaultDeps) {
|
|
|
41
41
|
.option("--base-url <url>", "API base URL", "https://warnung.bund.de")
|
|
42
42
|
.option("--timeout <ms>", "per-request timeout in milliseconds (0 disables; waits indefinitely)", parseIntArg)
|
|
43
43
|
.option("--user-agent <ua>", "User-Agent header value")
|
|
44
|
-
.option("--max-retries <n>", "retries for transient 429/503 responses (
|
|
44
|
+
.option("--max-retries <n>", "retries for transient 429/503 responses (default 2, max 10)", parseMaxRetries)
|
|
45
45
|
.option("--max-response-bytes <n>", "cap response body size in bytes (0 = unlimited; default 100 MiB)", parseIntArg)
|
|
46
46
|
.option("--compact", "print JSON on a single line instead of pretty-printed")
|
|
47
|
-
.option("-o, --output <file>", "
|
|
47
|
+
.option("-o, --output <file>", "write the command's output to this file instead of stdout")
|
|
48
48
|
.showHelpAfterError();
|
|
49
49
|
registerWarningCommands(program, deps);
|
|
50
50
|
registerMiscCommands(program, deps);
|
|
@@ -1 +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,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;
|
|
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,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAE1D;;;;;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,UAAU,CAAC,OAAO,CAAC;CACnD,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB,WAAW;IACtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,MAAM,CAAC;SACZ,WAAW,CACV,iFAAiF;QAC/E,4EAA4E,CAC/E;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,yBAAyB,CAAC;SACrE,MAAM,CACL,gBAAgB,EAChB,sEAAsE,EACtE,WAAW,CACZ;SACA,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;SACtD,MAAM,CACL,mBAAmB,EACnB,6DAA6D,EAC7D,eAAe,CAChB;SACA,MAAM,CACL,0BAA0B,EAC1B,kEAAkE,EAClE,WAAW,CACZ;SACA,MAAM,CAAC,WAAW,EAAE,uDAAuD,CAAC;SAC5E,MAAM,CAAC,qBAAqB,EAAE,2DAA2D,CAAC;SAC1F,kBAAkB,EAAE,CAAC;IAExB,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvC,oBAAoB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAEpC,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
|
@@ -1 +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;
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AA2BvC,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,OAAqB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+CtF"}
|
package/dist/src/cli/run.js
CHANGED
|
@@ -8,36 +8,55 @@ import { NinaApiError, NinaError } from "../client/errors.js";
|
|
|
8
8
|
* Apply exitOverride + output redirection to every command in the tree.
|
|
9
9
|
* commander does not propagate these to subcommands, so a parse error on a
|
|
10
10
|
* subcommand would otherwise call process.exit() and bypass our error handling.
|
|
11
|
+
*
|
|
12
|
+
* Commander's own output (help, version, parse-error text) is buffered into
|
|
13
|
+
* `sink` so run() can route it *after* it knows the outcome: a help display goes
|
|
14
|
+
* to stdout (matching `--help`), genuine errors to stderr. Action output is
|
|
15
|
+
* written through deps.io directly and never passes through here.
|
|
11
16
|
*/
|
|
12
|
-
function configureTree(command,
|
|
17
|
+
function configureTree(command, sink) {
|
|
13
18
|
command.exitOverride();
|
|
14
19
|
command.configureOutput({
|
|
15
|
-
writeOut: (str) =>
|
|
16
|
-
writeErr: (str) =>
|
|
20
|
+
writeOut: (str) => sink.out.push(str.replace(/\n$/, "")),
|
|
21
|
+
writeErr: (str) => sink.err.push(str.replace(/\n$/, "")),
|
|
17
22
|
});
|
|
18
23
|
for (const child of command.commands)
|
|
19
|
-
configureTree(child,
|
|
24
|
+
configureTree(child, sink);
|
|
20
25
|
}
|
|
21
26
|
export async function run(argv, deps = defaultDeps) {
|
|
22
27
|
const program = buildProgram(deps);
|
|
23
|
-
|
|
28
|
+
const sink = { out: [], err: [] };
|
|
29
|
+
configureTree(program, sink);
|
|
30
|
+
// Flush commander's buffered output. `helpToStdout` routes the buffered
|
|
31
|
+
// writeErr lines to stdout: commander emits no-command help (a bare invocation
|
|
32
|
+
// or a bare command group) via writeErr, and we want that to match an explicit
|
|
33
|
+
// `--help` (stdout, exit 0) rather than landing on stderr.
|
|
34
|
+
const flush = (helpToStdout) => {
|
|
35
|
+
for (const line of sink.out)
|
|
36
|
+
deps.io.out(line);
|
|
37
|
+
const errSink = helpToStdout ? deps.io.out : deps.io.err;
|
|
38
|
+
for (const line of sink.err)
|
|
39
|
+
errSink(line);
|
|
40
|
+
};
|
|
24
41
|
try {
|
|
25
42
|
await program.parseAsync(argv, { from: "user" });
|
|
43
|
+
flush(false);
|
|
26
44
|
return 0;
|
|
27
45
|
}
|
|
28
46
|
catch (err) {
|
|
29
47
|
if (err instanceof CommanderError) {
|
|
30
|
-
//
|
|
31
|
-
// (
|
|
32
|
-
// bare command group
|
|
33
|
-
// —
|
|
34
|
-
//
|
|
35
|
-
// (unknown command/option, missing argument) keep their own non-zero
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
return err.exitCode;
|
|
48
|
+
// A help/version display is a success: commander shows the requested text —
|
|
49
|
+
// help from an explicit `--help` ("commander.helpDisplayed") or from a bare
|
|
50
|
+
// invocation / bare command group ("commander.help"), or the version from
|
|
51
|
+
// `--version` — so we exit 0. Help written for a bare invocation lands on
|
|
52
|
+
// writeErr, so route it to stdout to match `--help`. Genuine parse errors
|
|
53
|
+
// (unknown command/option, missing argument) keep their own non-zero exit
|
|
54
|
+
// code and stay on stderr.
|
|
55
|
+
const isHelp = err.code === "commander.help" || err.code === "commander.helpDisplayed";
|
|
56
|
+
flush(isHelp);
|
|
57
|
+
return isHelp ? 0 : err.exitCode;
|
|
40
58
|
}
|
|
59
|
+
flush(false);
|
|
41
60
|
if (err instanceof NinaApiError) {
|
|
42
61
|
deps.io.err(`Error: ${err.message}`);
|
|
43
62
|
// Map a few notable statuses to distinct exit codes for scripting.
|
package/dist/src/cli/run.js.map
CHANGED
|
@@ -1 +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,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/run.ts"],"names":[],"mappings":"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"}
|
package/dist/src/cli/shared.d.ts
CHANGED
|
@@ -9,6 +9,16 @@ import type { EngineOptions, RawResponse } from "../client/engine.js";
|
|
|
9
9
|
* "Infinity"), so a typo never silently becomes a surprising value.
|
|
10
10
|
*/
|
|
11
11
|
export declare function parseIntArg(value: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* The most retries the engine will ever perform. Mirrors the engine's internal
|
|
14
|
+
* `MAX_RETRIES_CAP` (which still clamps as a defence for direct library users);
|
|
15
|
+
* surfacing it here lets the CLI *reject* an out-of-range value with a clear
|
|
16
|
+
* message rather than silently clamping it, matching the rest of the CLI's
|
|
17
|
+
* validate-and-reject style.
|
|
18
|
+
*/
|
|
19
|
+
export declare const MAX_RETRIES_LIMIT = 10;
|
|
20
|
+
/** commander value-parser for `--max-retries`: a non-negative integer, max 10. */
|
|
21
|
+
export declare function parseMaxRetries(value: string): number;
|
|
12
22
|
/**
|
|
13
23
|
* Validate a positional argument against an allowed set (commander does not
|
|
14
24
|
* support .choices() on positional args). Throws a NinaError so run() prints a
|
|
@@ -16,10 +26,13 @@ export declare function parseIntArg(value: string): number;
|
|
|
16
26
|
*/
|
|
17
27
|
export declare function assertEnum<T extends string>(value: string, allowed: readonly T[], argName: string): T;
|
|
18
28
|
/**
|
|
19
|
-
* Validate a required free-form positional (an identifier or region key).
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
* up front with a clear message (exit 1) instead
|
|
29
|
+
* Validate a required free-form positional (an identifier or region key). Both
|
|
30
|
+
* are single path segments, so two inputs can only ever produce a remote 404 (or
|
|
31
|
+
* a confusing parse error) for what is really a local input mistake — reject them
|
|
32
|
+
* up front with a clear message (exit 1) instead:
|
|
33
|
+
* - empty/whitespace-only (would build a path like `dashboard/.json`);
|
|
34
|
+
* - one containing a path separator (`/` or `\`), e.g. a `../../etc/passwd`
|
|
35
|
+
* traversal attempt — these are percent-encoded and can never match a real id.
|
|
23
36
|
*/
|
|
24
37
|
export declare function requireIdentifier(value: string, argName: string): string;
|
|
25
38
|
export interface GlobalOptions {
|
|
@@ -1 +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,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASjD;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
|
|
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,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEtE;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CASjD;AAED;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,KAAK,CAAC;AAEpC,kFAAkF;AAClF,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMrD;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;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAQxE;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;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,uEAAuE;AACvE,wBAAgB,eAAe,CAAC,MAAM,EAAE,aAAa,GAAG,aAAa,CAQpE;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,OAAO,GAAG,IAAI,CAUrF;AAeD;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,WAAW,EACrB,iBAAiB,CAAC,EAAE,MAAM,GACzB,IAAI,CAcN;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"}
|
package/dist/src/cli/shared.js
CHANGED
|
@@ -20,6 +20,22 @@ export function parseIntArg(value) {
|
|
|
20
20
|
}
|
|
21
21
|
return n;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* The most retries the engine will ever perform. Mirrors the engine's internal
|
|
25
|
+
* `MAX_RETRIES_CAP` (which still clamps as a defence for direct library users);
|
|
26
|
+
* surfacing it here lets the CLI *reject* an out-of-range value with a clear
|
|
27
|
+
* message rather than silently clamping it, matching the rest of the CLI's
|
|
28
|
+
* validate-and-reject style.
|
|
29
|
+
*/
|
|
30
|
+
export const MAX_RETRIES_LIMIT = 10;
|
|
31
|
+
/** commander value-parser for `--max-retries`: a non-negative integer, max 10. */
|
|
32
|
+
export function parseMaxRetries(value) {
|
|
33
|
+
const n = parseIntArg(value);
|
|
34
|
+
if (n > MAX_RETRIES_LIMIT) {
|
|
35
|
+
throw new InvalidArgumentError(`Expected a value between 0 and ${MAX_RETRIES_LIMIT}.`);
|
|
36
|
+
}
|
|
37
|
+
return n;
|
|
38
|
+
}
|
|
23
39
|
/**
|
|
24
40
|
* Validate a positional argument against an allowed set (commander does not
|
|
25
41
|
* support .choices() on positional args). Throws a NinaError so run() prints a
|
|
@@ -32,15 +48,21 @@ export function assertEnum(value, allowed, argName) {
|
|
|
32
48
|
return value;
|
|
33
49
|
}
|
|
34
50
|
/**
|
|
35
|
-
* Validate a required free-form positional (an identifier or region key).
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* up front with a clear message (exit 1) instead
|
|
51
|
+
* Validate a required free-form positional (an identifier or region key). Both
|
|
52
|
+
* are single path segments, so two inputs can only ever produce a remote 404 (or
|
|
53
|
+
* a confusing parse error) for what is really a local input mistake — reject them
|
|
54
|
+
* up front with a clear message (exit 1) instead:
|
|
55
|
+
* - empty/whitespace-only (would build a path like `dashboard/.json`);
|
|
56
|
+
* - one containing a path separator (`/` or `\`), e.g. a `../../etc/passwd`
|
|
57
|
+
* traversal attempt — these are percent-encoded and can never match a real id.
|
|
39
58
|
*/
|
|
40
59
|
export function requireIdentifier(value, argName) {
|
|
41
60
|
if (value.trim() === "") {
|
|
42
61
|
throw new NinaError(`A non-empty ${argName} is required.`);
|
|
43
62
|
}
|
|
63
|
+
if (/[/\\]/.test(value)) {
|
|
64
|
+
throw new NinaError(`Invalid ${argName} "${value}": must not contain a path separator.`);
|
|
65
|
+
}
|
|
44
66
|
return value;
|
|
45
67
|
}
|
|
46
68
|
/** Translate resolved global CLI options into client EngineOptions. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,+EAA+E;AAG/E,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC;AAEjD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,oBAAoB,CAAC,kCAAkC,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IACxB,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,oBAAoB,CAAC,qBAAqB,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAa,EACb,OAAqB,EACrB,OAAe;IAEf,IAAI,CAAE,OAA6B,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,IAAI,SAAS,CAAC,WAAW,OAAO,KAAK,KAAK,uBAAuB,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChG,CAAC;IACD,OAAO,KAAU,CAAC;AACpB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAGhE,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAG1D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;
|
|
1
|
+
{"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"AAIA,OAAO,EAAqB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAGhE,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAG1D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,KAAK,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACvC;AAqCD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;gBAE1C,OAAO,GAAE,aAAkB;IAWvC,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM;IAyBnD,6EAA6E;IACvE,OAAO,CACX,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,WAAW,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAmC,GAChF,OAAO,CAAC,WAAW,CAAC;IAqCvB,0DAA0D;IACpD,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAU/D,+EAA+E;IACzE,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IAIrF,OAAO,CAAC,UAAU;CAenB"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// (429, 503), and decodes responses.
|
|
4
4
|
import { nodeHttpTransport } from "./http.js";
|
|
5
5
|
import { buildQueryString } from "./query.js";
|
|
6
|
-
import { NinaApiError, NinaParseError } from "./errors.js";
|
|
6
|
+
import { NinaApiError, NinaNetworkError, NinaParseError } from "./errors.js";
|
|
7
7
|
export const DEFAULT_BASE_URL = "https://warnung.bund.de";
|
|
8
8
|
const DEFAULT_USER_AGENT = "nina-warnungen-cli";
|
|
9
9
|
const DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
|
|
@@ -14,6 +14,28 @@ const DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
|
|
|
14
14
|
* the process for hours. 10 retries is well beyond any realistic transient blip.
|
|
15
15
|
*/
|
|
16
16
|
const MAX_RETRIES_CAP = 10;
|
|
17
|
+
/**
|
|
18
|
+
* Strip control characters (all C0/C1 except tab and newline, plus DEL) out of a
|
|
19
|
+
* string that originates in an attacker-controlled response — the error `detail`
|
|
20
|
+
* and the echoed Content-Type. `JSON.parse` decodes an escaped ESC in an error
|
|
21
|
+
* body into a real ESC byte, so without this a hostile/MITM'd endpoint could
|
|
22
|
+
* drive ANSI/OSC escape sequences into the user's terminal when the message is
|
|
23
|
+
* printed to stderr. The success JSON path is already safe (`JSON.stringify`
|
|
24
|
+
* escapes these), so this only needs to cover text that flows into a message.
|
|
25
|
+
*
|
|
26
|
+
* Filtered by code point rather than a regex literal, so no raw control byte ever
|
|
27
|
+
* appears in this source file.
|
|
28
|
+
*/
|
|
29
|
+
function sanitizeServerText(text) {
|
|
30
|
+
let out = "";
|
|
31
|
+
for (const ch of text) {
|
|
32
|
+
const n = ch.codePointAt(0) ?? 0;
|
|
33
|
+
if (n <= 8 || (n >= 0x0b && n <= 0x1f) || (n >= 0x7f && n <= 0x9f))
|
|
34
|
+
continue;
|
|
35
|
+
out += ch;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
17
39
|
const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
18
40
|
export class RequestEngine {
|
|
19
41
|
baseUrl;
|
|
@@ -36,6 +58,24 @@ export class RequestEngine {
|
|
|
36
58
|
}
|
|
37
59
|
/** Build a fully-qualified URL from a path and optional query parameters. */
|
|
38
60
|
buildUrl(path, query) {
|
|
61
|
+
// Validate the base URL up front so a malformed `baseUrl` (e.g. a stray
|
|
62
|
+
// `--base-url notaurl`) yields a clear message naming the offending value,
|
|
63
|
+
// instead of an opaque "Invalid URL" that carries the full request path and
|
|
64
|
+
// reads as if the path were at fault.
|
|
65
|
+
let parsed;
|
|
66
|
+
try {
|
|
67
|
+
parsed = new URL(this.baseUrl);
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
throw new NinaNetworkError(`Invalid base URL: ${JSON.stringify(this.baseUrl)}`);
|
|
71
|
+
}
|
|
72
|
+
// Enforce the http(s) scheme here, transport-independently, so the guarantee
|
|
73
|
+
// holds even for a library user who injects a custom Transport that doesn't
|
|
74
|
+
// re-check (the default transport rejects non-http(s) too, but a swapped-in
|
|
75
|
+
// one might not, and could otherwise reach a file:/ftp: driver).
|
|
76
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
77
|
+
throw new NinaNetworkError(`Unsupported base URL scheme "${parsed.protocol}" (only http: and https: are allowed).`);
|
|
78
|
+
}
|
|
39
79
|
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
40
80
|
const qs = query ? buildQueryString(query) : "";
|
|
41
81
|
return `${this.baseUrl}${normalizedPath}${qs ? `?${qs}` : ""}`;
|
|
@@ -64,7 +104,9 @@ export class RequestEngine {
|
|
|
64
104
|
await this.sleep(this.retryDelayMs * attempt);
|
|
65
105
|
continue;
|
|
66
106
|
}
|
|
67
|
-
|
|
107
|
+
// The Content-Type is echoed to stderr (raw-download type-mismatch warning),
|
|
108
|
+
// so strip control characters at the source before it leaves the engine.
|
|
109
|
+
const contentType = sanitizeServerText(String(response.headers["content-type"] ?? ""));
|
|
68
110
|
if (status < 200 || status >= 300) {
|
|
69
111
|
throw this.toApiError(method, url, status, response.body);
|
|
70
112
|
}
|
|
@@ -99,6 +141,10 @@ export class RequestEngine {
|
|
|
99
141
|
catch {
|
|
100
142
|
// Non-JSON error body; leave detail undefined.
|
|
101
143
|
}
|
|
144
|
+
// `detail` came from the response body; strip control characters so a hostile
|
|
145
|
+
// endpoint cannot inject terminal escape sequences via the stderr error message.
|
|
146
|
+
if (detail !== undefined)
|
|
147
|
+
detail = sanitizeServerText(detail);
|
|
102
148
|
return new NinaApiError({ status, url, method, body: text, detail });
|
|
103
149
|
}
|
|
104
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,yEAAyE;AACzE,qCAAqC;AAErC,OAAO,EAAE,iBAAiB,EAAkB,MAAM,WAAW,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAoB,MAAM,YAAY,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"AAQA,OAAO,IAAI,MAAM,WAAW,CAAC;AAyB7B,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"AAQA,OAAO,IAAI,MAAM,WAAW,CAAC;AAyB7B,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,kDAAkD;IAClD,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mFAAmF;IACnF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAClC,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,YAAY,CAAC,CAAC;AAExE;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAuG5B,CAAC"}
|
package/dist/src/client/http.js
CHANGED
|
@@ -52,6 +52,19 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
|
|
|
52
52
|
const isHttps = url.protocol === "https:";
|
|
53
53
|
const driver = isHttps ? https : http;
|
|
54
54
|
const maxBytes = request.maxResponseBytes;
|
|
55
|
+
const timeoutMs = request.timeoutMs;
|
|
56
|
+
// Wall-clock deadline for the whole request. `req.setTimeout()` alone is an
|
|
57
|
+
// *idle-socket* timeout that resets on every byte, so a slow-drip server that
|
|
58
|
+
// sends one byte just under the idle window (and stays under maxResponseBytes)
|
|
59
|
+
// could keep the request alive indefinitely. A single fixed timer bounds the
|
|
60
|
+
// total time from request start to `end`, independent of the byte cadence.
|
|
61
|
+
let deadline;
|
|
62
|
+
const clearDeadline = () => {
|
|
63
|
+
if (deadline !== undefined) {
|
|
64
|
+
clearTimeout(deadline);
|
|
65
|
+
deadline = undefined;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
55
68
|
const req = driver.request(url, {
|
|
56
69
|
method: request.method,
|
|
57
70
|
headers: request.headers,
|
|
@@ -65,6 +78,7 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
|
|
|
65
78
|
received += chunk.length;
|
|
66
79
|
if (maxBytes !== undefined && received > maxBytes) {
|
|
67
80
|
aborted = true;
|
|
81
|
+
clearDeadline();
|
|
68
82
|
res.destroy();
|
|
69
83
|
reject(new NinaNetworkError(`Response exceeded maxResponseBytes (${maxBytes})`));
|
|
70
84
|
return;
|
|
@@ -74,6 +88,7 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
|
|
|
74
88
|
res.on("end", () => {
|
|
75
89
|
if (aborted)
|
|
76
90
|
return;
|
|
91
|
+
clearDeadline();
|
|
77
92
|
resolve({
|
|
78
93
|
status: res.statusCode ?? 0,
|
|
79
94
|
headers: res.headers,
|
|
@@ -83,15 +98,25 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
|
|
|
83
98
|
res.on("error", (err) => {
|
|
84
99
|
if (aborted)
|
|
85
100
|
return; // we already rejected with the size-cap error
|
|
101
|
+
clearDeadline();
|
|
86
102
|
reject(new NinaNetworkError(`Response stream error: ${err.message}`, { cause: err }));
|
|
87
103
|
});
|
|
88
104
|
});
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
105
|
+
if (timeoutMs && timeoutMs > 0) {
|
|
106
|
+
// Idle-socket timeout (resets on activity)...
|
|
107
|
+
req.setTimeout(timeoutMs, () => {
|
|
108
|
+
req.destroy(new NinaNetworkError(`Request timed out after ${timeoutMs}ms`));
|
|
92
109
|
});
|
|
110
|
+
// ...plus a hard wall-clock deadline (does not reset) so a slow drip cannot
|
|
111
|
+
// outlast the caller's timeout budget.
|
|
112
|
+
deadline = setTimeout(() => {
|
|
113
|
+
req.destroy(new NinaNetworkError(`Request exceeded the ${timeoutMs}ms deadline`));
|
|
114
|
+
}, timeoutMs);
|
|
115
|
+
// Don't let the deadline timer keep the event loop alive on its own.
|
|
116
|
+
deadline.unref?.();
|
|
93
117
|
}
|
|
94
118
|
req.on("error", (err) => {
|
|
119
|
+
clearDeadline();
|
|
95
120
|
// A timeout destroy already passes an NinaNetworkError; don't double-wrap.
|
|
96
121
|
if (err instanceof NinaNetworkError) {
|
|
97
122
|
reject(err);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,iDAAiD;AACjD,EAAE;AACF,gFAAgF;AAChF,8EAA8E;AAC9E,8EAA8E;AAC9E,yCAAyC;AAEzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,SAAS,oBAAoB,CAAC,GAA0B,EAAE,IAAY;IACpE,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;QACjB,KAAK,cAAc;YACjB,OAAO,wBAAwB,IAAI,4DAA4D,CAAC;QAClG,KAAK,WAAW,CAAC;QACjB,KAAK,WAAW;YACd,OAAO,0BAA0B,IAAI,8CAA8C,CAAC;QACtF,KAAK,YAAY;YACf,OAAO,iBAAiB,IAAI,aAAa,CAAC;QAC5C,KAAK,WAAW;YACd,OAAO,iBAAiB,IAAI,aAAa,CAAC;QAC5C;YACE,OAAO,GAAG,CAAC,OAAO,CAAC;IACvB,CAAC;AACH,CAAC;AAuBD;;;;GAIG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAc,CAAC,OAAO,EAAE,EAAE,CACtD,IAAI,OAAO,CAAe,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC5C,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,CAAC,IAAI,gBAAgB,CAAC,gBAAgB,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC5D,OAAO;IACT,CAAC;IAED,6EAA6E;IAC7E,2EAA2E;IAC3E,2DAA2D;IAC3D,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,CAAC,IAAI,gBAAgB,CAAC,yBAAyB,GAAG,CAAC,QAAQ,aAAa,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC9F,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC;IAC1C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED