@maschinenlesbar.org/nina-warnungen-cli 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CONTRIBUTING.md +25 -0
  2. package/LICENSE +661 -0
  3. package/LICENSING.md +47 -0
  4. package/README.md +227 -0
  5. package/dist/src/cli/commands/misc.d.ts +4 -0
  6. package/dist/src/cli/commands/misc.d.ts.map +1 -0
  7. package/dist/src/cli/commands/misc.js +36 -0
  8. package/dist/src/cli/commands/misc.js.map +1 -0
  9. package/dist/src/cli/commands/warnings.d.ts +4 -0
  10. package/dist/src/cli/commands/warnings.d.ts.map +1 -0
  11. package/dist/src/cli/commands/warnings.js +38 -0
  12. package/dist/src/cli/commands/warnings.js.map +1 -0
  13. package/dist/src/cli/index.d.ts +3 -0
  14. package/dist/src/cli/index.d.ts.map +1 -0
  15. package/dist/src/cli/index.js +6 -0
  16. package/dist/src/cli/index.js.map +1 -0
  17. package/dist/src/cli/io.d.ts +17 -0
  18. package/dist/src/cli/io.d.ts.map +1 -0
  19. package/dist/src/cli/io.js +22 -0
  20. package/dist/src/cli/io.js.map +1 -0
  21. package/dist/src/cli/program.d.ts +7 -0
  22. package/dist/src/cli/program.d.ts.map +1 -0
  23. package/dist/src/cli/program.js +53 -0
  24. package/dist/src/cli/program.js.map +1 -0
  25. package/dist/src/cli/run.d.ts +3 -0
  26. package/dist/src/cli/run.d.ts.map +1 -0
  27. package/dist/src/cli/run.js +56 -0
  28. package/dist/src/cli/run.js.map +1 -0
  29. package/dist/src/cli/shared.d.ts +69 -0
  30. package/dist/src/cli/shared.d.ts.map +1 -0
  31. package/dist/src/cli/shared.js +133 -0
  32. package/dist/src/cli/shared.js.map +1 -0
  33. package/dist/src/client/client.d.ts +45 -0
  34. package/dist/src/client/client.d.ts.map +1 -0
  35. package/dist/src/client/client.js +81 -0
  36. package/dist/src/client/client.js.map +1 -0
  37. package/dist/src/client/engine.d.ts +53 -0
  38. package/dist/src/client/engine.d.ts.map +1 -0
  39. package/dist/src/client/engine.js +105 -0
  40. package/dist/src/client/engine.js.map +1 -0
  41. package/dist/src/client/enums.d.ts +15 -0
  42. package/dist/src/client/enums.d.ts.map +1 -0
  43. package/dist/src/client/enums.js +15 -0
  44. package/dist/src/client/enums.js.map +1 -0
  45. package/dist/src/client/errors.d.ts +36 -0
  46. package/dist/src/client/errors.d.ts.map +1 -0
  47. package/dist/src/client/errors.js +60 -0
  48. package/dist/src/client/errors.js.map +1 -0
  49. package/dist/src/client/http.d.ts +26 -0
  50. package/dist/src/client/http.d.ts.map +1 -0
  51. package/dist/src/client/http.js +107 -0
  52. package/dist/src/client/http.js.map +1 -0
  53. package/dist/src/client/index.d.ts +11 -0
  54. package/dist/src/client/index.d.ts.map +1 -0
  55. package/dist/src/client/index.js +9 -0
  56. package/dist/src/client/index.js.map +1 -0
  57. package/dist/src/client/query.d.ts +9 -0
  58. package/dist/src/client/query.d.ts.map +1 -0
  59. package/dist/src/client/query.js +33 -0
  60. package/dist/src/client/query.js.map +1 -0
  61. package/dist/src/client/types.d.ts +48 -0
  62. package/dist/src/client/types.d.ts.map +1 -0
  63. package/dist/src/client/types.js +7 -0
  64. package/dist/src/client/types.js.map +1 -0
  65. package/dist/src/index.d.ts +2 -0
  66. package/dist/src/index.d.ts.map +1 -0
  67. package/dist/src/index.js +3 -0
  68. package/dist/src/index.js.map +1 -0
  69. package/package.json +67 -0
