@maschinenlesbar.org/luftqualitaet-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.
- package/CONTRIBUTING.md +25 -0
- package/LICENSE +661 -0
- package/LICENSING.md +47 -0
- package/README.md +208 -0
- package/dist/src/cli/commands/data.d.ts +4 -0
- package/dist/src/cli/commands/data.d.ts.map +1 -0
- package/dist/src/cli/commands/data.js +152 -0
- package/dist/src/cli/commands/data.js.map +1 -0
- package/dist/src/cli/commands/reference.d.ts +4 -0
- package/dist/src/cli/commands/reference.d.ts.map +1 -0
- package/dist/src/cli/commands/reference.js +33 -0
- package/dist/src/cli/commands/reference.js.map +1 -0
- package/dist/src/cli/index.d.ts +3 -0
- package/dist/src/cli/index.d.ts.map +1 -0
- package/dist/src/cli/index.js +6 -0
- package/dist/src/cli/index.js.map +1 -0
- package/dist/src/cli/io.d.ts +13 -0
- package/dist/src/cli/io.d.ts.map +1 -0
- package/dist/src/cli/io.js +7 -0
- package/dist/src/cli/io.js.map +1 -0
- package/dist/src/cli/program.d.ts +7 -0
- package/dist/src/cli/program.d.ts.map +1 -0
- package/dist/src/cli/program.js +52 -0
- package/dist/src/cli/program.js.map +1 -0
- package/dist/src/cli/run.d.ts +3 -0
- package/dist/src/cli/run.d.ts.map +1 -0
- package/dist/src/cli/run.js +48 -0
- package/dist/src/cli/run.js.map +1 -0
- package/dist/src/cli/shared.d.ts +65 -0
- package/dist/src/cli/shared.d.ts.map +1 -0
- package/dist/src/cli/shared.js +142 -0
- package/dist/src/cli/shared.js.map +1 -0
- package/dist/src/client/client.d.ts +30 -0
- package/dist/src/client/client.d.ts.map +1 -0
- package/dist/src/client/client.js +76 -0
- package/dist/src/client/client.js.map +1 -0
- package/dist/src/client/engine.d.ts +54 -0
- package/dist/src/client/engine.d.ts.map +1 -0
- package/dist/src/client/engine.js +117 -0
- package/dist/src/client/engine.js.map +1 -0
- package/dist/src/client/enums.d.ts +13 -0
- package/dist/src/client/enums.d.ts.map +1 -0
- package/dist/src/client/enums.js +17 -0
- package/dist/src/client/enums.js.map +1 -0
- package/dist/src/client/errors.d.ts +33 -0
- package/dist/src/client/errors.d.ts.map +1 -0
- package/dist/src/client/errors.js +40 -0
- package/dist/src/client/errors.js.map +1 -0
- package/dist/src/client/http.d.ts +26 -0
- package/dist/src/client/http.d.ts.map +1 -0
- package/dist/src/client/http.js +111 -0
- package/dist/src/client/http.js.map +1 -0
- package/dist/src/client/index.d.ts +11 -0
- package/dist/src/client/index.d.ts.map +1 -0
- package/dist/src/client/index.js +9 -0
- package/dist/src/client/index.js.map +1 -0
- package/dist/src/client/query.d.ts +9 -0
- package/dist/src/client/query.d.ts.map +1 -0
- package/dist/src/client/query.js +33 -0
- package/dist/src/client/query.js.map +1 -0
- package/dist/src/client/types.d.ts +57 -0
- package/dist/src/client/types.d.ts.map +1 -0
- package/dist/src/client/types.js +8 -0
- package/dist/src/client/types.js.map +1 -0
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -0
- package/package.json +66 -0
|
@@ -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 { LuftApiError, LuftError } 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 LuftApiError) {
|
|
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 LuftError) {
|
|
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,YAAY,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAE9D;;;;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,YAAY,EAAE,CAAC;YAChC,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,SAAS,EAAE,CAAC;YAC7B,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,65 @@
|
|
|
1
|
+
import type { CliDeps } from "./io.js";
|
|
2
|
+
import type { EngineOptions } from "../client/engine.js";
|
|
3
|
+
import type { IndexKind, Lang } from "../client/enums.js";
|
|
4
|
+
/** commander value-parser: a non-negative integer. */
|
|
5
|
+
export declare function parseIntArg(value: string): number;
|
|
6
|
+
/**
|
|
7
|
+
* commander value-parser: a positive integer (>= 1). Used for ids — station,
|
|
8
|
+
* component and scope ids are 1-based in this API, so `0` is a user error that
|
|
9
|
+
* should be caught locally rather than sent.
|
|
10
|
+
*/
|
|
11
|
+
export declare function parsePositiveIntArg(value: string): number;
|
|
12
|
+
/**
|
|
13
|
+
* commander value-parser: an hour in the API's hour-ending range `1..24`.
|
|
14
|
+
* (The UBA API uses hour-ending times; `0` and `> 24` are invalid.)
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseHour(value: string): number;
|
|
17
|
+
/** commander value-parser: a four-digit year, `>= 2016` (the API's earliest). */
|
|
18
|
+
export declare function parseYear(value: string): number;
|
|
19
|
+
/**
|
|
20
|
+
* commander value-parser for `--lang`. Rejects a flag-like value (one starting
|
|
21
|
+
* with `-`): commander would otherwise consume the *next* option (e.g. `--index`)
|
|
22
|
+
* as this option's value, producing a confusing downstream "too many arguments"
|
|
23
|
+
* error. Membership in the allowed set is still validated later by `lang()`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseLangArg(value: string): string;
|
|
26
|
+
/** commander value-parser for `--index`; see `parseLangArg`. */
|
|
27
|
+
export declare function parseIndexArg(value: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Validate a positional argument against an allowed set (commander does not
|
|
30
|
+
* support .choices() on positional args). Throws a LuftError so run() prints a
|
|
31
|
+
* clear message and exits 1.
|
|
32
|
+
*/
|
|
33
|
+
export declare function assertEnum<T extends string>(value: string, allowed: readonly T[], argName: string): T;
|
|
34
|
+
/** Resolve and validate the optional `--lang` option shared by many commands. */
|
|
35
|
+
export declare function lang(opts: Record<string, unknown>): Lang | undefined;
|
|
36
|
+
/** Resolve and validate the optional `--index` option shared by many commands. */
|
|
37
|
+
export declare function index(opts: Record<string, unknown>): IndexKind | undefined;
|
|
38
|
+
export interface GlobalOptions {
|
|
39
|
+
baseUrl?: string;
|
|
40
|
+
timeout?: number;
|
|
41
|
+
userAgent?: string;
|
|
42
|
+
maxRetries?: number;
|
|
43
|
+
maxResponseBytes?: number;
|
|
44
|
+
compact?: boolean;
|
|
45
|
+
}
|
|
46
|
+
/** Translate resolved global CLI options into client EngineOptions. */
|
|
47
|
+
export declare function toEngineOptions(global: GlobalOptions): EngineOptions;
|
|
48
|
+
/** Render a JSON value to stdout, pretty by default, compact with --compact. */
|
|
49
|
+
export declare function renderJson(deps: CliDeps, global: GlobalOptions, value: unknown): void;
|
|
50
|
+
export interface ActionContext {
|
|
51
|
+
client: ReturnType<CliDeps["createClient"]>;
|
|
52
|
+
global: GlobalOptions;
|
|
53
|
+
/** This command's own parsed options. */
|
|
54
|
+
opts: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Wrap an async command action with consistent global-option resolution and
|
|
58
|
+
* client construction. The callback receives a context (client + resolved global
|
|
59
|
+
* options + this command's options) and the command's positional arguments.
|
|
60
|
+
*
|
|
61
|
+
* Commander invokes actions as (arg1, ..., argN, options, command); we slice off
|
|
62
|
+
* the trailing options object and command instance to recover the positionals.
|
|
63
|
+
*/
|
|
64
|
+
export declare function action(deps: CliDeps, fn: (ctx: ActionContext, positionals: string[]) => Promise<void>): (...args: unknown[]) => Promise<void>;
|
|
65
|
+
//# 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,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAmB1D,sDAAsD;AACtD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMzD;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED,iFAAiF;AACjF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD;AAED,gEAAgE;AAChE,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKnD;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,iFAAiF;AACjF,wBAAgB,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAIpE;AAED,kFAAkF;AAClF,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,GAAG,SAAS,CAI1E;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"}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Shared helpers used across CLI command groups: option parsers, the global
|
|
2
|
+
// option resolver, and the JSON result renderer.
|
|
3
|
+
import { InvalidArgumentError } from "commander";
|
|
4
|
+
import { LuftError } from "../client/errors.js";
|
|
5
|
+
import { IndexValues, LangValues } from "../client/enums.js";
|
|
6
|
+
/**
|
|
7
|
+
* Strictly parse a plain decimal integer string into a number.
|
|
8
|
+
*
|
|
9
|
+
* Unlike `Number()`, this rejects hex (`0x..`), binary (`0b..`), octal (`0o..`),
|
|
10
|
+
* scientific (`1e3`), explicit-sign (`+5`), and whitespace-padded forms: only an
|
|
11
|
+
* optional leading `-` followed by ASCII digits is accepted. It also rejects
|
|
12
|
+
* values that cannot be represented exactly as a JS integer (`> 2^53 - 1`), so a
|
|
13
|
+
* user-supplied id is never silently rounded before being sent. Returns
|
|
14
|
+
* `undefined` on any non-conforming input; callers map that to a clear error.
|
|
15
|
+
*/
|
|
16
|
+
function parseStrictInt(value) {
|
|
17
|
+
if (!/^-?\d+$/.test(value))
|
|
18
|
+
return undefined;
|
|
19
|
+
const n = Number(value);
|
|
20
|
+
if (!Number.isSafeInteger(n))
|
|
21
|
+
return undefined;
|
|
22
|
+
return n;
|
|
23
|
+
}
|
|
24
|
+
/** commander value-parser: a non-negative integer. */
|
|
25
|
+
export function parseIntArg(value) {
|
|
26
|
+
const n = parseStrictInt(value);
|
|
27
|
+
if (n === undefined || n < 0) {
|
|
28
|
+
throw new InvalidArgumentError("Expected a non-negative integer.");
|
|
29
|
+
}
|
|
30
|
+
return n;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* commander value-parser: a positive integer (>= 1). Used for ids — station,
|
|
34
|
+
* component and scope ids are 1-based in this API, so `0` is a user error that
|
|
35
|
+
* should be caught locally rather than sent.
|
|
36
|
+
*/
|
|
37
|
+
export function parsePositiveIntArg(value) {
|
|
38
|
+
const n = parseStrictInt(value);
|
|
39
|
+
if (n === undefined || n < 1) {
|
|
40
|
+
throw new InvalidArgumentError("Expected a positive integer (>= 1).");
|
|
41
|
+
}
|
|
42
|
+
return n;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* commander value-parser: an hour in the API's hour-ending range `1..24`.
|
|
46
|
+
* (The UBA API uses hour-ending times; `0` and `> 24` are invalid.)
|
|
47
|
+
*/
|
|
48
|
+
export function parseHour(value) {
|
|
49
|
+
const n = parseStrictInt(value);
|
|
50
|
+
if (n === undefined || n < 1 || n > 24) {
|
|
51
|
+
throw new InvalidArgumentError("Expected an hour in the range 1..24.");
|
|
52
|
+
}
|
|
53
|
+
return n;
|
|
54
|
+
}
|
|
55
|
+
/** commander value-parser: a four-digit year, `>= 2016` (the API's earliest). */
|
|
56
|
+
export function parseYear(value) {
|
|
57
|
+
const n = parseStrictInt(value);
|
|
58
|
+
if (n === undefined || n < 2016 || n > 9999) {
|
|
59
|
+
throw new InvalidArgumentError("Expected a four-digit year >= 2016.");
|
|
60
|
+
}
|
|
61
|
+
return n;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* commander value-parser for `--lang`. Rejects a flag-like value (one starting
|
|
65
|
+
* with `-`): commander would otherwise consume the *next* option (e.g. `--index`)
|
|
66
|
+
* as this option's value, producing a confusing downstream "too many arguments"
|
|
67
|
+
* error. Membership in the allowed set is still validated later by `lang()`.
|
|
68
|
+
*/
|
|
69
|
+
export function parseLangArg(value) {
|
|
70
|
+
if (value.startsWith("-")) {
|
|
71
|
+
throw new InvalidArgumentError("Option '--lang' requires a value (e.g. de | en).");
|
|
72
|
+
}
|
|
73
|
+
return value;
|
|
74
|
+
}
|
|
75
|
+
/** commander value-parser for `--index`; see `parseLangArg`. */
|
|
76
|
+
export function parseIndexArg(value) {
|
|
77
|
+
if (value.startsWith("-")) {
|
|
78
|
+
throw new InvalidArgumentError("Option '--index' requires a value (e.g. id | code).");
|
|
79
|
+
}
|
|
80
|
+
return value;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Validate a positional argument against an allowed set (commander does not
|
|
84
|
+
* support .choices() on positional args). Throws a LuftError so run() prints a
|
|
85
|
+
* clear message and exits 1.
|
|
86
|
+
*/
|
|
87
|
+
export function assertEnum(value, allowed, argName) {
|
|
88
|
+
if (!allowed.includes(value)) {
|
|
89
|
+
throw new LuftError(`Invalid ${argName} "${value}". Expected one of: ${allowed.join(", ")}.`);
|
|
90
|
+
}
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
/** Resolve and validate the optional `--lang` option shared by many commands. */
|
|
94
|
+
export function lang(opts) {
|
|
95
|
+
return opts["lang"] === undefined
|
|
96
|
+
? undefined
|
|
97
|
+
: assertEnum(String(opts["lang"]), LangValues, "lang");
|
|
98
|
+
}
|
|
99
|
+
/** Resolve and validate the optional `--index` option shared by many commands. */
|
|
100
|
+
export function index(opts) {
|
|
101
|
+
return opts["index"] === undefined
|
|
102
|
+
? undefined
|
|
103
|
+
: assertEnum(String(opts["index"]), IndexValues, "index");
|
|
104
|
+
}
|
|
105
|
+
/** Translate resolved global CLI options into client EngineOptions. */
|
|
106
|
+
export function toEngineOptions(global) {
|
|
107
|
+
const options = {};
|
|
108
|
+
if (global.baseUrl !== undefined)
|
|
109
|
+
options.baseUrl = global.baseUrl;
|
|
110
|
+
if (global.timeout !== undefined)
|
|
111
|
+
options.timeoutMs = global.timeout;
|
|
112
|
+
if (global.userAgent !== undefined)
|
|
113
|
+
options.userAgent = global.userAgent;
|
|
114
|
+
if (global.maxRetries !== undefined)
|
|
115
|
+
options.maxRetries = global.maxRetries;
|
|
116
|
+
if (global.maxResponseBytes !== undefined)
|
|
117
|
+
options.maxResponseBytes = global.maxResponseBytes;
|
|
118
|
+
return options;
|
|
119
|
+
}
|
|
120
|
+
/** Render a JSON value to stdout, pretty by default, compact with --compact. */
|
|
121
|
+
export function renderJson(deps, global, value) {
|
|
122
|
+
const text = global.compact ? JSON.stringify(value) : JSON.stringify(value, null, 2);
|
|
123
|
+
deps.io.out(text);
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Wrap an async command action with consistent global-option resolution and
|
|
127
|
+
* client construction. The callback receives a context (client + resolved global
|
|
128
|
+
* options + this command's options) and the command's positional arguments.
|
|
129
|
+
*
|
|
130
|
+
* Commander invokes actions as (arg1, ..., argN, options, command); we slice off
|
|
131
|
+
* the trailing options object and command instance to recover the positionals.
|
|
132
|
+
*/
|
|
133
|
+
export function action(deps, fn) {
|
|
134
|
+
return async (...args) => {
|
|
135
|
+
const command = args[args.length - 1];
|
|
136
|
+
const positionals = args.slice(0, Math.max(0, args.length - 2));
|
|
137
|
+
const global = command.optsWithGlobals();
|
|
138
|
+
const client = deps.createClient(toEngineOptions(global));
|
|
139
|
+
await fn({ client, global, opts: command.opts() }, positionals);
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../../src/cli/shared.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type EngineOptions } from "./engine.js";
|
|
2
|
+
import type { AirDataResult, ListParams, WindowParams, MeasuresParams, YearComponentParams, ThresholdParams, MetaParams } from "./types.js";
|
|
3
|
+
import type { Lang } from "./enums.js";
|
|
4
|
+
export declare class LuftqualitaetClient {
|
|
5
|
+
private readonly engine;
|
|
6
|
+
constructor(options?: EngineOptions);
|
|
7
|
+
/** Air-quality index data for a station over a time window. */
|
|
8
|
+
airquality(params: WindowParams): Promise<AirDataResult>;
|
|
9
|
+
/** The available date range per station for air-quality data. */
|
|
10
|
+
airqualityLimits(): Promise<AirDataResult>;
|
|
11
|
+
/** Raw measurement data for a station over a window (optional component/scope). */
|
|
12
|
+
measures(params: MeasuresParams): Promise<AirDataResult>;
|
|
13
|
+
/** The available date range per scope/component/station for measurements. */
|
|
14
|
+
measuresLimits(): Promise<AirDataResult>;
|
|
15
|
+
/** Annual tabulations for a component and year (>= 2016). */
|
|
16
|
+
annualBalances(params: YearComponentParams): Promise<AirDataResult>;
|
|
17
|
+
/** Exceedance (Überschreitungen) data for a component and year. */
|
|
18
|
+
transgressions(params: YearComponentParams): Promise<AirDataResult>;
|
|
19
|
+
components(params?: ListParams): Promise<AirDataResult>;
|
|
20
|
+
networks(params?: ListParams): Promise<AirDataResult>;
|
|
21
|
+
scopes(params?: ListParams): Promise<AirDataResult>;
|
|
22
|
+
stationSettings(lang?: Lang): Promise<AirDataResult>;
|
|
23
|
+
stationTypes(lang?: Lang): Promise<AirDataResult>;
|
|
24
|
+
transgressionTypes(lang?: Lang): Promise<AirDataResult>;
|
|
25
|
+
/** Thresholds for a use (airquality | measure), optional component/scope. */
|
|
26
|
+
thresholds(params: ThresholdParams): Promise<AirDataResult>;
|
|
27
|
+
/** Combined metadata for a use (components, scopes, networks, stations, ...). */
|
|
28
|
+
meta(params: MetaParams): Promise<AirDataResult>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"AAMA,OAAO,EAAiB,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAEhE,OAAO,KAAK,EACV,aAAa,EACb,UAAU,EACV,YAAY,EACZ,cAAc,EACd,mBAAmB,EACnB,eAAe,EACf,UAAU,EACX,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAavC,qBAAa,mBAAmB;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;gBAE3B,OAAO,GAAE,aAAkB;IAMvC,+DAA+D;IAC/D,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxD,iEAAiE;IACjE,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC;IAI1C,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAIxD,6EAA6E;IAC7E,cAAc,IAAI,OAAO,CAAC,aAAa,CAAC;IAMxC,6DAA6D;IAC7D,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAInE,mEAAmE;IACnE,cAAc,CAAC,MAAM,EAAE,mBAAmB,GAAG,OAAO,CAAC,aAAa,CAAC;IAMnE,UAAU,CAAC,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAI3D,QAAQ,CAAC,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAIzD,MAAM,CAAC,MAAM,GAAE,UAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAIvD,eAAe,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC;IAIpD,YAAY,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC;IAIjD,kBAAkB,CAAC,IAAI,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC;IAIvD,6EAA6E;IAC7E,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,aAAa,CAAC;IAI3D,iFAAiF;IACjF,IAAI,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAGjD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// LuftqualitaetClient — a typed client over the open (no-auth) Air Data API of
|
|
2
|
+
// the Umweltbundesamt (https://www.umweltbundesamt.de/api/air_data/v3).
|
|
3
|
+
//
|
|
4
|
+
// client.components({ lang: "de" })
|
|
5
|
+
// client.airquality({ date_from: "2024-01-01", time_from: 1, date_to: "2024-01-01", time_to: 24, station: 143 })
|
|
6
|
+
import { RequestEngine } from "./engine.js";
|
|
7
|
+
const API = "/api/air_data/v3";
|
|
8
|
+
/** Drop undefined values so only the parameters the caller set are sent. */
|
|
9
|
+
function prune(params) {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const [k, v] of Object.entries(params)) {
|
|
12
|
+
if (v !== undefined)
|
|
13
|
+
out[k] = v;
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
export class LuftqualitaetClient {
|
|
18
|
+
engine;
|
|
19
|
+
constructor(options = {}) {
|
|
20
|
+
this.engine = new RequestEngine(options);
|
|
21
|
+
}
|
|
22
|
+
// --- Air-quality index & raw measures -------------------------------------
|
|
23
|
+
/** Air-quality index data for a station over a time window. */
|
|
24
|
+
airquality(params) {
|
|
25
|
+
return this.engine.getJson(`${API}/airquality/json`, prune({ ...params }));
|
|
26
|
+
}
|
|
27
|
+
/** The available date range per station for air-quality data. */
|
|
28
|
+
airqualityLimits() {
|
|
29
|
+
return this.engine.getJson(`${API}/airquality/limits`);
|
|
30
|
+
}
|
|
31
|
+
/** Raw measurement data for a station over a window (optional component/scope). */
|
|
32
|
+
measures(params) {
|
|
33
|
+
return this.engine.getJson(`${API}/measures/json`, prune({ ...params }));
|
|
34
|
+
}
|
|
35
|
+
/** The available date range per scope/component/station for measurements. */
|
|
36
|
+
measuresLimits() {
|
|
37
|
+
return this.engine.getJson(`${API}/measures/limits`);
|
|
38
|
+
}
|
|
39
|
+
// --- Aggregations ---------------------------------------------------------
|
|
40
|
+
/** Annual tabulations for a component and year (>= 2016). */
|
|
41
|
+
annualBalances(params) {
|
|
42
|
+
return this.engine.getJson(`${API}/annualbalances/json`, prune({ ...params }));
|
|
43
|
+
}
|
|
44
|
+
/** Exceedance (Überschreitungen) data for a component and year. */
|
|
45
|
+
transgressions(params) {
|
|
46
|
+
return this.engine.getJson(`${API}/transgressions/json`, prune({ ...params }));
|
|
47
|
+
}
|
|
48
|
+
// --- Reference lists ------------------------------------------------------
|
|
49
|
+
components(params = {}) {
|
|
50
|
+
return this.engine.getJson(`${API}/components/json`, prune({ ...params }));
|
|
51
|
+
}
|
|
52
|
+
networks(params = {}) {
|
|
53
|
+
return this.engine.getJson(`${API}/networks/json`, prune({ ...params }));
|
|
54
|
+
}
|
|
55
|
+
scopes(params = {}) {
|
|
56
|
+
return this.engine.getJson(`${API}/scopes/json`, prune({ ...params }));
|
|
57
|
+
}
|
|
58
|
+
stationSettings(lang) {
|
|
59
|
+
return this.engine.getJson(`${API}/stationsettings/json`, prune({ lang }));
|
|
60
|
+
}
|
|
61
|
+
stationTypes(lang) {
|
|
62
|
+
return this.engine.getJson(`${API}/stationtypes/json`, prune({ lang }));
|
|
63
|
+
}
|
|
64
|
+
transgressionTypes(lang) {
|
|
65
|
+
return this.engine.getJson(`${API}/transgressiontypes/json`, prune({ lang }));
|
|
66
|
+
}
|
|
67
|
+
/** Thresholds for a use (airquality | measure), optional component/scope. */
|
|
68
|
+
thresholds(params) {
|
|
69
|
+
return this.engine.getJson(`${API}/thresholds/json`, prune({ ...params }));
|
|
70
|
+
}
|
|
71
|
+
/** Combined metadata for a use (components, scopes, networks, stations, ...). */
|
|
72
|
+
meta(params) {
|
|
73
|
+
return this.engine.getJson(`${API}/meta/json`, prune({ ...params }));
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { type Transport } from "./http.js";
|
|
2
|
+
import { type QueryParams } from "./query.js";
|
|
3
|
+
export declare const DEFAULT_BASE_URL = "https://www.umweltbundesamt.de";
|
|
4
|
+
export interface RawResponse {
|
|
5
|
+
data: Buffer;
|
|
6
|
+
contentType: string;
|
|
7
|
+
status: number;
|
|
8
|
+
}
|
|
9
|
+
export interface EngineOptions {
|
|
10
|
+
/** Base URL of the API. Defaults to https://www.umweltbundesamt.de */
|
|
11
|
+
baseUrl?: string;
|
|
12
|
+
/** Swappable transport. Defaults to the built-in node http/https transport. */
|
|
13
|
+
transport?: Transport;
|
|
14
|
+
/** Value of the User-Agent header. */
|
|
15
|
+
userAgent?: string;
|
|
16
|
+
/** Per-request timeout in milliseconds (0 disables). */
|
|
17
|
+
timeoutMs?: number;
|
|
18
|
+
/** Number of automatic retries for transient (429/503) responses. */
|
|
19
|
+
maxRetries?: number;
|
|
20
|
+
/** Base backoff between retries in milliseconds (grows linearly). */
|
|
21
|
+
retryDelayMs?: number;
|
|
22
|
+
/** Number of HTTP redirects (301/302/303/307/308) to follow. Defaults to 5. */
|
|
23
|
+
maxRedirects?: number;
|
|
24
|
+
/**
|
|
25
|
+
* Hard cap on response body size in bytes (defends against memory exhaustion
|
|
26
|
+
* from a hostile/buggy endpoint). Defaults to 100 MiB; set to 0 for no limit.
|
|
27
|
+
*/
|
|
28
|
+
maxResponseBytes?: number;
|
|
29
|
+
/** Injectable sleep, primarily for deterministic tests. */
|
|
30
|
+
sleep?: (ms: number) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
export declare class RequestEngine {
|
|
33
|
+
private readonly baseUrl;
|
|
34
|
+
private readonly transport;
|
|
35
|
+
private readonly userAgent;
|
|
36
|
+
private readonly timeoutMs;
|
|
37
|
+
private readonly maxRetries;
|
|
38
|
+
private readonly retryDelayMs;
|
|
39
|
+
private readonly maxRedirects;
|
|
40
|
+
private readonly maxResponseBytes;
|
|
41
|
+
private readonly sleep;
|
|
42
|
+
constructor(options?: EngineOptions);
|
|
43
|
+
/** Build a fully-qualified URL from a path and optional query parameters. */
|
|
44
|
+
buildUrl(path: string, query?: QueryParams): string;
|
|
45
|
+
/** Perform a request with Accept negotiation and transient-error retries. */
|
|
46
|
+
request(method: string, path: string, options?: {
|
|
47
|
+
query?: QueryParams;
|
|
48
|
+
accept: string;
|
|
49
|
+
}): Promise<RawResponse>;
|
|
50
|
+
/** Perform a GET expecting JSON and parse it into `T`. */
|
|
51
|
+
getJson<T>(path: string, query?: QueryParams): Promise<T>;
|
|
52
|
+
private toApiError;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +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;IAYvC,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;CAYnB"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// The request engine: turns logical (method, path, query) calls into HTTP
|
|
2
|
+
// requests via a Transport, applies retry/backoff for transient statuses
|
|
3
|
+
// (429, 503), and decodes responses.
|
|
4
|
+
import { nodeHttpTransport } from "./http.js";
|
|
5
|
+
import { buildQueryString } from "./query.js";
|
|
6
|
+
import { LuftApiError, LuftParseError } from "./errors.js";
|
|
7
|
+
export const DEFAULT_BASE_URL = "https://www.umweltbundesamt.de";
|
|
8
|
+
const DEFAULT_USER_AGENT = "luftqualitaet-cli";
|
|
9
|
+
const DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
|
|
10
|
+
const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
11
|
+
export class RequestEngine {
|
|
12
|
+
baseUrl;
|
|
13
|
+
transport;
|
|
14
|
+
userAgent;
|
|
15
|
+
timeoutMs;
|
|
16
|
+
maxRetries;
|
|
17
|
+
retryDelayMs;
|
|
18
|
+
maxRedirects;
|
|
19
|
+
maxResponseBytes;
|
|
20
|
+
sleep;
|
|
21
|
+
constructor(options = {}) {
|
|
22
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
23
|
+
this.transport = options.transport ?? nodeHttpTransport;
|
|
24
|
+
this.userAgent = options.userAgent ?? DEFAULT_USER_AGENT;
|
|
25
|
+
this.timeoutMs = options.timeoutMs ?? 30_000;
|
|
26
|
+
this.maxRetries = options.maxRetries ?? 2;
|
|
27
|
+
this.retryDelayMs = options.retryDelayMs ?? 200;
|
|
28
|
+
this.maxRedirects = options.maxRedirects ?? 5;
|
|
29
|
+
this.maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
|
|
30
|
+
this.sleep = options.sleep ?? realSleep;
|
|
31
|
+
}
|
|
32
|
+
/** Build a fully-qualified URL from a path and optional query parameters. */
|
|
33
|
+
buildUrl(path, query) {
|
|
34
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
35
|
+
const qs = query ? buildQueryString(query) : "";
|
|
36
|
+
return `${this.baseUrl}${normalizedPath}${qs ? `?${qs}` : ""}`;
|
|
37
|
+
}
|
|
38
|
+
/** Perform a request with Accept negotiation and transient-error retries. */
|
|
39
|
+
async request(method, path, options = { accept: "application/json" }) {
|
|
40
|
+
let url = this.buildUrl(path, options.query);
|
|
41
|
+
const headers = {
|
|
42
|
+
Accept: options.accept,
|
|
43
|
+
"User-Agent": this.userAgent,
|
|
44
|
+
};
|
|
45
|
+
let attempt = 0;
|
|
46
|
+
let redirects = 0;
|
|
47
|
+
// attempts = initial try + maxRetries (redirects are counted separately)
|
|
48
|
+
for (;;) {
|
|
49
|
+
const response = await this.transport({
|
|
50
|
+
method,
|
|
51
|
+
url,
|
|
52
|
+
headers,
|
|
53
|
+
timeoutMs: this.timeoutMs,
|
|
54
|
+
...(this.maxResponseBytes > 0 ? { maxResponseBytes: this.maxResponseBytes } : {}),
|
|
55
|
+
});
|
|
56
|
+
const status = response.status;
|
|
57
|
+
const retryable = status === 429 || status === 503;
|
|
58
|
+
if (retryable && attempt < this.maxRetries) {
|
|
59
|
+
attempt += 1;
|
|
60
|
+
await this.sleep(this.retryDelayMs * attempt);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
// Follow redirects, resolving the Location relative to the current URL.
|
|
64
|
+
if (status >= 300 && status < 400 && redirects < this.maxRedirects) {
|
|
65
|
+
const location = response.headers["location"];
|
|
66
|
+
if (typeof location === "string" && location.length > 0) {
|
|
67
|
+
const target = new URL(location, url);
|
|
68
|
+
// Cross-origin redirect: strip request headers so any sensitive
|
|
69
|
+
// header (e.g. an Authorization/token added later) is never leaked to
|
|
70
|
+
// a different origin. Today only Accept/User-Agent are sent, so we
|
|
71
|
+
// re-add those benign defaults to keep negotiation working.
|
|
72
|
+
if (target.origin !== new URL(url).origin) {
|
|
73
|
+
for (const key of Object.keys(headers))
|
|
74
|
+
delete headers[key];
|
|
75
|
+
headers["Accept"] = options.accept;
|
|
76
|
+
headers["User-Agent"] = this.userAgent;
|
|
77
|
+
}
|
|
78
|
+
url = target.toString();
|
|
79
|
+
redirects += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
const contentType = String(response.headers["content-type"] ?? "");
|
|
84
|
+
if (status < 200 || status >= 300) {
|
|
85
|
+
throw this.toApiError(method, url, status, response.body);
|
|
86
|
+
}
|
|
87
|
+
return { data: response.body, contentType, status };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/** Perform a GET expecting JSON and parse it into `T`. */
|
|
91
|
+
async getJson(path, query) {
|
|
92
|
+
const res = await this.request("GET", path, { query, accept: "application/json" });
|
|
93
|
+
const text = res.data.toString("utf8");
|
|
94
|
+
try {
|
|
95
|
+
return JSON.parse(text);
|
|
96
|
+
}
|
|
97
|
+
catch (cause) {
|
|
98
|
+
throw new LuftParseError(`Failed to parse JSON response from ${path}`, { cause });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
toApiError(method, url, status, body) {
|
|
102
|
+
const text = body.toString("utf8");
|
|
103
|
+
let detail;
|
|
104
|
+
try {
|
|
105
|
+
const parsed = JSON.parse(text);
|
|
106
|
+
if (parsed && typeof parsed.detail === "string")
|
|
107
|
+
detail = parsed.detail;
|
|
108
|
+
else if (parsed && typeof parsed.message === "string")
|
|
109
|
+
detail = parsed.message;
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
// Non-JSON error body; leave detail undefined.
|
|
113
|
+
}
|
|
114
|
+
return new LuftApiError({ status, url, method, body: text, detail });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../../src/client/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Response language. */
|
|
2
|
+
export declare const LangValues: readonly ["de", "en"];
|
|
3
|
+
export type Lang = (typeof LangValues)[number];
|
|
4
|
+
/** How reference lists are keyed in the response. */
|
|
5
|
+
export declare const IndexValues: readonly ["id", "code"];
|
|
6
|
+
export type IndexKind = (typeof IndexValues)[number];
|
|
7
|
+
/** `use` values for the combined metadata endpoint. */
|
|
8
|
+
export declare const MetaUseValues: readonly ["airquality", "measure", "transgression", "annualbalance", "map"];
|
|
9
|
+
export type MetaUse = (typeof MetaUseValues)[number];
|
|
10
|
+
/** `use` values for the thresholds endpoint. */
|
|
11
|
+
export declare const ThresholdUseValues: readonly ["airquality", "measure"];
|
|
12
|
+
export type ThresholdUse = (typeof ThresholdUseValues)[number];
|
|
13
|
+
//# sourceMappingURL=enums.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/client/enums.ts"],"names":[],"mappings":"AAGA,yBAAyB;AACzB,eAAO,MAAM,UAAU,uBAAwB,CAAC;AAChD,MAAM,MAAM,IAAI,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAC;AAE/C,qDAAqD;AACrD,eAAO,MAAM,WAAW,yBAA0B,CAAC;AACnD,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,WAAW,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,uDAAuD;AACvD,eAAO,MAAM,aAAa,6EAMhB,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAErD,gDAAgD;AAChD,eAAO,MAAM,kBAAkB,oCAAqC,CAAC;AACrE,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Enum-like value sets. These const arrays double as runtime CLI choice
|
|
2
|
+
// validators and as TS union types.
|
|
3
|
+
/** Response language. */
|
|
4
|
+
export const LangValues = ["de", "en"];
|
|
5
|
+
/** How reference lists are keyed in the response. */
|
|
6
|
+
export const IndexValues = ["id", "code"];
|
|
7
|
+
/** `use` values for the combined metadata endpoint. */
|
|
8
|
+
export const MetaUseValues = [
|
|
9
|
+
"airquality",
|
|
10
|
+
"measure",
|
|
11
|
+
"transgression",
|
|
12
|
+
"annualbalance",
|
|
13
|
+
"map",
|
|
14
|
+
];
|
|
15
|
+
/** `use` values for the thresholds endpoint. */
|
|
16
|
+
export const ThresholdUseValues = ["airquality", "measure"];
|
|
17
|
+
//# sourceMappingURL=enums.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enums.js","sourceRoot":"","sources":["../../../src/client/enums.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,oCAAoC;AAEpC,yBAAyB;AACzB,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,CAAU,CAAC;AAGhD,qDAAqD;AACrD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,MAAM,CAAU,CAAC;AAGnD,uDAAuD;AACvD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,YAAY;IACZ,SAAS;IACT,eAAe;IACf,eAAe;IACf,KAAK;CACG,CAAC;AAGX,gDAAgD;AAChD,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,SAAS,CAAU,CAAC"}
|