/** * A parsed database connection URL, as a VALUE. * * Feature 5 of the feature audit. This used to be `parseDatabaseUrl()`, a single * function with a cyclomatic complexity of 43 - the worst function measured * anywhere in the audit - whose entire job is string-to-struct. It is now one * small parser per engine, each well under the threshold, behind a value type * with the same surface as PHP's `DatabaseUrl` (the reference for this row). * * Core Principle 6 says a connection string must mean literally the same thing * in every framework. `test/fixtures/database_url_corpus.json` is the answer * key, byte-identical in all four. */ import { inspect } from "node:util"; /** The canonical engine names. Aliases resolve to these ONCE, at parse. */ export type DatabaseEngine = "sqlite" | "postgres" | "mysql" | "mssql" | "firebird" | "mongodb" | "odbc"; /** * Remove every credential from an arbitrary connection string. * * THE single redaction primitive. It works on a RAW string - valid or * malformed, a URL or an ODBC DSN - so the error paths can use it too, and it * is what `toSafeString()` calls for the odbc form rather than hand-rolling a * second, weaker rule. * * It cannot be complete on a string with no recognisable credential structure * (`notaurl-with-hunter2` has nothing to key off), which is exactly why the * invalid-URL error reports the scheme and host instead of any form of the * input. Redaction is for strings we can parse enough to redact. */ export declare function redactCredentials(raw: string): string; /** * DISPLAY REDACTS, FIDELITY DOES NOT. JSON.stringify, util.inspect, String() and * toSafeString() replace the password with the redaction marker, so a log line, a * stack or a status payload is safe. structuredClone deliberately does not: its * contract is a faithful structural copy, and a masked clone would produce an * object whose password is the literal "***". * * The consequence: DO NOT PERSIST THIS OBJECT. A DatabaseUrl structured-cloned * onto a worker thread, into a cache or into a queue payload carries a cleartext * credential across that boundary. Use toSafeString() instead. * test/databaseUrlRedaction.test.ts fails the build if framework code ever does. */ export declare class DatabaseUrl { readonly engine: DatabaseEngine; /** Null for sqlite and odbc - a file or a DSN string has no host. */ readonly host: string | null; /** Null for sqlite and odbc. Otherwise always set: the engine default applies. */ readonly port: number | null; readonly database: string; /** Null when absent, never an empty string - absent and blank differ. */ readonly username: string | null; readonly password: string | null; /** ODBC only: the raw connection string handed to odbc.connect(). */ readonly connectionString: string | null; constructor(url: string, username?: string, password?: string); static fromEnv(key?: string): DatabaseUrl | null; /** * Connection target for the adapter. sqlite and odbc are the whole value. * * NOT SAFE TO LOG. For every network engine this is credential-free * (host:port/database), which makes it look loggable - but the odbc branch * returns the connection string VERBATIM, `PWD=` included, because that is * what the driver has to receive. Log `toSafeString()`; never this. */ dsn(): string; /** * The URL with the password replaced by ***. * * The ONLY form allowed in a log line or an error message: a connection URL in * a log is a credential leak. Node had no such method at all before this, * which meant every call site that wanted to log a connection target had to * redact it by hand. It round-trips, so it stays readable as well as safe. */ toSafeString(): string; /** * What `JSON.stringify(url)` emits. * * Without it, stringifying the value - directly, or as one field of a config * object being logged - emitted `"password":""`, measured * on this class. Python guards the same exposure with `__repr__` and Ruby * with `#inspect`; JSON is the shape Node actually serialises into a log * line, so it needs the guard too. * * Structure is preserved so the dump is still worth having: only the secret * is masked. `null` stays `null` - an ABSENT password and a masked one are * different facts, and flattening them would hide exactly the confusion C7 * is about. */ toJSON(): Record; /** * What `console.log(url)` / `util.inspect(url)` print. * * Node's equivalent of Python's `__repr__` and Ruby's `#inspect`, and the * same rendering they produce - `DatabaseUrl('postgres://user:***@h:5432/db')` * (tina4-python/tina4_python/database/database_url.py:153). Without it, * `console.log(url)` printed the default field dump, password included. */ [inspect.custom](): string; private static parse; /** * sqlite is parsed on the RAW string. The URL class collapses `sqlite:/x` and * `sqlite:///x`, losing the difference between a one-slash ABSOLUTE path and * the documented three-slash RELATIVE form. * * sqlite:///app.db -> app.db (three slashes = relative to cwd) * sqlite:////abs/app.db -> /abs/app.db (four slashes = absolute) * sqlite:/abs/app.db -> /abs/app.db (one slash = a real absolute path) * sqlite:app.db -> app.db */ private static parseSqlite; /** * mssql and firebird: the URL class does not know these schemes, so they are * matched directly. * * The captured path keeps its own leading slash when the URL had two, which is * how the documented absolute Firebird form survives. The old code did * `"/" + match[5]`, ADDING a slash - so an absolute path came back with two * and a relative path was silently made absolute. Verified against live * Firebird 5.0.4: the driver takes one or two leading slashes and rejects a * relative path outright. */ private static parseRegexForm; /** postgres / mysql / mongodb, via the URL class. */ private static parseStandard; }