/** * Pure XML parsing for JMA's disaster-prevention feed — the Atom index and a * VPWW53 warning document. * * Zero I/O, zero logging: XML strings in, typed records (or a thrown, fixed, * sanitized message) out. The service layer owns fetching, caching, revalidation * and the contract-vs-garnish decision; this module owns every shape and size * constant and every parsing decision, which follow from **field names, never * from position**. * * **This is JMA's own H27 schema, not CAP.** `src/utils/capParse.ts` does not * apply and is not called from here. What *is* deliberately reused is its * guard sequence and parser configuration, reproduced below with JMA wording, * because the index needs its own byte cap (5.27 MB observed against CAP's * 2 MB `MAX_DOCUMENT_BYTES`) and every thrown message must name JMA rather than * CAP. The order of the guards is the load-bearing part and is identical: * * size -> BOM/whitespace strip -> HTML error page -> DOCTYPE -> * `XMLValidator.validate` -> parse -> exactly one non-array, non-PI root key. * * Two of those exist because `fast-xml-parser` cannot be trusted for * well-formedness on its own (G3): its parser is lenient (`` parses * without throwing), and `XMLValidator` *accepts* several documents that are * not one root — two self-closing roots, and two self-closing roots sharing a * tag name, which the parser then coalesces into one key holding an array. Only * the post-parse structural check catches every case. * * **An unusable envelope throws; a recognised envelope with nothing in it * returns an honest empty (G4).** A feed whose root is not `feed`, or a * document with no `Body`, or a document whose `Body` carries no class10 * `Warning` block, is a *shape* failure and throws — it is not "no warnings". * A class10 `Warning` block with no `Item`s is a genuine empty and returns * normally. On safety data those are different sentences and the caller must * be able to tell them apart. * * Every thrown message is fixed text — never the input XML, never a raw parser * error — so a malformed or oversize feed cannot leak upstream content into * logs or user-facing errors. * * Verified live 2026-09-03 against `feed/extra_l.xml` and 14 VPWW53 documents * from 14 distinct offices. */ import type { JmaIndexResult, JmaWarningDocument } from '../types/jma.js'; /** * Maximum accepted byte size of the Atom index. * * The long-term index decompressed to **5,267,421 bytes** on 2026-09-03, so * CAP's 2 MB `MAX_DOCUMENT_BYTES` cannot be reused for it. 12 MB leaves better * than 2x headroom for growth while still refusing anything that is no longer * an index. * * These constants live in this pure module and are imported by the service, * never the other way round (CLAUDE.md design pattern 6, and the same placement * `capParse.ts` uses). */ export declare const JMA_MAX_INDEX_BYTES = 12000000; /** Maximum accepted byte size of one warning document. Observed: 25 KB; the plan's earlier sample, 171 KB. */ export declare const JMA_MAX_DOCUMENT_BYTES = 2000000; /** * Maximum number of `` elements kept from one index. * * The live index carried 8,597 entries over seven days. A trim is a **caveat * the caller renders, never a reason to exclude an office** (G8) — see * `JmaIndexResult.trimmed`. */ export declare const JMA_MAX_INDEX_ENTRIES = 20000; /** Maximum number of class10 areas kept from one warning document. Observed: 2-8. */ export declare const JMA_MAX_AREAS_PER_DOCUMENT = 500; /** Maximum number of kinds kept for one area. Observed: 1-6. */ export declare const JMA_MAX_KINDS_PER_AREA = 100; /** * The bulletin type this feature reads. * * Measured over seven days: VPWW53 carries 2,515 entries covering **all 58 * offices**, and no office publishes VPWW54 (also 2,515 entries) or an R06 * split without also publishing VPWW53. It is therefore the correct and * complete single source, and consuming any second type would double-render * every warning. */ export declare const JMA_WARNING_INFO_TYPE = "VPWW53"; /** * Substring identifying the class10 (`一次細分区域等`, "primary subdivision * areas") granularity level among a document's five sibling `Warning` blocks. * * Matched as a substring rather than by equality because the surrounding label * differs between the `Head` summary and the `Body` * (`気象警報・注意報(一次細分区域等)`), and because a schema generation that * re-words the prefix should not silently drop the level and render an empty * document as "no warnings". */ export declare const JMA_CLASS10_WARNING_LEVEL = "\u4E00\u6B21\u7D30\u5206\u533A\u57DF"; /** * Parse the Atom index into flat entries. * * Throws when the envelope is wrong — a root that is not `feed` is a shape * failure, **not** an empty feed (G4). A `feed` with no entries returns an * honest empty result. */ export declare function parseJmaIndex(xml: string): JmaIndexResult; /** * Parse a VPWW53 warning document, reading **only** the class10 * (`一次細分区域等`) granularity level. * * Throws when the envelope is unusable: no `Report` root, no `Body`, no * `Warning` blocks at all, or `Warning` blocks none of which is the class10 * level. A class10 block carrying no `Item`s returns `areas: []` — an honest * empty for a document that really was fetched and really says nothing is in * force (G4). */ export declare function parseJmaWarningDocument(xml: string): JmaWarningDocument; //# sourceMappingURL=jmaParse.d.ts.map