/** * Describing attacker-influenceable content in a log line without reproducing it. * * Translation values arrive from the server and are influenceable by whoever * can write a translation. Interpolating one whole into a log line on a path * that runs PER RENDER turns a single poisoned row into unbounded, repeating * log volume — the same amplification found in @lionrapid/formatters, where a * 40k-marker template wrote ~320KB per call. * * A bare truncation would bound the volume and destroy the point of the line, * so this keeps what actually answers "which translation, and what was in it": * * LENGTH — the real length, not the truncated one, so a pathological * value is visibly pathological. * FINGERPRINT — md5 truncated to 12, the SAME function and width used to * derive `auto_` keys (`generateAutoKey` = `auto_` + md5 of * the TRIMMED text, first 12). For a markup-free source string * the value printed here is exactly the key's hash, so the row * can be looked up by prefixing `auto_`. For a value carrying * markup the auto key is derived from the parsed ContentUnit's * text rather than the raw string, so it is a stable * fingerprint but NOT the key — hence `md5:` rather than * `auto_`, which would overclaim. * EXCERPT — head and tail, quoted and escaped. * * Escaping is not cosmetic. The content can contain newlines, and a log line * assembled by interpolation is forgeable: a value containing `\n Error: ...` * writes what looks like its own log entry. JSON.stringify escapes it back into * a single quoted token. * * @module utils/log-safe */ /** * Identity of a value without reproducing it: `"1234 chars, md5:ab12cd34ef56"`. * * Hashes the TRIMMED value, matching `generateAutoKey`, so the two agree * wherever the auto key was derived from this exact string. */ export declare function contentIdentity(value: string): string; /** * A bounded, quoted, escaped excerpt. * * Head AND tail rather than a prefix: these failures carry no offset to centre * a window on (unlike an ICU SyntaxError, which reports one), and the end of a * value is where an unterminated tag or a truncated payload shows itself. */ export declare function contentExcerpt(value: string): string; /** * A thrown value, as one bounded, escaped line: `"TypeError: boom"`. * * INCLUDES THE NAME. It previously returned `error.message` for Errors and * `String(value)` for everything else, which was backwards: `String(err)` keeps * the name ("TypeError: boom") while `.message` drops it ("boom"), so a * non-Error carried MORE identifying information than an Error did. The name is * the distinction that separates "bad template" (MissingValueError) from "our * bug" (TypeError), and neither line carried it. * * Bounded because an error message is not automatically small OR content-free — * see `oneLine`. No stack: this is used INLINE, mid-sentence, where frames read * badly. `describeLogData` adds them where they land at the end of a line. */ export declare function describeError(error: unknown): string; /** * Anything handed to a logger as its `data` argument, rendered safely. * * The logger used to do `JSON.stringify(data)` in both of its rendering * branches. That was wrong three ways, and every one of them was silent: * * ERRORS VANISHED — `JSON.stringify(new Error('boom'))` is `{}`, because an * Error's fields are not enumerable. Both branches end by * building a single string for `console.*`, so devtools * could not expand the object either. Every caught error * passed as data — across the whole package — printed * `{}` and always had. * UNBOUNDED — any object rendered whole, so a large payload was log * amplification on a path that runs per render. * IT COULD THROW — `JSON.stringify` throws on a circular structure or a * BigInt, so logging inside a `catch` could replace the * error being diagnosed with a TypeError from the logger. * * Errors get name, bounded message and the first couple of frames, joined with * ` | ` rather than newlines so the whole record stays one greppable line and a * forged message cannot masquerade as a frame. */ export declare function describeLogData(data: unknown): string; /** * Identity plus excerpt, ready to drop into a log line. * * `1234 chars, md5:ab12cd34ef56, "the start…the end"` */ export declare function describeContent(value: string): string; //# sourceMappingURL=log-safe.d.ts.map