@maschinenlesbar.org/pegel-online-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 CHANGED
@@ -1,192 +1,231 @@
1
1
  # pegel-online-cli
2
2
 
3
- A TypeScript **API client** and **command-line interface** for the open
4
- [PEGELONLINE REST API v2](https://www.pegelonline.wsv.de/webservice/dokuRestapi)
5
- (`pegelonline.wsv.de`) operated by the **WSV** (Wasserstraßen- und
6
- Schifffahrtsverwaltung des Bundes) — live **water levels** and related timeseries
7
- across the German federal waterway network.
8
-
9
- - **Zero runtime HTTP dependencies** — built on Node's built-in `http`/`https` (no axios, no fetch polyfill).
10
- - **One small dependency** for the CLI: [`commander`](https://github.com/tj/commander.js).
11
- - **Strongly typed** — typed stations, timeseries and measurement shapes.
12
- - **Well tested** — unit tests on Node's built-in test runner (`node --test`), every HTTP response mocked.
13
- - **Read-only, no auth** — the PEGELONLINE API needs no key; this client only reads.
3
+ [![CI](https://github.com/maschinenlesbar-org/pegel-online-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/maschinenlesbar-org/pegel-online-cli/actions/workflows/ci.yml)
4
+ [![Release](https://github.com/maschinenlesbar-org/pegel-online-cli/actions/workflows/release.yml/badge.svg)](https://github.com/maschinenlesbar-org/pegel-online-cli/actions/workflows/release.yml)
5
+ [![npm](https://img.shields.io/npm/v/@maschinenlesbar.org/pegel-online-cli)](https://www.npmjs.com/package/@maschinenlesbar.org/pegel-online-cli)
14
6
 
15
- New to PEGELONLINE, or terms like *Gewässer*, *timeseries* (`W`/`Q`), MNW/MHW or
16
- NSW/HSW? See **[GLOSSARY.md](GLOSSARY.md)** for the domain concepts and the
17
- project's own vocabulary.
7
+ Check live water levels and gauge readings for any German federal waterway station
8
+ from your terminal. `pegel` is a command-line tool over the open
9
+ [PEGELONLINE REST API v2](https://www.pegelonline.wsv.de/webservice/dokuRestapi)
10
+ (`pegelonline.wsv.de`) operated by the WSV — find stations, query current readings,
11
+ pull measurement histories, and get the full picture on any gauge — as clean JSON
12
+ you can pipe straight into [`jq`](https://jqlang.github.io/jq/).
18
13
 
19
- ## Requirements
14
+ - **Works out of the box** — no account, no API key, no configuration. Install and query.
15
+ - **Clean JSON output** — pretty-printed by default, `--compact` for one-line/scripting.
16
+ - **Covers the full hierarchy** — bodies of water, stations, timeseries, current readings, measurement windows, and gauge marks.
17
+ - **Live data** — readings update continuously from hundreds of federal gauges across Germany's rivers and canals.
20
18
 
21
- - Node.js **>= 20** (uses the stable built-in test runner, ESM and top-level `await`).
19
+ > Want to use this as a TypeScript library or understand how it's built?
20
+ > See **[DEVELOPING.md](DEVELOPING.md)**.
22
21
 
23
22
  ## Install
24
23
 
25
24
  ```bash
26
- npm install
27
- npm run build # compiles TypeScript to dist/
25
+ npm i -g @maschinenlesbar.org/pegel-online-cli
28
26
  ```
29
27
 
30
- Run the CLI without a global install:
28
+ This installs the **`pegel`** command. Requires **Node.js 20+**.
29
+
30
+ Check it works:
31
31
 
32
32
  ```bash
33
- node dist/src/cli/index.js --help
34
- # or, after `npm link` / global install:
35
33
  pegel --help
36
34
  ```
37
35
 
38
- ---
36
+ ## Quickstart
39
37
 
40
- ## CLI usage
38
+ No setup needed — the API is public and requires no key. Your first command:
41
39
 
42
- Every command prints pretty JSON to stdout (`--compact` for a single line). A
43
- `<station>` may be a **uuid**, **number**, **shortname** or **longname**. A
44
- `[timeseries]` defaults to **`W`** (water level); others include `Q` (flow),
45
- `WT` (water temperature), `LT` (air temperature), depending on the station.
40
+ ```bash
41
+ pegel waters
42
+ ```
46
43
 
47
- ### Global options
44
+ This lists every body of water (*Gewässer*) in the network. Grab just the shortnames
45
+ with `jq`:
48
46
 
49
- | Option | Description |
50
- | --- | --- |
51
- | `--base-url <url>` | API base URL (default `https://www.pegelonline.wsv.de`) |
52
- | `--timeout <ms>` | Per-request timeout (default `30000`) |
53
- | `--user-agent <ua>` | `User-Agent` header value |
54
- | `--max-retries <n>` | Retries for transient `429`/`503` responses (default `2`) |
55
- | `--max-response-bytes <n>` | Cap response body size in bytes (`0` = unlimited; default 100 MiB) |
56
- | `--compact` | Print JSON on a single line |
47
+ ```bash
48
+ pegel waters | jq -r '.[].shortname'
49
+ ```
57
50
 
58
- Global options are accepted **before or after** the command, e.g. both
59
- `pegel --compact waters` and `pegel waters --compact` work; placing them before
60
- the command is recommended for clarity.
51
+ Pick one say `RHEIN` and get the current water level at Bonn:
61
52
 
62
- ### Commands
53
+ ```bash
54
+ pegel current BONN
55
+ ```
56
+
57
+ Pull just the value and timestamp:
58
+
59
+ ```bash
60
+ pegel current BONN | jq '{value, timestamp}'
61
+ ```
62
+
63
+ ## Commands
63
64
 
64
65
  ```text
65
- stations list [--ids <id> ...] [--waters <shortname>] [--fuzzy-id <id>]
66
- [--include-timeseries] [--include-current] [--include-characteristic]
67
- stations get <station> [--include-...]
68
- timeseries <station> [timeseries] metadata for a timeseries
69
- current <station> [timeseries] the current measurement
70
- measurements <station> [timeseries] [--start <iso|P7D>] [--end <iso>]
71
- waters list all bodies of water (Gewässer)
66
+ stations list [filters…] list / filter stations
67
+ stations get <station> [includes…] full details for one station
68
+ timeseries <station> [timeseries] metadata for a timeseries
69
+ current <station> [timeseries] the current measurement
70
+ measurements <station> [timeseries] a window of measurements
71
+ waters list all bodies of water (Gewässer)
72
72
  ```
73
73
 
74
- ### Examples
74
+ A `<station>` may be a **uuid**, **number**, **shortname** or **longname** — e.g.
75
+ `BONN`, `6302010`, or a full UUID. A `[timeseries]` defaults to **`W`** (water
76
+ level); other codes include `Q` (flow/discharge), `WT` (water temperature), and
77
+ `LT` (air temperature) depending on the station.
78
+
79
+ ### `stations list` filters
80
+
81
+ | Flag | Meaning |
82
+ | --- | --- |
83
+ | `--ids <id>` | station id (uuid/number/shortname/longname); repeatable |
84
+ | `--waters <shortname>` | filter by water shortname (see `waters`) |
85
+ | `--fuzzy-id <id>` | fuzzy match against short/long name |
86
+ | `--include-timeseries` | embed each station's timeseries list |
87
+ | `--include-current` | embed the current measurement |
88
+ | `--include-characteristic` | embed characteristic (gauge-mark) values |
89
+
90
+ ### `stations get` options
91
+
92
+ | Flag | Meaning |
93
+ | --- | --- |
94
+ | `--include-timeseries` | embed the station's timeseries list |
95
+ | `--include-current` | embed the current measurement |
96
+ | `--include-characteristic` | embed characteristic (gauge-mark) values |
97
+
98
+ ### `measurements` options
99
+
100
+ | Flag | Meaning |
101
+ | --- | --- |
102
+ | `--start <iso>` | window start — ISO-8601 instant *or* a period like `P7D` |
103
+ | `--end <iso>` | window end — ISO-8601 instant |
104
+
105
+ The **[Glossary](GLOSSARY.md)** explains every domain term and timeseries code.
106
+
107
+ ## Common tasks
108
+
109
+ A few recipes to get going — see **[Usage.md](Usage.md)** for the full,
110
+ use-case-driven set.
75
111
 
76
112
  ```bash
77
113
  # All stations on the Rhine, with their current water level
78
114
  pegel stations list --waters RHEIN --include-current
79
115
 
80
- # One station
116
+ # One station — metadata + timeseries list + current reading
81
117
  pegel stations get BONN --include-timeseries --include-current
82
118
 
83
- # Current water level at Bonn
119
+ # Current water level at Bonn (default timeseries W)
84
120
  pegel current BONN
85
121
 
86
- # Last 3 days of measurements
87
- pegel measurements BONN W --start P3D
122
+ # Current flow at Bonn (timeseries Q)
123
+ pegel current BONN Q
88
124
 
89
- # Characteristic (gauge-mark) values, embedded in the timeseries
90
- pegel stations get BONN --include-timeseries --include-characteristic
125
+ # Last 7 days of measurements
126
+ pegel measurements BONN W --start P7D
91
127
 
92
- # Bodies of water
93
- pegel waters
94
- ```
128
+ # Explicit date window
129
+ pegel measurements BONN W --start 2026-06-01T00:00:00Z --end 2026-06-07T00:00:00Z
95
130
 
96
- Exit codes: `0` success, `2` for usage/parse errors (unknown command/option, missing argument, invalid flag value), `4` on a `404` from the API, `1` for any other (runtime/network) error.
131
+ # Gauge marks (MNW/MHW/NSW/HSW) for Cologne
132
+ pegel stations get KÖLN --include-timeseries --include-characteristic
97
133
 
98
- ---
134
+ # Timeseries metadata — discover which series a station exposes
135
+ pegel timeseries BONN
99
136
 
100
- ## Library usage
137
+ # Multiple specific stations in one call
138
+ pegel stations list --ids BONN --ids KÖLN --ids EMMERICH --include-current
139
+ ```
101
140
 
102
- ```ts
103
- import { PegelOnlineClient, PegelApiError } from "@maschinenlesbar.org/pegel-online-cli";
141
+ ## Output & scripting
104
142
 
105
- const client = new PegelOnlineClient(); // defaults to https://www.pegelonline.wsv.de
143
+ Every command prints **pretty JSON to stdout**. Errors and diagnostics go to
144
+ stderr, so piping stdout into `jq` stays clean.
106
145
 
107
- const rhine = await client.stations.list({ waters: "RHEIN", includeCurrentMeasurement: true });
108
- const bonn = await client.stations.get("BONN", { includeTimeseries: true });
109
- const now = await client.timeseries.currentMeasurement("BONN", "W");
110
- const series = await client.timeseries.measurements("BONN", "W", { start: "P3D" });
146
+ ```bash
147
+ # Water shortnames, one per line
148
+ pegel waters | jq -r '.[].shortname'
111
149
 
112
- try {
113
- await client.stations.get("DOES-NOT-EXIST");
114
- } catch (err) {
115
- if (err instanceof PegelApiError) console.error(err.status, err.detail);
116
- }
117
- ```
150
+ # Reshape a current measurement
151
+ pegel current BONN | jq '{value, timestamp}'
118
152
 
119
- ### Client options
120
-
121
- ```ts
122
- new PegelOnlineClient({
123
- baseUrl: "https://www.pegelonline.wsv.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
- ```
153
+ # CSV-ish series for a spreadsheet
154
+ pegel measurements BONN W --start P3D | jq -r '.[] | [.timestamp, .value] | @csv'
131
155
 
132
- ### Resource groups
156
+ # Station names and coordinates on the Rhine (tab-separated)
157
+ pegel stations list --waters RHEIN | jq -r '.[] | [.shortname, .longitude, .latitude] | @tsv'
133
158
 
134
- `client.stations` (`.list` / `.get`), `client.timeseries` (`.get` / `.currentMeasurement` /
135
- `.measurements`), and `client.waters()`. Characteristic (gauge-mark) values are
136
- available via the `includeCharacteristicValues` embed on `.get` / `.list`.
137
-
138
- ---
159
+ # Gauge marks for the W series at Cologne
160
+ pegel stations get KÖLN --include-timeseries --include-characteristic \
161
+ | jq '.timeseries[] | select(.shortname == "W") | .characteristicValues'
162
+ ```
139
163
 
140
- ## Architecture
164
+ Use `--compact` for single-line JSON in pipelines and logs:
141
165
 
142
- ```
143
- src/
144
- client/
145
- types.ts # Station / TimeseriesInfo / CurrentMeasurement / Measurement + param objects
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 # PegelError / PegelApiError / PegelNetworkError / PegelParseError
150
- client.ts # PegelOnlineClient — stations + timeseries resources over the engine
151
- cli/
152
- io.ts # injectable I/O seam (stdout/stderr)
153
- shared.ts # option parsers, global-option resolver, JSON renderer
154
- commands/ # stations + timeseries/measurements/waters
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
166
+ ```bash
167
+ pegel --compact current BONN | jq '.value'
158
168
  ```
159
169
 
160
- **Design notes**
170
+ `--compact` (and every global option) works **before or after** the command —
171
+ both `pegel --compact waters` and `pegel waters --compact` do the same thing.
161
172
 
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
- - The engine follows HTTP redirects, so trailing-slash and host normalisations are handled transparently.
173
+ **Exit codes** make the CLI easy to use in scripts:
167
174
 
168
- ---
175
+ | Code | Meaning |
176
+ | --- | --- |
177
+ | `0` | success (also `--help` / `--version`) |
178
+ | `2` | bad usage / invalid argument (nothing was sent) |
179
+ | `4` | station or resource not found (`404`) |
180
+ | `1` | any other error (network, timeout, unexpected response) |
181
+
182
+ ## Troubleshooting
183
+
184
+ - **`command not found: pegel`** — the global npm bin directory isn't on your
185
+ `PATH`. Run `npm bin -g` to find it and add it, or run via
186
+ `npx @maschinenlesbar.org/pegel-online-cli …`.
187
+ - **Exit `2` / "invalid argument"** — check the command syntax: a `<station>`
188
+ argument is required, and `--start` / `--end` must be valid ISO-8601 instants or
189
+ periods (e.g. `P7D`). Run `pegel <command> --help` for the exact signature.
190
+ - **Exit `4` / "not found"** — the station shortname or id doesn't exist. Run
191
+ `pegel stations list --fuzzy-id <name>` or `pegel waters` to find the right
192
+ shortname.
193
+ - **Exit `1` / network error** — connectivity, DNS, or a timeout. Try again, or
194
+ raise the limit with `--timeout 60000`.
195
+ - **Empty `timeseries` array** — the station doesn't publish the requested series.
196
+ Run `pegel timeseries <station>` to see which codes it actually exposes.
197
+
198
+ ## Global options
199
+
200
+ These apply to every command and may be given before *or* after it:
169
201
 
170
- ## Testing
202
+ | Option | Description |
203
+ | --- | --- |
204
+ | `-V, --version` | Print the version number |
205
+ | `-h, --help` | Show help for the program or a command |
206
+ | `--compact` | Print JSON on a single line instead of pretty-printed |
207
+ | `--base-url <url>` | API base URL (default `https://www.pegelonline.wsv.de`) |
208
+ | `--timeout <ms>` | Per-request timeout in milliseconds (default `30000`) |
209
+ | `--user-agent <ua>` | `User-Agent` header value |
210
+ | `--max-retries <n>` | Retries for transient `429`/`503` responses (default `2`) |
211
+ | `--max-response-bytes <n>` | Cap response body size in bytes (`0` = unlimited; default 100 MiB) |
171
212
 
172
- ```bash
173
- npm test # builds, then runs `node --test` over dist/test
174
- ```
213
+ ## Learn more
175
214
 
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 mocked transport.
179
- - **`client.test.ts`**every endpoint's method/URL/query mapping mocked transport.
180
- - **`cli.test.ts`** — end-to-end command parsing, validation and exit codes — mocked client.
215
+ - **[SKILLS.md](SKILLS.md)**Claude Code Agent Skills that drive this CLI for live water-level questions.
216
+ - **[Usage.md](Usage.md)**full use-case-driven cookbook.
217
+ - **[GLOSSARY.md](GLOSSARY.md)**every domain term, timeseries code, and state classification explained.
218
+ - **[DEVELOPING.md](DEVELOPING.md)**TypeScript library usage, architecture, testing, CI.
181
219
 
182
- ## Continuous integration
220
+ ## Data license
183
221
 
184
- GitHub Actions workflows under `.github/workflows/`:
222
+ This CLI is a **client** — it accesses data it does not own or redistribute. The
223
+ upstream data is © its provider and licensed **separately from this tool's code**.
224
+ See **[DATA_LICENSE.md](DATA_LICENSE.md)**.
185
225
 
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.
226
+ > **Wasserstraßen- und Schifffahrtsverwaltung des Bundes (WSV)** Datenlizenz
227
+ > Deutschland **Zero** 2.0 (≈ CC0): no attribution required, commercial use and
228
+ > modification allowed. Raw, unchecked data no warranty.
190
229
 
191
230
  ## License
192
231
 
@@ -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 { PegelOnlineClient } from "../client/client.js";
9
- import { parseIntArg } from "./shared.js";
9
+ import { parseIntArg, parseBaseUrl } from "./shared.js";
10
10
  import { registerStationCommands } from "./commands/stations.js";
11
11
  import { registerTimeseriesCommands } from "./commands/timeseries.js";
12
12
  /**
@@ -38,7 +38,7 @@ export function buildProgram(deps = defaultDeps) {
38
38
  .description("CLI for the open PEGELONLINE water-level REST API " +
39
39
  "(https://www.pegelonline.wsv.de/webservices/rest-api/v2)")
40
40
  .version(VERSION)
41
- .option("--base-url <url>", "API base URL", "https://www.pegelonline.wsv.de")
41
+ .option("--base-url <url>", "API base URL", parseBaseUrl, "https://www.pegelonline.wsv.de")
42
42
  .option("--timeout <ms>", "per-request timeout in milliseconds", parseIntArg)
43
43
  .option("--user-agent <ua>", "User-Agent header value")
44
44
  .option("--max-retries <n>", "retries for transient 429/503 responses", parseIntArg)
@@ -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,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE;;;;;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,iBAAiB,CAAC,OAAO,CAAC;CAC1D,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB,WAAW;IACtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CACV,oDAAoD;QAClD,0DAA0D,CAC7D;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,gCAAgC,CAAC;SAC5E,MAAM,CAAC,gBAAgB,EAAE,qCAAqC,EAAE,WAAW,CAAC;SAC5E,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;SACtD,MAAM,CAAC,mBAAmB,EAAE,yCAAyC,EAAE,WAAW,CAAC;SACnF,MAAM,CACL,0BAA0B,EAC1B,kEAAkE,EAClE,WAAW,CACZ;SACA,MAAM,CAAC,WAAW,EAAE,uDAAuD,CAAC;SAC5E,kBAAkB,EAAE,CAAC;IAExB,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE1C,OAAO,OAAO,CAAC;AACjB,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,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAEtE;;;;;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,iBAAiB,CAAC,OAAO,CAAC;CAC1D,CAAC;AAEF,MAAM,UAAU,YAAY,CAAC,OAAgB,WAAW;IACtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,OAAO,CAAC;SACb,WAAW,CACV,oDAAoD;QAClD,0DAA0D,CAC7D;SACA,OAAO,CAAC,OAAO,CAAC;SAChB,MAAM,CAAC,kBAAkB,EAAE,cAAc,EAAE,YAAY,EAAE,gCAAgC,CAAC;SAC1F,MAAM,CAAC,gBAAgB,EAAE,qCAAqC,EAAE,WAAW,CAAC;SAC5E,MAAM,CAAC,mBAAmB,EAAE,yBAAyB,CAAC;SACtD,MAAM,CAAC,mBAAmB,EAAE,yCAAyC,EAAE,WAAW,CAAC;SACnF,MAAM,CACL,0BAA0B,EAC1B,kEAAkE,EAClE,WAAW,CACZ;SACA,MAAM,CAAC,WAAW,EAAE,uDAAuD,CAAC;SAC5E,kBAAkB,EAAE,CAAC;IAExB,uBAAuB,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACvC,0BAA0B,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAE1C,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -2,6 +2,15 @@ import type { CliDeps } from "./io.js";
2
2
  import type { EngineOptions } from "../client/engine.js";
3
3
  /** commander value-parser: a non-negative integer. */
4
4
  export declare function parseIntArg(value: string): number;
5
+ /**
6
+ * commander value-parser for `--base-url`: reject anything that is not a parseable
7
+ * absolute `http:`/`https:` URL at *parse* time, so a bad scheme (`file:`, `ftp:`)
8
+ * or malformed URL exits 2 (usage) — consistent with the blueprint — instead of
9
+ * surfacing later as a runtime PegelNetworkError (exit 1). The transport still
10
+ * enforces the same allowlist as the authoritative egress control; this only moves
11
+ * the user-facing rejection earlier and to the correct exit code.
12
+ */
13
+ export declare function parseBaseUrl(value: string): string;
5
14
  /**
6
15
  * Validate a required positional argument: reject an empty/blank value rather
7
16
  * than forwarding it into the URL path (which would produce a malformed request
@@ -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;AACvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAU1E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,SAAM,GAAG,MAAM,CAE9E;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"}
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,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGzD,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAajD;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAWlD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAU1E;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,SAAM,GAAG,MAAM,CAE9E;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"}
@@ -17,6 +17,27 @@ export function parseIntArg(value) {
17
17
  }
18
18
  return n;
19
19
  }
20
+ /**
21
+ * commander value-parser for `--base-url`: reject anything that is not a parseable
22
+ * absolute `http:`/`https:` URL at *parse* time, so a bad scheme (`file:`, `ftp:`)
23
+ * or malformed URL exits 2 (usage) — consistent with the blueprint — instead of
24
+ * surfacing later as a runtime PegelNetworkError (exit 1). The transport still
25
+ * enforces the same allowlist as the authoritative egress control; this only moves
26
+ * the user-facing rejection earlier and to the correct exit code.
27
+ */
28
+ export function parseBaseUrl(value) {
29
+ let url;
30
+ try {
31
+ url = new URL(value);
32
+ }
33
+ catch {
34
+ throw new InvalidArgumentError("Expected an absolute http(s) URL.");
35
+ }
36
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
37
+ throw new InvalidArgumentError("Only http and https URLs are supported.");
38
+ }
39
+ return value;
40
+ }
20
41
  /**
21
42
  * Validate a required positional argument: reject an empty/blank value rather
22
43
  * than forwarding it into the URL path (which would produce a malformed request
@@ -1 +1 @@
1
- {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,14 @@ export interface EngineOptions {
13
13
  transport?: Transport;
14
14
  /** Value of the User-Agent header. */
15
15
  userAgent?: string;
16
+ /**
17
+ * Extra headers sent on every request. Credential-bearing headers
18
+ * (Authorization, Cookie, X-API-Key, Proxy-Authorization) are automatically
19
+ * stripped when a redirect crosses to a different origin, so they never leak to
20
+ * an arbitrary host named in Location. This client is keyless and sets none, but
21
+ * library consumers may add one.
22
+ */
23
+ headers?: Record<string, string>;
16
24
  /** Per-request timeout in milliseconds (0 disables). */
17
25
  timeoutMs?: number;
18
26
  /** Number of automatic retries for transient (429/503) responses. */
@@ -33,6 +41,7 @@ export declare class RequestEngine {
33
41
  private readonly baseUrl;
34
42
  private readonly transport;
35
43
  private readonly userAgent;
44
+ private readonly extraHeaders;
36
45
  private readonly timeoutMs;
37
46
  private readonly maxRetries;
38
47
  private readonly retryDelayMs;
@@ -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,mCAAmC,CAAC;AAGjE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,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,+EAA+E;IAC/E,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;AAOD,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,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;gBAE1C,OAAO,GAAE,aAAkB;IAkBvC,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM;IAMnD,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;IAsDvB,0DAA0D;IACpD,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAU/D,OAAO,CAAC,UAAU;CAYnB"}
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,mCAAmC,CAAC;AAGjE,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+EAA+E;IAC/E,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,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;AAmDD,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,YAAY,CAAyB;IACtD,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,YAAY,CAAS;IACtC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;IAC1C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;gBAE1C,OAAO,GAAE,aAAkB;IAmBvC,6EAA6E;IAC7E,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM;IAMnD,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;IAwDvB,0DAA0D;IACpD,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC;IAU/D,OAAO,CAAC,UAAU;CAenB"}
@@ -7,11 +7,55 @@ import { PegelApiError, PegelError, PegelParseError } from "./errors.js";
7
7
  export const DEFAULT_BASE_URL = "https://www.pegelonline.wsv.de";
8
8
  const DEFAULT_USER_AGENT = "pegel-online-cli";
9
9
  const DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
10
+ /**
11
+ * Credential-bearing headers that must never be carried across an origin boundary
12
+ * on a redirect. Stored lower-cased and compared case-insensitively so a header
13
+ * added as `X-Api-Key` or `Authorization` is caught regardless of casing.
14
+ */
15
+ const CREDENTIAL_HEADERS = new Set([
16
+ "authorization",
17
+ "cookie",
18
+ "x-api-key",
19
+ "proxy-authorization",
20
+ ]);
21
+ /**
22
+ * Delete every credential-bearing header from `headers`, matching case-insensitively.
23
+ * The CLI sends none today (keyless), but RequestEngine is exported as a library and
24
+ * a keyed sibling/consumer could add one via a future headers option — keep the
25
+ * guarantee correct regardless of the casing the caller used.
26
+ */
27
+ function stripSensitiveHeaders(headers) {
28
+ for (const key of Object.keys(headers)) {
29
+ if (CREDENTIAL_HEADERS.has(key.toLowerCase()))
30
+ delete headers[key];
31
+ }
32
+ }
33
+ /**
34
+ * Strip control characters (all C0/C1 controls except tab and newline, plus DEL)
35
+ * out of a string that originates in an attacker-controlled response — the error
36
+ * `detail`. `JSON.parse` decodes an escaped ESC in an error body into a real ESC
37
+ * byte, so without this a hostile or MITM'd endpoint
38
+ * could drive ANSI/OSC escape sequences into the user's terminal once the message
39
+ * is printed raw to stderr (title spoofing, output overwrite, OSC 52 clipboard).
40
+ * The success path is already safe (`JSON.stringify` escapes these), so this only
41
+ * needs to cover text that flows into an error message.
42
+ */
43
+ function sanitizeServerText(text) {
44
+ let out = "";
45
+ for (const ch of text) {
46
+ const n = ch.codePointAt(0) ?? 0;
47
+ if (n <= 8 || (n >= 0x0b && n <= 0x1f) || (n >= 0x7f && n <= 0x9f))
48
+ continue;
49
+ out += ch;
50
+ }
51
+ return out;
52
+ }
10
53
  const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
11
54
  export class RequestEngine {
12
55
  baseUrl;
13
56
  transport;
14
57
  userAgent;
58
+ extraHeaders;
15
59
  timeoutMs;
16
60
  maxRetries;
17
61
  retryDelayMs;
@@ -28,6 +72,7 @@ export class RequestEngine {
28
72
  if (/[\x00-\x1f\x7f]/.test(this.userAgent)) {
29
73
  throw new PegelError("Invalid User-Agent: control characters are not allowed.");
30
74
  }
75
+ this.extraHeaders = options.headers ?? {};
31
76
  this.timeoutMs = options.timeoutMs ?? 30_000;
32
77
  this.maxRetries = options.maxRetries ?? 2;
33
78
  this.retryDelayMs = options.retryDelayMs ?? 200;
@@ -45,6 +90,7 @@ export class RequestEngine {
45
90
  async request(method, path, options = { accept: "application/json" }) {
46
91
  let url = this.buildUrl(path, options.query);
47
92
  const headers = {
93
+ ...this.extraHeaders,
48
94
  Accept: options.accept,
49
95
  "User-Agent": this.userAgent,
50
96
  };
@@ -71,12 +117,13 @@ export class RequestEngine {
71
117
  const location = response.headers["location"];
72
118
  if (typeof location === "string" && location.length > 0) {
73
119
  const next = new URL(location, url);
74
- // Security: never carry credential-bearing headers across origins. The
75
- // CLI sends none today, but this guards a future Authorization/Cookie
76
- // header from leaking to an attacker-controlled redirect target.
120
+ // Security: never carry credential-bearing headers across an origin
121
+ // boundary. The CLI sends none today, but this guards a future
122
+ // Authorization/Cookie/X-Api-Key header from leaking to an
123
+ // attacker-controlled redirect target. Comparing full origin (scheme +
124
+ // host + port) also strips on a same-host https->http downgrade.
77
125
  if (next.origin !== new URL(url).origin) {
78
- delete headers["Authorization"];
79
- delete headers["Cookie"];
126
+ stripSensitiveHeaders(headers);
80
127
  }
81
128
  url = next.toString();
82
129
  redirects += 1;
@@ -114,6 +161,10 @@ export class RequestEngine {
114
161
  catch {
115
162
  // Non-JSON error body; leave detail undefined.
116
163
  }
164
+ // `detail` came from the response body; strip control characters so a hostile
165
+ // endpoint cannot inject terminal escape sequences via the stderr error message.
166
+ if (detail !== undefined)
167
+ detail = sanitizeServerText(detail);
117
168
  return new PegelApiError({ status, url, method, body: text, detail });
118
169
  }
119
170
  }
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"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"}
@@ -17,10 +17,5 @@ export interface HttpResponse {
17
17
  body: Buffer;
18
18
  }
19
19
  export type Transport = (request: HttpRequest) => Promise<HttpResponse>;
20
- /**
21
- * Default transport. Resolves with the raw response (including non-2xx) — status
22
- * interpretation is the client's job. Rejects only on transport-level failures
23
- * (connection errors, timeouts, malformed URLs).
24
- */
25
20
  export declare const nodeHttpTransport: Transport;
26
21
  //# sourceMappingURL=http.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"AAQA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,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,SAwE5B,CAAC"}
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"AAQA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,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;AAgBxE,eAAO,MAAM,iBAAiB,EAAE,SAmG5B,CAAC"}
@@ -13,6 +13,14 @@ import { PegelNetworkError } from "./errors.js";
13
13
  * interpretation is the client's job. Rejects only on transport-level failures
14
14
  * (connection errors, timeouts, malformed URLs).
15
15
  */
16
+ /**
17
+ * Multiplier applied to the per-request idle timeout to derive an overall
18
+ * wall-clock deadline. `req.setTimeout` only fires on an *idle* socket — every
19
+ * received byte resets it — so a hostile server can trickle one byte just under
20
+ * the idle window forever and the request never times out. This bounds the total
21
+ * time a single request may take before it is destroyed, regardless of trickle.
22
+ */
23
+ const OVERALL_DEADLINE_FACTOR = 10;
16
24
  export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
17
25
  let url;
18
26
  try {
@@ -32,6 +40,23 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
32
40
  const isHttps = url.protocol === "https:";
33
41
  const driver = isHttps ? https : http;
34
42
  const maxBytes = request.maxResponseBytes;
43
+ // Overall wall-clock deadline (see OVERALL_DEADLINE_FACTOR). Cleared on the
44
+ // first settle so it never leaks or keeps the event loop alive.
45
+ let deadlineTimer;
46
+ const clearDeadline = () => {
47
+ if (deadlineTimer !== undefined) {
48
+ clearTimeout(deadlineTimer);
49
+ deadlineTimer = undefined;
50
+ }
51
+ };
52
+ const settleResolve = (value) => {
53
+ clearDeadline();
54
+ resolve(value);
55
+ };
56
+ const settleReject = (err) => {
57
+ clearDeadline();
58
+ reject(err);
59
+ };
35
60
  const req = driver.request(url, {
36
61
  method: request.method,
37
62
  headers: request.headers,
@@ -46,7 +71,7 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
46
71
  if (maxBytes !== undefined && received > maxBytes) {
47
72
  aborted = true;
48
73
  res.destroy();
49
- reject(new PegelNetworkError(`Response exceeded maxResponseBytes (${maxBytes})`));
74
+ settleReject(new PegelNetworkError(`Response exceeded maxResponseBytes (${maxBytes})`));
50
75
  return;
51
76
  }
52
77
  chunks.push(chunk);
@@ -54,7 +79,7 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
54
79
  res.on("end", () => {
55
80
  if (aborted)
56
81
  return;
57
- resolve({
82
+ settleResolve({
58
83
  status: res.statusCode ?? 0,
59
84
  headers: res.headers,
60
85
  body: Buffer.concat(chunks),
@@ -63,17 +88,26 @@ export const nodeHttpTransport = (request) => new Promise((resolve, reject) => {
63
88
  res.on("error", (err) => {
64
89
  if (aborted)
65
90
  return; // we already rejected with the size-cap error
66
- reject(new PegelNetworkError(`Response stream error: ${err.message}`, { cause: err }));
91
+ settleReject(new PegelNetworkError(`Response stream error: ${err.message}`, { cause: err }));
67
92
  });
68
93
  });
69
94
  if (request.timeoutMs && request.timeoutMs > 0) {
95
+ // Idle-socket timeout: fires when no bytes move for timeoutMs.
70
96
  req.setTimeout(request.timeoutMs, () => {
71
97
  req.destroy(new PegelNetworkError(`Request timed out after ${request.timeoutMs}ms`));
72
98
  });
99
+ // Overall deadline: a hostile server can trickle bytes just under the idle
100
+ // window forever, so cap total wall-clock time as well.
101
+ const overallMs = request.timeoutMs * OVERALL_DEADLINE_FACTOR;
102
+ deadlineTimer = setTimeout(() => {
103
+ req.destroy(new PegelNetworkError(`Request exceeded overall deadline of ${overallMs}ms`));
104
+ }, overallMs);
105
+ // Do not let the deadline timer alone keep the process alive.
106
+ deadlineTimer.unref?.();
73
107
  }
74
108
  req.on("error", (err) => {
75
109
  // A timeout destroy already passes an PegelNetworkError; don't double-wrap.
76
- reject(err instanceof PegelNetworkError ? err : new PegelNetworkError(err.message, { cause: err }));
110
+ settleReject(err instanceof PegelNetworkError ? err : new PegelNetworkError(err.message, { cause: err }));
77
111
  });
78
112
  if (request.body !== undefined)
79
113
  req.write(request.body);
@@ -1 +1 @@
1
- {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../../../src/client/http.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maschinenlesbar.org/pegel-online-cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "TypeScript API client and CLI for the open PEGELONLINE water-level REST API (pegelonline.wsv.de)",
5
5
  "type": "module",
6
6
  "bin": {