@@ -0,0 +1,69 @@
1
+ import type { CliDeps } from "./io.js";
2
+ import type { EngineOptions, RawResponse } from "../client/engine.js";
3
+ /**
4
+ * commander value-parser: a plain non-negative decimal integer.
5
+ *
6
+ * Only accepts an optional leading run of digits with no sign, decimal point,
7
+ * whitespace, exponent or radix prefix. This deliberately rejects forms that
8
+ * `Number()` would otherwise coerce (e.g. "", " 5", "0x10", "1e3", "5.0",
9
+ * "Infinity"), so a typo never silently becomes a surprising value.
10
+ */
11
+ export declare function parseIntArg(value: string): number;
12
+ /**
13
+ * Validate a positional argument against an allowed set (commander does not
14
+ * support .choices() on positional args). Throws a NinaError so run() prints a
15
+ * clear message and exits 1.
16
+ */
17
+ export declare function assertEnum<T extends string>(value: string, allowed: readonly T[], argName: string): T;
18
+ /**
19
+ * Validate a required free-form positional (an identifier or region key). An
20
+ * empty or whitespace-only value would build a path like `dashboard/.json` and
21
+ * come back as a remote 404 for what is really a local input error; reject it
22
+ * up front with a clear message (exit 1) instead.
23
+ */
24
+ export declare function requireIdentifier(value: string, argName: string): string;
25
+ export interface GlobalOptions {
26
+ baseUrl?: string;
27
+ timeout?: number;
28
+ userAgent?: string;
29
+ maxRetries?: number;
30
+ maxResponseBytes?: number;
31
+ compact?: boolean;
32
+ output?: string;
33
+ }
34
+ /** Translate resolved global CLI options into client EngineOptions. */
35
+ export declare function toEngineOptions(global: GlobalOptions): EngineOptions;
36
+ /**
37
+ * Render a JSON value, pretty by default, compact with --compact. Writes to the
38
+ * file given by --output when present (so `-o` is honoured for JSON commands, not
39
+ * only raw downloads), otherwise to stdout. When writing a file we print a short
40
+ * confirmation to stderr so stdout stays clean for piping.
41
+ */
42
+ export declare function renderJson(deps: CliDeps, global: GlobalOptions, value: unknown): void;
43
+ /**
44
+ * Render a raw (binary/text) download. Writes to the file given by --output, or
45
+ * to stdout otherwise. Prints a short confirmation to stderr when writing a file
46
+ * so stdout stays clean for piping.
47
+ *
48
+ * `expectContentType` is an optional substring sanity check. A misconfigured
49
+ * gateway can return an HTML error page with a 200 status; without this the bytes
50
+ * would be saved silently to e.g. `out.geojson`. We do not fail (the body may be
51
+ * valid with an unusual type), but we warn to stderr so the surprise is visible.
52
+ */
53
+ export declare function renderRaw(deps: CliDeps, global: GlobalOptions, response: RawResponse, expectContentType?: string): void;
54
+ export interface ActionContext {
55
+ client: ReturnType<CliDeps["createClient"]>;
56
+ global: GlobalOptions;
57
+ /** This command's own parsed options. */
58
+ opts: Record<string, unknown>;
59
+ }
60
+ /**
61
+ * Wrap an async command action with consistent global-option resolution and
62
+ * client construction. The callback receives a context (client + resolved global
63
+ * options + this command's options) and the command's positional arguments.
64
+ *
65
+ * Commander invokes actions as (arg1, ..., argN, options, command); we slice off
66
+ * the trailing options object and command instance to recover the positionals.
67
+ */
68
+ export declare function action(deps: CliDeps, fn: (ctx: ActionContext, positionals: string[]) => Promise<void>): (...args: unknown[]) => Promise<void>;
69
+ //# 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,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;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAKxE;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"}
@@ -0,0 +1,133 @@
1
+ // Shared helpers used across CLI command groups: option parsers, the global
2
+ // option resolver, and the two result-rendering paths (JSON and raw download).
3
+ import { InvalidArgumentError } from "commander";
4
+ import { NinaError } from "../client/errors.js";
5
+ /**
6
+ * commander value-parser: a plain non-negative decimal integer.
7
+ *
8
+ * Only accepts an optional leading run of digits with no sign, decimal point,
9
+ * whitespace, exponent or radix prefix. This deliberately rejects forms that
10
+ * `Number()` would otherwise coerce (e.g. "", " 5", "0x10", "1e3", "5.0",
11
+ * "Infinity"), so a typo never silently becomes a surprising value.
12
+ */
13
+ export function parseIntArg(value) {
14
+ if (!/^[0-9]+$/.test(value)) {
15
+ throw new InvalidArgumentError("Expected a non-negative integer.");
16
+ }
17
+ const n = Number(value);
18
+ if (!Number.isSafeInteger(n)) {
19
+ throw new InvalidArgumentError("Value is too large.");
20
+ }
21
+ return n;
22
+ }
23
+ /**
24
+ * Validate a positional argument against an allowed set (commander does not
25
+ * support .choices() on positional args). Throws a NinaError so run() prints a
26
+ * clear message and exits 1.
27
+ */
28
+ export function assertEnum(value, allowed, argName) {
29
+ if (!allowed.includes(value)) {
30
+ throw new NinaError(`Invalid ${argName} "${value}". Expected one of: ${allowed.join(", ")}.`);
31
+ }
32
+ return value;
33
+ }
34
+ /**
35
+ * Validate a required free-form positional (an identifier or region key). An
36
+ * empty or whitespace-only value would build a path like `dashboard/.json` and
37
+ * come back as a remote 404 for what is really a local input error; reject it
38
+ * up front with a clear message (exit 1) instead.
39
+ */
40
+ export function requireIdentifier(value, argName) {
41
+ if (value.trim() === "") {
42
+ throw new NinaError(`A non-empty ${argName} is required.`);
43
+ }
44
+ return value;
45
+ }
46
+ /** Translate resolved global CLI options into client EngineOptions. */
47
+ export function toEngineOptions(global) {
48
+ const options = {};
49
+ if (global.baseUrl !== undefined)
50
+ options.baseUrl = global.baseUrl;
51
+ if (global.timeout !== undefined)
52
+ options.timeoutMs = global.timeout;
53
+ if (global.userAgent !== undefined)
54
+ options.userAgent = global.userAgent;
55
+ if (global.maxRetries !== undefined)
56
+ options.maxRetries = global.maxRetries;
57
+ if (global.maxResponseBytes !== undefined)
58
+ options.maxResponseBytes = global.maxResponseBytes;
59
+ return options;
60
+ }
61
+ /**
62
+ * Render a JSON value, pretty by default, compact with --compact. Writes to the
63
+ * file given by --output when present (so `-o` is honoured for JSON commands, not
64
+ * only raw downloads), otherwise to stdout. When writing a file we print a short
65
+ * confirmation to stderr so stdout stays clean for piping.
66
+ */
67
+ export function renderJson(deps, global, value) {
68
+ const text = global.compact ? JSON.stringify(value) : JSON.stringify(value, null, 2);
69
+ const output = resolveOutput(global.output);
70
+ if (output !== undefined) {
71
+ const data = Buffer.from(text + "\n", "utf8");
72
+ deps.io.writeFile(output, data);
73
+ deps.io.err(`Wrote ${data.length} bytes to ${output}`);
74
+ }
75
+ else {
76
+ deps.io.out(text);
77
+ }
78
+ }
79
+ /**
80
+ * Resolve the --output target. `undefined` means "no -o given" (write to stdout).
81
+ * An explicitly empty string is a user error (e.g. `--output "$OUT"` with an
82
+ * unset variable) and must not silently fall through to stdout, so we reject it.
83
+ */
84
+ function resolveOutput(output) {
85
+ if (output === undefined)
86
+ return undefined;
87
+ if (output === "") {
88
+ throw new NinaError("--output requires a non-empty file path.");
89
+ }
90
+ return output;
91
+ }
92
+ /**
93
+ * Render a raw (binary/text) download. Writes to the file given by --output, or
94
+ * to stdout otherwise. Prints a short confirmation to stderr when writing a file
95
+ * so stdout stays clean for piping.
96
+ *
97
+ * `expectContentType` is an optional substring sanity check. A misconfigured
98
+ * gateway can return an HTML error page with a 200 status; without this the bytes
99
+ * would be saved silently to e.g. `out.geojson`. We do not fail (the body may be
100
+ * valid with an unusual type), but we warn to stderr so the surprise is visible.
101
+ */
102
+ export function renderRaw(deps, global, response, expectContentType) {
103
+ if (expectContentType && !response.contentType.toLowerCase().includes(expectContentType)) {
104
+ deps.io.err(`Warning: expected a "${expectContentType}" response but got ` +
105
+ `"${response.contentType || "(none)"}". The body may not be what you expect.`);
106
+ }
107
+ const output = resolveOutput(global.output);
108
+ if (output !== undefined) {
109
+ deps.io.writeFile(output, response.data);
110
+ deps.io.err(`Wrote ${response.data.length} bytes to ${output}`);
111
+ }
112
+ else {
113
+ deps.io.outBinary(response.data);
114
+ }
115
+ }
116
+ /**
117
+ * Wrap an async command action with consistent global-option resolution and
118
+ * client construction. The callback receives a context (client + resolved global
119
+ * options + this command's options) and the command's positional arguments.
120
+ *
121
+ * Commander invokes actions as (arg1, ..., argN, options, command); we slice off
122
+ * the trailing options object and command instance to recover the positionals.
123
+ */
124
+ export function action(deps, fn) {
125
+ return async (...args) => {
126
+ const command = args[args.length - 1];
127
+ const positionals = args.slice(0, Math.max(0, args.length - 2));
128
+ const global = command.optsWithGlobals();
129
+ const client = deps.createClient(toEngineOptions(global));
130
+ await fn({ client, global, opts: command.opts() }, positionals);
131
+ };
132
+ }
133
+ //# 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,45 @@
1
+ import { RequestEngine, type EngineOptions, type RawResponse } from "./engine.js";
2
+ import type { NinaSource } from "./enums.js";
3
+ import type { MapWarning, WarningDetail, DashboardEntry, ArchiveMapping, Notfalltipps, EventCodes, DataVersion } from "./types.js";
4
+ /** Single-warning retrieval (full payload + geometry). */
5
+ declare class WarningsResource {
6
+ private readonly engine;
7
+ constructor(engine: RequestEngine);
8
+ /** The full CAP-derived warning for an identifier. */
9
+ get(identifier: string): Promise<WarningDetail>;
10
+ /** The warning's geometry as GeoJSON (returned as raw bytes). */
11
+ geojson(identifier: string): Promise<RawResponse>;
12
+ }
13
+ /** The MoWaS archive (historical warnings + their revision history). */
14
+ declare class ArchiveResource {
15
+ private readonly engine;
16
+ constructor(engine: RequestEngine);
17
+ /** Revision history for an archived MoWaS identifier. */
18
+ mapping(identifier: string): Promise<ArchiveMapping>;
19
+ /** A specific archived MoWaS warning (same shape as a live warning). */
20
+ get(identifier: string): Promise<WarningDetail>;
21
+ }
22
+ /** Static reference data published alongside the warnings. */
23
+ declare class ReferenceResource {
24
+ private readonly engine;
25
+ constructor(engine: RequestEngine);
26
+ /** Emergency-preparedness tips (Notfalltipps), German. */
27
+ notfalltipps(): Promise<Notfalltipps>;
28
+ /** The CAP event-code catalogue (maps event keys to icons/labels). */
29
+ eventCodes(): Promise<EventCodes>;
30
+ /** Current data version/hash (useful for change detection / polling). */
31
+ dataVersion(): Promise<DataVersion>;
32
+ }
33
+ export declare class NinaClient {
34
+ private readonly engine;
35
+ readonly warnings: WarningsResource;
36
+ readonly archive: ArchiveResource;
37
+ readonly reference: ReferenceResource;
38
+ constructor(options?: EngineOptions);
39
+ /** Current warnings from one source, e.g. `mapData("dwd")`. */
40
+ mapData(source: NinaSource): Promise<MapWarning[]>;
41
+ /** Warnings affecting a region, keyed by Amtlicher Regionalschlüssel (ARS/AGS). */
42
+ dashboard(ars: string): Promise<DashboardEntry[]>;
43
+ }
44
+ export {};
45
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAClF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,KAAK,EACV,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACZ,MAAM,YAAY,CAAC;AAMpB,0DAA0D;AAC1D,cAAM,gBAAgB;IACR,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD,sDAAsD;IACtD,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAI/C,iEAAiE;IACjE,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAGlD;AAED,wEAAwE;AACxE,cAAM,eAAe;IACP,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD,yDAAyD;IACzD,OAAO,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,CAAC;IAIpD,wEAAwE;IACxE,GAAG,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;CAGhD;AAED,8DAA8D;AAC9D,cAAM,iBAAiB;IACT,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,aAAa;IAElD,0DAA0D;IAC1D,YAAY,IAAI,OAAO,CAAC,YAAY,CAAC;IAIrC,sEAAsE;IACtE,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC;IAIjC,yEAAyE;IACzE,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;CAGpC;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IAEvC,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,OAAO,EAAE,eAAe,CAAC;IAClC,QAAQ,CAAC,SAAS,EAAE,iBAAiB,CAAC;gBAE1B,OAAO,GAAE,aAAkB;IAOvC,+DAA+D;IAC/D,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;IAIlD,mFAAmF;IACnF,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;CAGlD"}
@@ -0,0 +1,81 @@
1
+ // NinaClient — a typed client over the open (no-auth) endpoints of the NINA API
2
+ // (https://warnung.bund.de/api31), the federal civil-protection warning system
3
+ // run by the BBK (Bundesamt für Bevölkerungsschutz und Katastrophenhilfe).
4
+ //
5
+ // client.mapData("mowas") // current alerts from a source
6
+ // client.warnings.get(id) // full CAP warning
7
+ // client.dashboard(ars) // alerts for a region (Amtlicher Regionalschlüssel)
8
+ import { RequestEngine } from "./engine.js";
9
+ const API = "/api31";
10
+ const ACCEPT_GEOJSON = "application/geo+json";
11
+ const enc = encodeURIComponent;
12
+ /** Single-warning retrieval (full payload + geometry). */
13
+ class WarningsResource {
14
+ engine;
15
+ constructor(engine) {
16
+ this.engine = engine;
17
+ }
18
+ /** The full CAP-derived warning for an identifier. */
19
+ get(identifier) {
20
+ return this.engine.getJson(`${API}/warnings/${enc(identifier)}.json`);
21
+ }
22
+ /** The warning's geometry as GeoJSON (returned as raw bytes). */
23
+ geojson(identifier) {
24
+ return this.engine.getRaw(`${API}/warnings/${enc(identifier)}.geojson`, ACCEPT_GEOJSON);
25
+ }
26
+ }
27
+ /** The MoWaS archive (historical warnings + their revision history). */
28
+ class ArchiveResource {
29
+ engine;
30
+ constructor(engine) {
31
+ this.engine = engine;
32
+ }
33
+ /** Revision history for an archived MoWaS identifier. */
34
+ mapping(identifier) {
35
+ return this.engine.getJson(`${API}/archive.mowas/${enc(identifier)}-mapping.json`);
36
+ }
37
+ /** A specific archived MoWaS warning (same shape as a live warning). */
38
+ get(identifier) {
39
+ return this.engine.getJson(`${API}/archive.mowas/${enc(identifier)}.json`);
40
+ }
41
+ }
42
+ /** Static reference data published alongside the warnings. */
43
+ class ReferenceResource {
44
+ engine;
45
+ constructor(engine) {
46
+ this.engine = engine;
47
+ }
48
+ /** Emergency-preparedness tips (Notfalltipps), German. */
49
+ notfalltipps() {
50
+ return this.engine.getJson(`${API}/appdata/gsb/notfalltipps/DE/notfalltipps.json`);
51
+ }
52
+ /** The CAP event-code catalogue (maps event keys to icons/labels). */
53
+ eventCodes() {
54
+ return this.engine.getJson(`${API}/appdata/gsb/eventCodes/eventCodes.json`);
55
+ }
56
+ /** Current data version/hash (useful for change detection / polling). */
57
+ dataVersion() {
58
+ return this.engine.getJson(`${API}/dynamic/version/dataVersion.json`);
59
+ }
60
+ }
61
+ export class NinaClient {
62
+ engine;
63
+ warnings;
64
+ archive;
65
+ reference;
66
+ constructor(options = {}) {
67
+ this.engine = new RequestEngine(options);
68
+ this.warnings = new WarningsResource(this.engine);
69
+ this.archive = new ArchiveResource(this.engine);
70
+ this.reference = new ReferenceResource(this.engine);
71
+ }
72
+ /** Current warnings from one source, e.g. `mapData("dwd")`. */
73
+ mapData(source) {
74
+ return this.engine.getJson(`${API}/${source}/mapData.json`);
75
+ }
76
+ /** Warnings affecting a region, keyed by Amtlicher Regionalschlüssel (ARS/AGS). */
77
+ dashboard(ars) {
78
+ return this.engine.getJson(`${API}/dashboard/${enc(ars)}.json`);
79
+ }
80
+ }
81
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../../src/client/client.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,+EAA+E;AAC/E,2EAA2E;AAC3E,EAAE;AACF,mEAAmE;AACnE,uDAAuD;AACvD,wFAAwF;AAExF,OAAO,EAAE,aAAa,EAAwC,MAAM,aAAa,CAAC;AAYlF,MAAM,GAAG,GAAG,QAAQ,CAAC;AACrB,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAC9C,MAAM,GAAG,GAAG,kBAAkB,CAAC;AAE/B,0DAA0D;AAC1D,MAAM,gBAAgB;IACS;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,sDAAsD;IACtD,GAAG,CAAC,UAAkB;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,aAAa,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IACxE,CAAC;IAED,iEAAiE;IACjE,OAAO,CAAC,UAAkB;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,GAAG,aAAa,GAAG,CAAC,UAAU,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC1F,CAAC;CACF;AAED,wEAAwE;AACxE,MAAM,eAAe;IACU;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,yDAAyD;IACzD,OAAO,CAAC,UAAkB;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,kBAAkB,GAAG,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC;IACrF,CAAC;IAED,wEAAwE;IACxE,GAAG,CAAC,UAAkB;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,kBAAkB,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7E,CAAC;CACF;AAED,8DAA8D;AAC9D,MAAM,iBAAiB;IACQ;IAA7B,YAA6B,MAAqB;QAArB,WAAM,GAAN,MAAM,CAAe;IAAG,CAAC;IAEtD,0DAA0D;IAC1D,YAAY;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,gDAAgD,CAAC,CAAC;IACrF,CAAC;IAED,sEAAsE;IACtE,UAAU;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,yCAAyC,CAAC,CAAC;IAC9E,CAAC;IAED,yEAAyE;IACzE,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,mCAAmC,CAAC,CAAC;IACxE,CAAC;CACF;AAED,MAAM,OAAO,UAAU;IACJ,MAAM,CAAgB;IAE9B,QAAQ,CAAmB;IAC3B,OAAO,CAAkB;IACzB,SAAS,CAAoB;IAEtC,YAAY,UAAyB,EAAE;QACrC,IAAI,CAAC,MAAM,GAAG,IAAI,aAAa,CAAC,OAAO,CAAC,CAAC;QACzC,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAClD,IAAI,CAAC,OAAO,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,IAAI,CAAC,SAAS,GAAG,IAAI,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtD,CAAC;IAED,+DAA+D;IAC/D,OAAO,CAAC,MAAkB;QACxB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,IAAI,MAAM,eAAe,CAAC,CAAC;IAC9D,CAAC;IAED,mFAAmF;IACnF,SAAS,CAAC,GAAW;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,GAAG,cAAc,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IAClE,CAAC;CACF"}
@@ -0,0 +1,53 @@
1
+ import { type Transport } from "./http.js";
2
+ import { type QueryParams } from "./query.js";
3
+ export declare const DEFAULT_BASE_URL = "https://warnung.bund.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://warnung.bund.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
+ /**
23
+ * Hard cap on response body size in bytes (defends against memory exhaustion
24
+ * from a hostile/buggy endpoint). Defaults to 100 MiB; set to 0 for no limit.
25
+ */
26
+ maxResponseBytes?: number;
27
+ /** Injectable sleep, primarily for deterministic tests. */
28
+ sleep?: (ms: number) => Promise<void>;
29
+ }
30
+ export declare class RequestEngine {
31
+ private readonly baseUrl;
32
+ private readonly transport;
33
+ private readonly userAgent;
34
+ private readonly timeoutMs;
35
+ private readonly maxRetries;
36
+ private readonly retryDelayMs;
37
+ private readonly maxResponseBytes;
38
+ private readonly sleep;
39
+ constructor(options?: EngineOptions);
40
+ /** Build a fully-qualified URL from a path and optional query parameters. */
41
+ buildUrl(path: string, query?: QueryParams): string;
42
+ /** Perform a request with Accept negotiation and transient-error retries. */
43
+ request(method: string, path: string, options?: {
44
+ query?: QueryParams;
45
+ accept: string;
46
+ }): Promise<RawResponse>;
47
+ /** Perform a GET expecting JSON and parse it into `T`. */
48
+ getJson<T>(path: string, query?: QueryParams): Promise<T>;
49
+ /** Perform a GET returning the raw bytes (GeoJSON / RSS / image downloads). */
50
+ getRaw(path: string, accept: string, query?: QueryParams): Promise<RawResponse>;
51
+ private toApiError;
52
+ }
53
+ //# 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,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;AAeD,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;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;IAmCvB,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;CAYnB"}
@@ -0,0 +1,105 @@
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 { NinaApiError, NinaParseError } from "./errors.js";
7
+ export const DEFAULT_BASE_URL = "https://warnung.bund.de";
8
+ const DEFAULT_USER_AGENT = "nina-warnungen-cli";
9
+ const DEFAULT_MAX_RESPONSE_BYTES = 100 * 1024 * 1024;
10
+ /**
11
+ * Upper bound on retry attempts. Without a cap, a host stuck on 429/503 combined
12
+ * with the linear backoff (`retryDelayMs * attempt`) makes the total wait grow
13
+ * quadratically, so a large `--max-retries` (up to MAX_SAFE_INTEGER) would hang
14
+ * the process for hours. 10 retries is well beyond any realistic transient blip.
15
+ */
16
+ const MAX_RETRIES_CAP = 10;
17
+ const realSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
18
+ export class RequestEngine {
19
+ baseUrl;
20
+ transport;
21
+ userAgent;
22
+ timeoutMs;
23
+ maxRetries;
24
+ retryDelayMs;
25
+ maxResponseBytes;
26
+ sleep;
27
+ constructor(options = {}) {
28
+ this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
29
+ this.transport = options.transport ?? nodeHttpTransport;
30
+ this.userAgent = options.userAgent ?? DEFAULT_USER_AGENT;
31
+ this.timeoutMs = options.timeoutMs ?? 30_000;
32
+ this.maxRetries = Math.min(options.maxRetries ?? 2, MAX_RETRIES_CAP);
33
+ this.retryDelayMs = options.retryDelayMs ?? 200;
34
+ this.maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
35
+ this.sleep = options.sleep ?? realSleep;
36
+ }
37
+ /** Build a fully-qualified URL from a path and optional query parameters. */
38
+ buildUrl(path, query) {
39
+ const normalizedPath = path.startsWith("/") ? path : `/${path}`;
40
+ const qs = query ? buildQueryString(query) : "";
41
+ return `${this.baseUrl}${normalizedPath}${qs ? `?${qs}` : ""}`;
42
+ }
43
+ /** Perform a request with Accept negotiation and transient-error retries. */
44
+ async request(method, path, options = { accept: "application/json" }) {
45
+ const url = this.buildUrl(path, options.query);
46
+ const headers = {
47
+ Accept: options.accept,
48
+ "User-Agent": this.userAgent,
49
+ };
50
+ let attempt = 0;
51
+ // attempts = initial try + maxRetries
52
+ for (;;) {
53
+ const response = await this.transport({
54
+ method,
55
+ url,
56
+ headers,
57
+ timeoutMs: this.timeoutMs,
58
+ ...(this.maxResponseBytes > 0 ? { maxResponseBytes: this.maxResponseBytes } : {}),
59
+ });
60
+ const status = response.status;
61
+ const retryable = status === 429 || status === 503;
62
+ if (retryable && attempt < this.maxRetries) {
63
+ attempt += 1;
64
+ await this.sleep(this.retryDelayMs * attempt);
65
+ continue;
66
+ }
67
+ const contentType = String(response.headers["content-type"] ?? "");
68
+ if (status < 200 || status >= 300) {
69
+ throw this.toApiError(method, url, status, response.body);
70
+ }
71
+ return { data: response.body, contentType, status };
72
+ }
73
+ }
74
+ /** Perform a GET expecting JSON and parse it into `T`. */
75
+ async getJson(path, query) {
76
+ const res = await this.request("GET", path, { query, accept: "application/json" });
77
+ const text = res.data.toString("utf8");
78
+ try {
79
+ return JSON.parse(text);
80
+ }
81
+ catch (cause) {
82
+ throw new NinaParseError(`Failed to parse JSON response from ${path}`, { cause });
83
+ }
84
+ }
85
+ /** Perform a GET returning the raw bytes (GeoJSON / RSS / image downloads). */
86
+ async getRaw(path, accept, query) {
87
+ return this.request("GET", path, { query, accept });
88
+ }
89
+ toApiError(method, url, status, body) {
90
+ const text = body.toString("utf8");
91
+ let detail;
92
+ try {
93
+ const parsed = JSON.parse(text);
94
+ if (parsed && typeof parsed.detail === "string")
95
+ detail = parsed.detail;
96
+ else if (parsed && typeof parsed.message === "string")
97
+ detail = parsed.message;
98
+ }
99
+ catch {
100
+ // Non-JSON error body; leave detail undefined.
101
+ }
102
+ return new NinaApiError({ status, url, method, body: text, detail });
103
+ }
104
+ }
105
+ //# 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,15 @@
1
+ /**
2
+ * The warning "providers" NINA aggregates, each exposed at `/{source}/mapData.json`:
3
+ * mowas — Modulares Warnsystem (Bund/Länder civil-protection alerts)
4
+ * katwarn — KATWARN municipal alerting
5
+ * biwapp — BIWAPP municipal alerting
6
+ * dwd — Deutscher Wetterdienst severe-weather warnings
7
+ * lhp — Länderübergreifendes Hochwasser Portal (flood warnings)
8
+ * police — police incident reports
9
+ */
10
+ export declare const NinaSourceValues: readonly ["mowas", "katwarn", "biwapp", "dwd", "lhp", "police"];
11
+ export type NinaSource = (typeof NinaSourceValues)[number];
12
+ /** Severity levels used in CAP-derived warning payloads. */
13
+ export declare const SeverityValues: readonly ["Minor", "Moderate", "Severe", "Extreme", "Unknown"];
14
+ export type Severity = (typeof SeverityValues)[number];
15
+ //# sourceMappingURL=enums.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.d.ts","sourceRoot":"","sources":["../../../src/client/enums.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AACH,eAAO,MAAM,gBAAgB,iEAAkE,CAAC;AAChG,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,gBAAgB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,4DAA4D;AAC5D,eAAO,MAAM,cAAc,gEAAiE,CAAC;AAC7F,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,15 @@
1
+ // Enum-like value sets. These const arrays double as runtime CLI choice
2
+ // validators and as TS union types.
3
+ /**
4
+ * The warning "providers" NINA aggregates, each exposed at `/{source}/mapData.json`:
5
+ * mowas — Modulares Warnsystem (Bund/Länder civil-protection alerts)
6
+ * katwarn — KATWARN municipal alerting
7
+ * biwapp — BIWAPP municipal alerting
8
+ * dwd — Deutscher Wetterdienst severe-weather warnings
9
+ * lhp — Länderübergreifendes Hochwasser Portal (flood warnings)
10
+ * police — police incident reports
11
+ */
12
+ export const NinaSourceValues = ["mowas", "katwarn", "biwapp", "dwd", "lhp", "police"];
13
+ /** Severity levels used in CAP-derived warning payloads. */
14
+ export const SeverityValues = ["Minor", "Moderate", "Severe", "Extreme", "Unknown"];
15
+ //# 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;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,CAAU,CAAC;AAGhG,4DAA4D;AAC5D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,CAAU,CAAC"}
@@ -0,0 +1,36 @@
1
+ /** Base class for every error originating from this client. */
2
+ export declare class NinaError extends Error {
3
+ constructor(message: string, options?: {
4
+ cause?: unknown;
5
+ });
6
+ }
7
+ /**
8
+ * The API responded with a non-2xx status code. `detail` holds a human-readable
9
+ * message extracted from the response body when one is present.
10
+ */
11
+ export declare class NinaApiError extends NinaError {
12
+ readonly status: number;
13
+ readonly detail: string | undefined;
14
+ readonly url: string;
15
+ readonly method: string;
16
+ readonly body: string;
17
+ constructor(args: {
18
+ status: number;
19
+ url: string;
20
+ method: string;
21
+ body: string;
22
+ detail?: string;
23
+ });
24
+ /** True for statuses the API documents as transient and retry-able. */
25
+ get isRetryable(): boolean;
26
+ }
27
+ /** A transport-level failure (DNS, connection reset, timeout, ...). */
28
+ export declare class NinaNetworkError extends NinaError {
29
+ }
30
+ /** The response body could not be parsed as the expected JSON shape. */
31
+ export declare class NinaParseError extends NinaError {
32
+ }
33
+ /** A local I/O failure, e.g. writing the --output file (no such dir, EISDIR). */
34
+ export declare class NinaIOError extends NinaError {
35
+ }
36
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/client/errors.ts"],"names":[],"mappings":"AAGA,+DAA+D;AAC/D,qBAAa,SAAU,SAAQ,KAAK;gBACtB,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAI3D;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,SAAS;IACzC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;gBAEV,IAAI,EAAE;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,EAAE,MAAM,CAAC;QACZ,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACjB;IAaD,uEAAuE;IACvE,IAAI,WAAW,IAAI,OAAO,CAEzB;CACF;AAgBD,uEAAuE;AACvE,qBAAa,gBAAiB,SAAQ,SAAS;CAAG;AAElD,wEAAwE;AACxE,qBAAa,cAAe,SAAQ,SAAS;CAAG;AAEhD,iFAAiF;AACjF,qBAAa,WAAY,SAAQ,SAAS;CAAG"}