@adrianhall/cloudflare-toolkit 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/LICENSE +21 -0
- package/README.md +59 -0
- package/THIRD-PARTY-NOTICES.md +75 -0
- package/dist/cli/generate-wrangler-types/index.d.ts +1 -0
- package/dist/cli/generate-wrangler-types/index.js +329 -0
- package/dist/cli/generate-wrangler-types/index.js.map +1 -0
- package/dist/error-CLYcAvBM.d.ts +28 -0
- package/dist/errors/index.d.ts +2 -0
- package/dist/errors/index.js +3 -0
- package/dist/errors-Ciipq_zr.js +58 -0
- package/dist/errors-Ciipq_zr.js.map +1 -0
- package/dist/factory-BI5gVL_P.js +220 -0
- package/dist/factory-BI5gVL_P.js.map +1 -0
- package/dist/generators-D8WWEHa1.js +165 -0
- package/dist/generators-D8WWEHa1.js.map +1 -0
- package/dist/guards/index.d.ts +2 -0
- package/dist/guards/index.js +2 -0
- package/dist/guards-6K1CVAr5.js +61 -0
- package/dist/guards-6K1CVAr5.js.map +1 -0
- package/dist/hono/index.d.ts +347 -0
- package/dist/hono/index.js +307 -0
- package/dist/hono/index.js.map +1 -0
- package/dist/index-434HN8jN.d.ts +43 -0
- package/dist/index-Byl-ZrCy.d.ts +138 -0
- package/dist/index-CUICemFw.d.ts +129 -0
- package/dist/index-DRIhR-Xn.d.ts +81 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.js +8 -0
- package/dist/jwt-BvuKtvby.js +328 -0
- package/dist/jwt-BvuKtvby.js.map +1 -0
- package/dist/logging/index.d.ts +3 -0
- package/dist/logging/index.js +3 -0
- package/dist/logging-CGHjOVLM.js +24 -0
- package/dist/logging-CGHjOVLM.js.map +1 -0
- package/dist/policy-CvS6AvvD.js +20 -0
- package/dist/policy-CvS6AvvD.js.map +1 -0
- package/dist/problem-details/index.d.ts +4 -0
- package/dist/problem-details/index.js +3 -0
- package/dist/problem-details-CuRsLy3Q.js +37 -0
- package/dist/problem-details-CuRsLy3Q.js.map +1 -0
- package/dist/silent-CWpHE65X.js +652 -0
- package/dist/silent-CWpHE65X.js.map +1 -0
- package/dist/testing/index.d.ts +44 -0
- package/dist/testing/index.js +2 -0
- package/dist/types-Cx6NNILW.d.ts +44 -0
- package/dist/types-DCSMb1cp.d.ts +195 -0
- package/dist/types-DXboaWOT.d.ts +29 -0
- package/dist/vite/index.d.ts +79 -0
- package/dist/vite/index.js +417 -0
- package/dist/vite/index.js.map +1 -0
- package/package.json +137 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"silent-CWpHE65X.js","names":["LEVEL_METHOD"],"sources":["../src/lib/logging/levels.ts","../src/lib/logging/internal/optional-field.ts","../src/lib/logging/serialize.ts","../src/lib/logging/logger.ts","../src/lib/logging/internal/console.ts","../src/lib/logging/transports/browser.ts","../src/lib/logging/transports/capture.ts","../src/lib/logging/internal/safe-json.ts","../src/lib/logging/internal/sanitize.ts","../src/lib/logging/transports/console.ts","../src/lib/logging/transports/structured.ts","../src/lib/logging/resolve.ts","../src/lib/logging/transports/silent.ts"],"sourcesContent":["/**\n * @file Numeric level weights for the logging subpath.\n *\n * `LOG_LEVELS` and `levelValue()` are internal implementation details, not exported from\n * `src/lib/logging/index.ts`. Numeric values are stable for the emitted `LogRecord.levelValue`\n * field.\n */\nimport type { LogLevel } from \"./types.js\";\n\n/**\n * Stable numeric weights for each log level.\n *\n * A record is emitted when: `LOG_LEVELS[record.level] >= LOG_LEVELS[logger.level]`\n */\nexport const LOG_LEVELS: Readonly<Record<LogLevel, number>> = {\n trace: 10,\n debug: 20,\n info: 30,\n warn: 40,\n error: 50,\n fatal: 60\n};\n\n/**\n * Return the numeric weight for `level`.\n *\n * Throws a `TypeError` for any value that is not a recognized `LogLevel`. TypeScript consumers\n * should rely on the `LogLevel` union type and never reach this error path under normal usage.\n * Deliberately not implemented with `throwIfNull`: this throws a `TypeError` for an unrecognized\n * string, not a `null`/`undefined` guard, so using that helper would change the thrown error\n * type.\n *\n * @param level - The level to look up.\n * @returns The numeric weight for `level`.\n * @throws {TypeError} If `level` is not one of the six recognized `LogLevel` values.\n */\nexport function levelValue(level: LogLevel): number {\n const value = LOG_LEVELS[level];\n if (value === undefined) {\n throw new TypeError(\n `Unknown log level: ${String(level)}. Expected one of: ${Object.keys(LOG_LEVELS).join(\", \")}`\n );\n }\n return value;\n}\n","/**\n * @file An internal helper for the logging subpath — not one of the toolkit's public defensive\n * guards (`src/lib/guards`) and not exported from `src/lib/logging/index.ts`.\n */\n\n/**\n * Returns `{ [prop]: o[prop] }` when `prop` is an own property of `o` with a non-`undefined`\n * value, otherwise returns `{}`.\n *\n * Intended for safely spreading optional fields onto plain objects without introducing\n * `undefined`-valued keys:\n *\n * ```ts\n * const result = {\n * name: err.name,\n * ...optionalField(err, \"stack\"),\n * };\n * ```\n *\n * @param o - The object to read `prop` from.\n * @param prop - The property to conditionally include.\n * @returns `{ [prop]: o[prop] }` when defined, otherwise `{}`.\n */\nexport function optionalField<T extends object>(\n o: T,\n prop: keyof T\n): Partial<Pick<T, typeof prop>> {\n return o[prop] !== undefined ? ({ [prop]: o[prop] } as Partial<Pick<T, typeof prop>>) : {};\n}\n","/**\n * @file Error serialization for the logging subpath.\n *\n * `serializeError()` converts `Error` instances to plain objects so transports can safely\n * forward structured context without raw `Error` values escaping into JSON serialization or\n * console methods. Only top-level context values are serialized by the logger (`logger.ts`);\n * nested errors are left as-is unless they appear as a direct `cause` of a top-level error.\n */\nimport { optionalField } from \"./internal/optional-field.js\";\n\n/**\n * Serialize `value` if it is an `Error`; return it unchanged otherwise.\n *\n * - Non-`Error` values are returned as-is.\n * - `Error` instances become plain objects with `name`, `message`, and optionally `stack` and\n * `cause`.\n * - `cause` is shallowly serialized when it is itself an `Error`.\n *\n * @param value - The value to serialize, if it is an `Error`.\n * @returns A plain-object serialization of `value` when it is an `Error`, otherwise `value`\n * unchanged.\n */\nexport function serializeError(value: unknown): unknown {\n if (!(value instanceof Error)) {\n return value;\n }\n\n const serialized: Record<string, unknown> = {\n name: value.name,\n message: value.message,\n ...optionalField(value, \"stack\")\n };\n\n if (value.cause !== undefined) {\n serialized.cause =\n value.cause instanceof Error ?\n {\n name: value.cause.name,\n message: value.cause.message,\n ...optionalField(value.cause, \"stack\")\n }\n : value.cause;\n }\n\n return serialized;\n}\n","/**\n * @file The core logger implementation. This is the framework-agnostic core that the\n * `cloudflareLogger` Hono middleware wraps — it must never import `hono`.\n *\n * `createLogger()` constructs a `Logger` that:\n * - Filters records below the configured level before touching context.\n * - Merges bindings and per-call context into a new object (never mutates input).\n * - Serializes top-level `Error` values in context before delivering to transport.\n * - Wraps transport delivery in try/catch so transport failures never escape.\n * - Supports child loggers that inherit transport, level, clock, and error handler.\n */\nimport { levelValue } from \"./levels.js\";\nimport { serializeError } from \"./serialize.js\";\nimport type {\n CreateLoggerOptions,\n LogContext,\n LogLevel,\n LogRecord,\n Logger,\n TransportErrorHandler,\n Transport\n} from \"./types.js\";\n\n/**\n * Internal factory used by both `createLogger` and child loggers.\n *\n * All logger state is captured in the closure; no class is used. Both root loggers and child\n * loggers are created through this function, which keeps the child creation path identical to\n * the root path.\n *\n * @param level - Minimum level to emit.\n * @param transport - Destination for emitted records.\n * @param bindings - Key-value pairs merged into every record's context.\n * @param clock - Produces the timestamp for each record.\n * @param onTransportError - Optional callback for transport failures.\n * @returns A `Logger` bound to the supplied state.\n */\nfunction makeLogger(\n level: LogLevel,\n transport: Transport,\n bindings: LogContext,\n clock: () => Date,\n onTransportError: TransportErrorHandler | undefined\n): Logger {\n const currentLevelValue = levelValue(level);\n\n /**\n * Returns `true` when records at `candidate` severity will be emitted. Used both for the\n * public `isLevelEnabled` method and internally before constructing a record.\n *\n * @param candidate - The level to test against the configured minimum level.\n * @returns `true` when `candidate` is at or above the configured minimum level.\n */\n function isLevelEnabled(candidate: LogLevel): boolean {\n return levelValue(candidate) >= currentLevelValue;\n }\n\n /**\n * Core emit path shared by all six level methods.\n *\n * Exits immediately when `logLevel` is below the configured minimum so that disabled calls\n * never access the `context` argument. When enabled, merges bindings with per-call context,\n * serializes top-level `Error` values, builds the `LogRecord`, and delivers it to the\n * transport inside a try/catch.\n *\n * @param logLevel - Severity of this record.\n * @param message - Human-readable description of the event.\n * @param context - Optional per-call structured context.\n */\n function emit(logLevel: LogLevel, message: string, context?: LogContext): void {\n if (!isLevelEnabled(logLevel)) {\n return;\n }\n\n // Merge bindings + call context into a new object. Per-call context wins.\n const merged: LogContext =\n context !== undefined ? { ...bindings, ...context } : { ...bindings };\n\n // Serialize top-level Error values before delivering to transport.\n const serializedContext: LogContext = {};\n for (const key of Object.keys(merged)) {\n serializedContext[key] = serializeError(merged[key]);\n }\n\n const record: LogRecord = {\n time: clock().toISOString(),\n level: logLevel,\n levelValue: levelValue(logLevel),\n message,\n context: serializedContext\n };\n\n try {\n transport.log(record);\n } catch (error) {\n try {\n onTransportError?.(error, record);\n } catch {\n // Logging must not throw into application code.\n }\n }\n }\n\n return {\n get level(): LogLevel {\n return level;\n },\n\n isLevelEnabled,\n\n trace(message: string, context?: LogContext): void {\n emit(\"trace\", message, context);\n },\n\n debug(message: string, context?: LogContext): void {\n emit(\"debug\", message, context);\n },\n\n info(message: string, context?: LogContext): void {\n emit(\"info\", message, context);\n },\n\n warn(message: string, context?: LogContext): void {\n emit(\"warn\", message, context);\n },\n\n error(message: string, context?: LogContext): void {\n emit(\"error\", message, context);\n },\n\n fatal(message: string, context?: LogContext): void {\n emit(\"fatal\", message, context);\n },\n\n child(childBindings: LogContext): Logger {\n // Child inherits parent's transport, level, clock, and error handler.\n // Child bindings are merged: parent bindings + child bindings.\n return makeLogger(\n level,\n transport,\n { ...bindings, ...childBindings },\n clock,\n onTransportError\n );\n }\n };\n}\n\n/**\n * Create a new `Logger` with the provided options.\n *\n * - `options.transport` is required.\n * - `options.level` defaults to `\"info\"`.\n * - `options.clock` defaults to `() => new Date()`.\n * - `options.bindings` are merged into every emitted record.\n * - `options.onTransportError` receives transport errors without crashing the app.\n *\n * @param options - Logger construction options.\n * @returns A new `Logger`.\n */\nexport function createLogger(options: CreateLoggerOptions): Logger {\n const {\n transport,\n level = \"info\",\n bindings = {},\n clock = () => new Date(),\n onTransportError\n } = options;\n\n return makeLogger(level, transport, bindings, clock, onTransportError);\n}\n","/**\n * @file Internal console-method fallback helpers for the logging subpath. Not exported from\n * `src/lib/logging/index.ts`.\n *\n * Transports use specific `console` methods (`debug`, `info`, `warn`, `error`, `log`) to route\n * records to the appropriate DevTools channel or log level in the host environment. Some\n * environments (notably older Workers runtimes and custom test harnesses) may not expose every\n * console method.\n *\n * `getConsoleMethod()` returns the requested console method when available and falls back to\n * `console.log` otherwise, preventing a missing-method crash from surfacing into application\n * code.\n */\n\n/** The subset of `console` method names used by built-in transports. */\nexport type ConsoleMethodName = \"debug\" | \"info\" | \"log\" | \"warn\" | \"error\";\n\n/**\n * Minimal console interface used internally by transports.\n *\n * Typed as `(...args: unknown[]) => void` so that both the real `console` object and\n * test-injected spies satisfy the shape without needing to reference DOM or Workers globals.\n */\nexport type ConsoleMethod = (...args: unknown[]) => void;\n\n/**\n * A minimal console-like object that transports write to.\n *\n * Transports accept an optional `console` parameter (defaulting to the global `console`) so\n * that tests can inject a spy without patching the global.\n */\nexport type ConsoleLike = Partial<Record<ConsoleMethodName, ConsoleMethod>> & {\n log: ConsoleMethod;\n};\n\n/**\n * Return the named console method from `c`, falling back to `c.log` if the method is absent or\n * not a function.\n *\n * Rationale: logging must not crash because a host environment is missing a specific console\n * method. `console.log` is the safest baseline and is present in every JS environment that\n * supports `console` at all.\n *\n * @param c - The console-like object to query.\n * @param method - The preferred method name.\n * @returns The requested method if callable, otherwise `c.log`.\n */\nexport function getConsoleMethod(c: ConsoleLike, method: ConsoleMethodName): ConsoleMethod {\n const candidate = c[method];\n if (typeof candidate === \"function\") {\n return candidate.bind(c);\n }\n return c.log.bind(c);\n}\n","/**\n * @file A transport that formats records for browser DevTools using `%c` styled level badges.\n *\n * `createBrowserTransport()` maps severity levels to appropriate console methods and passes the\n * context object as a separate argument when non-empty, so DevTools can expand it interactively.\n *\n * Level-to-method mapping:\n * trace, debug → console.debug\n * info → console.info\n * warn → console.warn\n * error, fatal → console.error\n */\nimport { getConsoleMethod } from \"../internal/console.js\";\nimport type { ConsoleLike, ConsoleMethodName } from \"../internal/console.js\";\nimport type { BrowserTransportOptions, LogLevel, LogRecord, Transport } from \"../types.js\";\n\n/** Default CSS badge styles keyed by level. */\nconst DEFAULT_STYLES: Readonly<Record<LogLevel, string>> = {\n trace: \"color: #9ca3af; font-weight: bold\",\n debug: \"color: #6b7280; font-weight: bold\",\n info: \"color: #3b82f6; font-weight: bold\",\n warn: \"color: #f59e0b; font-weight: bold\",\n error: \"color: #ef4444; font-weight: bold\",\n fatal: \"color: #dc2626; font-weight: bold; text-decoration: underline\"\n};\n\n/** Map each log level to the preferred console method name. */\nconst LEVEL_METHOD: Readonly<Record<LogLevel, ConsoleMethodName>> = {\n trace: \"debug\",\n debug: \"debug\",\n info: \"info\",\n warn: \"warn\",\n error: \"error\",\n fatal: \"error\"\n};\n\n/**\n * Create a browser transport optimized for DevTools output.\n *\n * @param options - Optional level style overrides.\n * @param _console - Injected console-like object (defaults to global `console`). Used in tests.\n * @returns A `Transport` that writes styled records to the browser console.\n */\nexport function createBrowserTransport(\n options?: BrowserTransportOptions,\n _console: ConsoleLike = console\n): Transport {\n const levelStyles: Readonly<Record<LogLevel, string>> = {\n ...DEFAULT_STYLES,\n ...options?.levelStyles\n };\n\n return {\n log(record: LogRecord): void {\n const methodName = LEVEL_METHOD[record.level];\n const method = getConsoleMethod(_console, methodName);\n const style = levelStyles[record.level];\n const badge = record.level.toUpperCase();\n\n const hasContext = Object.keys(record.context).length > 0;\n\n if (hasContext) {\n method(`%c${badge}`, style, record.message, record.context);\n } else {\n method(`%c${badge}`, style, record.message);\n }\n }\n };\n}\n","/**\n * @file A transport that accumulates log records in memory without writing to the console.\n *\n * `createCaptureTransport()` is intended for use in Vitest tests where assertions need to\n * inspect emitted records deterministically. Use `.find(level)` as the preferred assertion\n * helper for level-specific record checks rather than filtering `.records` manually.\n */\nimport type { CaptureTransport, LogLevel, LogRecord } from \"../types.js\";\n\n/**\n * Create a capture transport that stores records in memory.\n *\n * @returns A `CaptureTransport` with `.records`, `.clear()`, and `.find()`.\n */\nexport function createCaptureTransport(): CaptureTransport {\n let internal: LogRecord[] = [];\n\n return {\n log(record: LogRecord): void {\n internal.push(record);\n },\n\n get records(): readonly LogRecord[] {\n // Return a shallow copy so callers cannot mutate internal storage.\n return internal.slice();\n },\n\n clear(): void {\n internal = [];\n },\n\n find(level: LogLevel): readonly LogRecord[] {\n return internal.filter((r) => r.level === level);\n }\n };\n}\n","/**\n * @file Internal safe JSON/string formatting for the logging subpath. Not exported from\n * `src/lib/logging/index.ts`; used by `createConsoleTransport` and `createStructuredTransport`.\n *\n * `safeStringify()` serializes arbitrary values to a compact JSON string while handling the\n * common non-JSON types that appear in structured log context:\n * - Circular references → `\"[Circular]\"` (a shared/diamond reference reachable via two\n * non-nested paths — e.g. `{ a: shared, b: shared }` — is NOT a circular reference and is\n * serialized in full at both locations; only true ancestor cycles are replaced)\n * - `bigint` → `\"<n>n\"` (e.g. `42n` → `\"42n\"`)\n * - `symbol` → `\"Symbol(description)\"`\n * - `function` → `\"[Function name]\"` or `\"[Function (anonymous)]\"`\n * - `undefined` → omitted from objects, `\"undefined\"` at top level\n */\n\n/**\n * A stable placeholder emitted when `JSON.stringify` itself throws unexpectedly (e.g. a getter\n * that throws mid-serialization after the circular-reference check has passed).\n */\nconst FALLBACK = \"[FormattingError]\";\n\n/**\n * Convert a single value to a JSON-safe replacement.\n *\n * Called from the `JSON.stringify` replacer for every value encountered during serialization.\n * Non-JSON-safe primitives (`bigint`, `symbol`, `function`) are converted to descriptive\n * strings. All other values are returned unchanged so that `JSON.stringify` handles them\n * normally.\n *\n * Exported for direct unit testing so the default return path is reachable without going\n * through the full replacer loop.\n *\n * @param value - The raw value at the current key.\n * @returns A JSON-safe replacement value.\n */\nexport function replaceNonJsonValue(value: unknown): unknown {\n if (typeof value === \"bigint\") {\n return `${value.toString()}n`;\n }\n if (typeof value === \"symbol\") {\n // Symbol.prototype.toString() returns \"Symbol(description)\"\n return value.toString();\n }\n if (typeof value === \"function\") {\n const name = value.name;\n return name ? `[Function ${name}]` : \"[Function (anonymous)]\";\n }\n return value;\n}\n\n/**\n * Serialize `value` to a compact JSON string.\n *\n * Handles:\n * - Circular references (replaced with `\"[Circular]\"`); shared/diamond references (the same\n * object reachable via two different, non-nested paths) are NOT treated as circular and are\n * serialized in full at every location\n * - `bigint` (serialized as `\"<n>n\"`)\n * - `symbol` (serialized as `\"Symbol(description)\"`)\n * - `function` (serialized as `\"[Function name]\"`)\n * - `undefined` at the top level (returns `\"undefined\"`)\n * - Unexpected formatter errors (returns `\"[FormattingError]\"`)\n *\n * @param value - The value to serialize.\n * @returns A JSON string representation.\n */\nexport function safeStringify(value: unknown): string {\n if (value === undefined) {\n return \"undefined\";\n }\n\n // Track only the current ancestor path — not every object seen across the whole graph — so\n // that a shared/diamond reference isn't mistaken for a true circular reference. `JSON.stringify`\n // invokes the replacer depth-first with `this` bound to the holder (the object/array whose\n // property is currently being visited). Comparing `this` against the top of `stack` lets us\n // detect ascent: once we've finished a subtree and moved to the next sibling (or back up to a\n // grandparent), the holder no longer matches the stack's current top, and we trim the stack\n // back down to that holder's depth — discarding the finished subtree's entries — before\n // continuing. This mirrors the well-known \"delete on the way back up\" technique used by\n // reference circular-JSON implementations, applied here via `JSON.stringify`'s own recursion.\n const stack: unknown[] = [];\n\n try {\n return JSON.stringify(\n value,\n function replacer(this: unknown, _key: string, val: unknown): unknown {\n // Handle non-JSON primitives before the circular-ref check so that symbols and functions\n // (which are objects in some host environments) are caught early.\n if (typeof val === \"bigint\" || typeof val === \"symbol\" || typeof val === \"function\") {\n return replaceNonJsonValue(val);\n }\n\n // Circular reference detection applies to objects and arrays only.\n if (val !== null && typeof val === \"object\") {\n const holderIndex = stack.indexOf(this);\n if (holderIndex === -1) {\n // First descent into this holder's subtree.\n stack.push(this);\n } else {\n // Ascended back to (or sideways from) this holder: drop everything below it that was\n // pushed while processing a previously-visited sibling subtree.\n stack.length = holderIndex + 1;\n }\n\n if (stack.includes(val)) {\n return \"[Circular]\";\n }\n stack.push(val);\n }\n\n return val;\n }\n );\n } catch {\n // Last-resort fallback: JSON.stringify threw despite the replacer.\n // This can happen when a getter throws during property enumeration.\n return FALLBACK;\n }\n}\n","/**\n * @file An internal helper for the logging subpath — not exported from\n * `src/lib/logging/index.ts`.\n *\n * `sanitizeTerminalText()` neutralizes terminal-injection risk (SEC-007) in strings that are\n * about to be written to a real terminal by `createConsoleTransport()`. `record.message` is\n * caller-supplied and may embed attacker-controlled data (e.g. an email address or path). Left\n * unescaped, it could contain newlines that forge fake log lines, or ANSI escape sequences\n * (`\\x1b...`) that manipulate the terminal (colors, cursor movement, title changes) when the\n * output is later viewed through a real terminal such as `wrangler tail`.\n *\n * `record.context` does not need the same treatment: `createConsoleTransport()` always renders\n * it via `safeStringify()` (`JSON.stringify` under the hood), which already escapes every C0\n * control character — including `\\x1b` — as `\\uXXXX` per the JSON spec.\n */\n\n/**\n * Control characters (C0: `\\x00`-`\\x1f`, plus DEL `\\x7f`) that could forge terminal output or\n * trigger ANSI escape sequences. Every terminal escape sequence begins with `\\x1b` (ESC), so\n * escaping it alone is sufficient to neutralize ANSI injection; the rest of the range is\n * escaped defensively for the same reason.\n */\nconst CONTROL_CHAR_PATTERN = /[\\x00-\\x1f\\x7f]/g;\n\n/** Readable escape sequences for the most common control characters. */\nconst NAMED_ESCAPES: Readonly<Record<string, string>> = {\n \"\\n\": \"\\\\n\",\n \"\\r\": \"\\\\r\",\n \"\\t\": \"\\\\t\"\n};\n\n/**\n * Replace every C0 control character and DEL in `value` with a visible, non-executable escape\n * sequence.\n *\n * Common whitespace controls (`\\n`, `\\r`, `\\t`) are rendered as their familiar backslash\n * escapes; every other control character (including ESC, `\\x1b`) is rendered as a two-digit hex\n * escape (`\\xHH`). This preserves the original information for debugging while preventing the\n * string from forging additional log lines or executing terminal escape sequences.\n *\n * @param value - The raw string to sanitize before writing it to a terminal.\n * @returns `value` with every control character replaced by a visible escape sequence.\n */\nexport function sanitizeTerminalText(value: string): string {\n return value.replace(CONTROL_CHAR_PATTERN, (char) => {\n const named = NAMED_ESCAPES[char];\n if (named !== undefined) {\n return named;\n }\n return `\\\\x${char.charCodeAt(0).toString(16).padStart(2, \"0\")}`;\n });\n}\n","/**\n * @file A transport that formats records as human-readable single-line output intended for\n * terminal environments including `wrangler dev`.\n *\n * `createConsoleTransport()` supports optional ANSI color codes and configurable timestamp\n * formats.\n *\n * `record.message` is sanitized via `sanitizeTerminalText()` (SEC-007) before it is written,\n * escaping control/ANSI characters so caller-supplied data cannot forge additional log lines or\n * inject terminal escape sequences when the output is later viewed in a real terminal (e.g.\n * `wrangler tail`).\n *\n * Level-to-method mapping:\n * trace, debug, info → console.log\n * warn, error, fatal → console.error\n *\n * Output format:\n * [timestamp] LEVEL message [{\"key\":\"value\"}]\n */\nimport { getConsoleMethod } from \"../internal/console.js\";\nimport type { ConsoleLike } from \"../internal/console.js\";\nimport { safeStringify } from \"../internal/safe-json.js\";\nimport { sanitizeTerminalText } from \"../internal/sanitize.js\";\nimport { valueOrDefault } from \"../../guards/index.js\";\nimport type { ConsoleTransportOptions, LogLevel, LogRecord, Transport } from \"../types.js\";\n\n// ---------------------------------------------------------------------------\n// ANSI color codes\n// ---------------------------------------------------------------------------\n\nconst RESET = \"\\x1b[0m\";\n\n/** Map each level to its ANSI color code. */\nconst LEVEL_COLOR: Readonly<Record<LogLevel, string>> = {\n trace: \"\\x1b[90m\", // dark gray\n debug: \"\\x1b[37m\", // white\n info: \"\\x1b[36m\", // cyan\n warn: \"\\x1b[33m\", // yellow\n error: \"\\x1b[31m\", // red\n fatal: \"\\x1b[35m\" // magenta\n};\n\n// ---------------------------------------------------------------------------\n// Timestamp helpers\n// ---------------------------------------------------------------------------\n\n/**\n * Extract an `HH:MM:SS` time string from an ISO 8601 timestamp. Falls back to the first 8\n * characters if the expected `T` separator is absent.\n *\n * Exported for direct unit testing of the fallback branch.\n *\n * @param isoString - An ISO 8601 timestamp string.\n * @returns The `HH:MM:SS` portion, or the first 8 characters if no `T` separator is found.\n */\nexport function extractTime(isoString: string): string {\n const tIndex = isoString.indexOf(\"T\");\n if (tIndex === -1) {\n return isoString.slice(0, 8);\n }\n return isoString.slice(tIndex + 1, tIndex + 9);\n}\n\n// ---------------------------------------------------------------------------\n// Level label helpers\n// ---------------------------------------------------------------------------\n\n/** Fixed-width (5 chars) uppercase level labels. */\nconst LEVEL_LABEL: Readonly<Record<LogLevel, string>> = {\n trace: \"TRACE\",\n debug: \"DEBUG\",\n info: \"INFO \",\n warn: \"WARN \",\n error: \"ERROR\",\n fatal: \"FATAL\"\n};\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Create a console transport for terminal/wrangler dev output.\n *\n * @param options - Timestamp and color options.\n * @param _console - Injected console-like object (defaults to global `console`). Used in tests.\n * @returns A `Transport` that writes formatted lines to the terminal.\n */\nexport function createConsoleTransport(\n options?: ConsoleTransportOptions,\n _console: ConsoleLike = console\n): Transport {\n const colors = valueOrDefault(options?.colors, true);\n const timestamp = valueOrDefault(options?.timestamp, \"time\");\n\n return {\n log(record: LogRecord): void {\n // Choose sink: warn/error/fatal → stderr, rest → stdout.\n const isError =\n record.level === \"warn\" || record.level === \"error\" || record.level === \"fatal\";\n const method = getConsoleMethod(_console, isError ? \"error\" : \"log\");\n\n // Build the line parts.\n const parts: string[] = [];\n\n // Timestamp prefix.\n if (timestamp === \"time\") {\n const ts = extractTime(record.time);\n parts.push(colors ? `\\x1b[90m${ts}${RESET}` : ts);\n } else if (timestamp === \"iso\") {\n parts.push(colors ? `\\x1b[90m${record.time}${RESET}` : record.time);\n }\n\n // Level label.\n const label = LEVEL_LABEL[record.level];\n if (colors) {\n const color = LEVEL_COLOR[record.level];\n parts.push(`${color}${label}${RESET}`);\n } else {\n parts.push(label);\n }\n\n // Message (sanitized — see SEC-007 note in the file header above).\n parts.push(sanitizeTerminalText(record.message));\n\n // Context (compact safe JSON, omitted when empty). `safeStringify` delegates to\n // `JSON.stringify`, which already escapes every C0 control character (including ESC) per\n // the JSON spec, so no additional sanitization is needed here.\n const hasContext = Object.keys(record.context).length > 0;\n if (hasContext) {\n parts.push(safeStringify(record.context));\n }\n\n method(parts.join(\" \"));\n }\n };\n}\n","/**\n * @file A transport that emits records as structured payloads intended for Cloudflare Workers\n * Logs.\n *\n * Workers Logs automatically extracts and indexes fields from JSON object logs, so\n * `createStructuredTransport()` defaults to object logging (`stringify: false`) rather than\n * string logging.\n *\n * Payload shape: `{ time, level, message, ...context }`\n * Reserved keys (`time`, `level`, `message`) from the record take precedence over identically\n * named context keys.\n *\n * Level-to-method mapping:\n * trace, debug → console.debug\n * info → console.log\n * warn → console.warn\n * error, fatal → console.error\n */\nimport { getConsoleMethod } from \"../internal/console.js\";\nimport type { ConsoleLike, ConsoleMethodName } from \"../internal/console.js\";\nimport { safeStringify } from \"../internal/safe-json.js\";\nimport { valueOrDefault } from \"../../guards/index.js\";\nimport type { LogLevel, LogRecord, StructuredTransportOptions, Transport } from \"../types.js\";\n\n/** Map each log level to the preferred console method name. */\nconst LEVEL_METHOD: Readonly<Record<LogLevel, ConsoleMethodName>> = {\n trace: \"debug\",\n debug: \"debug\",\n info: \"log\",\n warn: \"warn\",\n error: \"error\",\n fatal: \"error\"\n};\n\n/**\n * Create a structured transport for Cloudflare Workers Logs.\n *\n * @param options - Optional stringify flag.\n * @param _console - Injected console-like object (defaults to global `console`). Used in tests.\n * @returns A `Transport` that writes structured payloads to the console.\n */\nexport function createStructuredTransport(\n options?: StructuredTransportOptions,\n _console: ConsoleLike = console\n): Transport {\n const stringify = valueOrDefault(options?.stringify, false);\n\n return {\n log(record: LogRecord): void {\n const methodName = LEVEL_METHOD[record.level];\n const method = getConsoleMethod(_console, methodName);\n\n // Build payload: context spread first, then reserved keys override.\n const payload: Record<string, unknown> = {\n ...record.context,\n time: record.time,\n level: record.level,\n message: record.message\n };\n\n if (stringify) {\n method(safeStringify(payload));\n } else {\n method(payload);\n }\n }\n };\n}\n","/**\n * @file A default-config helper that maps an environment + runtime pair to a ready-to-use\n * `{ level, transport }` pair.\n *\n * `resolveLoggerConfig()` is optional policy — `createLogger` does not require it. Applications\n * that need environment-specific configuration without hand-wiring transports can call this\n * helper and pass the result directly to `createLogger`.\n *\n * Policy table:\n *\n * | Environment | Runtime | Level | Transport |\n * |---------------|-----------|---------|------------|\n * | test | browser | trace | capture |\n * | test | worker | trace | capture |\n * | development | browser | info | browser |\n * | development | worker | debug | console |\n * | production | browser | warn | browser |\n * | production | worker | warn | structured |\n * | unknown | browser | warn | browser |\n * | unknown | worker | warn | structured |\n *\n * There is no `detectRuntime()` helper in the public API. Applications are expected to know\n * whether they are constructing a browser logger or a Worker logger.\n */\nimport { createBrowserTransport } from \"./transports/browser.js\";\nimport { createCaptureTransport } from \"./transports/capture.js\";\nimport { createConsoleTransport } from \"./transports/console.js\";\nimport { createStructuredTransport } from \"./transports/structured.js\";\nimport type { Environment, ResolvedLoggerConfig, Runtime } from \"./types.js\";\n\n/**\n * Resolve a `{ level, transport }` configuration for the given environment and runtime.\n *\n * Each call creates a **fresh** transport instance. If you call this helper more than once with\n * the same arguments you will receive independent transport instances, which is intentional for\n * test isolation.\n *\n * Unknown or `undefined` environments are treated as `\"production\"`.\n *\n * @param environment - One of `\"test\"`, `\"development\"`, `\"production\"`, or any other string.\n * `undefined` maps to production behavior.\n * @param runtime - Either `\"browser\"` or `\"worker\"`.\n * @returns A fresh `ResolvedLoggerConfig` ready to pass to `createLogger`.\n */\nexport function resolveLoggerConfig(\n environment: Environment | undefined,\n runtime: Runtime\n): ResolvedLoggerConfig {\n // Normalise: anything that is not a recognised well-known string falls through to the\n // production defaults.\n const env = environment === \"test\" || environment === \"development\" ? environment : \"production\";\n\n if (env === \"test\") {\n return { level: \"trace\", transport: createCaptureTransport() };\n }\n\n if (env === \"development\") {\n if (runtime === \"browser\") {\n return { level: \"info\", transport: createBrowserTransport() };\n }\n // runtime === \"worker\"\n return { level: \"debug\", transport: createConsoleTransport() };\n }\n\n // production (and all unknown / undefined environments)\n if (runtime === \"browser\") {\n return { level: \"warn\", transport: createBrowserTransport() };\n }\n // runtime === \"worker\"\n return { level: \"warn\", transport: createStructuredTransport() };\n}\n","/**\n * @file A no-op transport that discards every record without emitting anything to the console\n * and without throwing. Use it in contexts where logging should be fully suppressed.\n */\nimport type { Transport } from \"../types.js\";\n\n/**\n * Create a silent transport that discards all records.\n *\n * @returns A `Transport` that does nothing.\n */\nexport function createSilentTransport(): Transport {\n return {\n log(): void {\n // Intentionally empty — records are dropped without side effects.\n }\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import "jose";
|
|
2
|
+
//#region src/lib/auth-internal/jwt.d.ts
|
|
3
|
+
/** Name of the cookie that stores the JWT. */
|
|
4
|
+
declare const COOKIE_NAME = "CF_Authorization";
|
|
5
|
+
/** Header containing the JWT (set by Cloudflare Access). */
|
|
6
|
+
declare const JWT_HEADER = "cf-access-jwt-assertion";
|
|
7
|
+
/**
|
|
8
|
+
* Create a signed JWT that mimics a Cloudflare Access token.
|
|
9
|
+
*
|
|
10
|
+
* The `type` claim is set to `"dev"` so that the verification layer can distinguish
|
|
11
|
+
* locally-issued tokens from real Access tokens.
|
|
12
|
+
*
|
|
13
|
+
* @param email - The user's email address (becomes the `email` claim).
|
|
14
|
+
* @param options - Optional overrides.
|
|
15
|
+
* @param options.secret - HMAC signing secret (default {@link DEFAULT_DEV_SECRET}).
|
|
16
|
+
* @param options.lifetime - Token lifetime in seconds (default `86400` / 24 h).
|
|
17
|
+
* @param options.sub - Subject claim. When provided it is used **verbatim**; when omitted a
|
|
18
|
+
* random UUID is generated (matching the shape of a real Cloudflare Access `sub`) instead of
|
|
19
|
+
* an email-derived value.
|
|
20
|
+
*/
|
|
21
|
+
declare function signDevJwt(email: string, options?: {
|
|
22
|
+
secret?: string;
|
|
23
|
+
lifetime?: number;
|
|
24
|
+
sub?: string;
|
|
25
|
+
}): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Build a `Set-Cookie` header value for the authorisation cookie.
|
|
28
|
+
*
|
|
29
|
+
* Mirrors the attributes used by Cloudflare Access: `HttpOnly; Secure; SameSite=Lax; Path=/`
|
|
30
|
+
*
|
|
31
|
+
* For local dev over plain HTTP the `Secure` flag is omitted when the request was made to
|
|
32
|
+
* `localhost` or `127.0.0.1`.
|
|
33
|
+
*/
|
|
34
|
+
declare function buildCookieHeader(token: string, isSecure: boolean): string;
|
|
35
|
+
/**
|
|
36
|
+
* Build a `Set-Cookie` header that clears the `CF_Authorization` cookie by setting it to an
|
|
37
|
+
* empty value with `Max-Age=0`.
|
|
38
|
+
*
|
|
39
|
+
* Use this when a stale or invalid cookie needs to be removed so the user can re-authenticate.
|
|
40
|
+
*/
|
|
41
|
+
declare function clearCookieHeader(): string;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { COOKIE_NAME, JWT_HEADER, buildCookieHeader, clearCookieHeader, signDevJwt };
|
|
44
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
//#region src/lib/problem-details/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @file Core RFC 9457 Problem Details types: the `ProblemDetails` object shape and the
|
|
4
|
+
* `ProblemDetailsInput` accepted by the `problemDetails()` factory.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* RFC 9457 Problem Details object.
|
|
8
|
+
* Supports 5 standard fields + extension members.
|
|
9
|
+
*/
|
|
10
|
+
interface ProblemDetails<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
11
|
+
/** Problem type URI. Default: "about:blank" */
|
|
12
|
+
type: string;
|
|
13
|
+
/** HTTP status code */
|
|
14
|
+
status: number;
|
|
15
|
+
/** Short summary of the problem type */
|
|
16
|
+
title: string;
|
|
17
|
+
/** Human-readable explanation specific to this occurrence */
|
|
18
|
+
detail?: string;
|
|
19
|
+
/** URI that identifies the specific occurrence */
|
|
20
|
+
instance?: string;
|
|
21
|
+
/** RFC 9457 extension members (flattened to top level on serialization) */
|
|
22
|
+
extensions?: T;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Input for the {@link problemDetails} factory.
|
|
26
|
+
* `type` and `title` are optional (auto-derived from `status`).
|
|
27
|
+
*/
|
|
28
|
+
interface ProblemDetailsInput<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
29
|
+
/** HTTP status code */
|
|
30
|
+
status: number;
|
|
31
|
+
/** Problem type URI. Defaults to "about:blank" when omitted */
|
|
32
|
+
type?: string;
|
|
33
|
+
/** Short summary of the problem type. Derived from `status` when omitted */
|
|
34
|
+
title?: string;
|
|
35
|
+
/** Human-readable explanation specific to this occurrence */
|
|
36
|
+
detail?: string;
|
|
37
|
+
/** URI that identifies the specific occurrence */
|
|
38
|
+
instance?: string;
|
|
39
|
+
/** RFC 9457 extension members (flattened to top level on serialization) */
|
|
40
|
+
extensions?: T;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ProblemDetailsInput as n, ProblemDetails as t };
|
|
44
|
+
//# sourceMappingURL=types-Cx6NNILW.d.ts.map
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
//#region src/lib/logging/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* @file Core public types for the logging subpath.
|
|
4
|
+
*
|
|
5
|
+
* These types form the stable public contract for the logging core. Numeric level values are
|
|
6
|
+
* fixed once released; the string `LogLevel` union is the primary API surface for TypeScript
|
|
7
|
+
* consumers.
|
|
8
|
+
*
|
|
9
|
+
* Note: `src/cli/generate-wrangler-types/logger.ts` defines its own, deliberately separate
|
|
10
|
+
* `Logger`/`LogLevel` pair for colored stderr CLI output — it is not a consumer of this
|
|
11
|
+
* `Transport`-based contract. See that file's header for why the split is intentional
|
|
12
|
+
* (ARCH-003, `docs/specs/SPECv2.md` §12.3).
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The six severity levels supported by the logger, ordered from lowest to highest: `trace <
|
|
16
|
+
* debug < info < warn < error < fatal`.
|
|
17
|
+
*
|
|
18
|
+
* Numeric weights are exposed on `LogRecord.levelValue`.
|
|
19
|
+
*/
|
|
20
|
+
type LogLevel = "trace" | "debug" | "info" | "warn" | "error" | "fatal";
|
|
21
|
+
/**
|
|
22
|
+
* Arbitrary structured key-value pairs attached to a log record.
|
|
23
|
+
*
|
|
24
|
+
* Values may be any JSON-compatible type. Top-level `Error` values are serialized to plain
|
|
25
|
+
* objects by the logger before transport delivery.
|
|
26
|
+
*/
|
|
27
|
+
type LogContext = Record<string, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* An immutable, fully-resolved log record delivered to transports.
|
|
30
|
+
*
|
|
31
|
+
* The logger creates exactly one record per enabled log call. Transports receive the record
|
|
32
|
+
* after level filtering and context serialization.
|
|
33
|
+
*/
|
|
34
|
+
interface LogRecord {
|
|
35
|
+
/** ISO 8601 timestamp produced by the logger's clock at emit time. */
|
|
36
|
+
readonly time: string;
|
|
37
|
+
/** String severity level of this record. */
|
|
38
|
+
readonly level: LogLevel;
|
|
39
|
+
/** Numeric weight of `level`. */
|
|
40
|
+
readonly levelValue: number;
|
|
41
|
+
/** Human-readable description of the event. */
|
|
42
|
+
readonly message: string;
|
|
43
|
+
/** Merged bindings and per-call context. Top-level `Error` values have been serialized. */
|
|
44
|
+
readonly context: LogContext;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* The minimum interface a transport must implement.
|
|
48
|
+
*
|
|
49
|
+
* `log` is called synchronously for every record that passes level filtering. Built-in
|
|
50
|
+
* transports must not throw; the logger wraps all transport calls in try/catch and routes
|
|
51
|
+
* failures through `onTransportError`.
|
|
52
|
+
*/
|
|
53
|
+
interface Transport {
|
|
54
|
+
/** Deliver `record` to the transport's destination. */
|
|
55
|
+
log(record: LogRecord): void;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Optional callback invoked when a transport's `log` method throws.
|
|
59
|
+
*
|
|
60
|
+
* Receives the thrown value and the record that triggered the failure. Any exception thrown by
|
|
61
|
+
* this callback is silently swallowed by the logger.
|
|
62
|
+
*/
|
|
63
|
+
type TransportErrorHandler = (error: unknown, record: LogRecord) => void;
|
|
64
|
+
/**
|
|
65
|
+
* Options accepted by `createLogger`.
|
|
66
|
+
*/
|
|
67
|
+
interface CreateLoggerOptions {
|
|
68
|
+
/**
|
|
69
|
+
* Minimum severity level to emit. Records below this level are dropped before context is
|
|
70
|
+
* accessed. Defaults to `"info"`.
|
|
71
|
+
*/
|
|
72
|
+
readonly level?: LogLevel;
|
|
73
|
+
/** Transport to receive emitted records. Required. */
|
|
74
|
+
readonly transport: Transport;
|
|
75
|
+
/**
|
|
76
|
+
* Key-value pairs merged into every record's context. Per-call context wins on key collision.
|
|
77
|
+
* Defaults to `{}`.
|
|
78
|
+
*/
|
|
79
|
+
readonly bindings?: LogContext;
|
|
80
|
+
/**
|
|
81
|
+
* Clock used to produce `record.time`. Defaults to `() => new Date()`. Override in tests for
|
|
82
|
+
* deterministic timestamps.
|
|
83
|
+
*/
|
|
84
|
+
readonly clock?: () => Date;
|
|
85
|
+
/**
|
|
86
|
+
* Called when the transport throws. Receives the error and the record that triggered it.
|
|
87
|
+
* Exceptions thrown by this callback are swallowed.
|
|
88
|
+
*/
|
|
89
|
+
readonly onTransportError?: TransportErrorHandler;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* The public logging interface returned by `createLogger` and `child`.
|
|
93
|
+
*
|
|
94
|
+
* Each level method checks `isLevelEnabled` before touching the context argument, so disabled
|
|
95
|
+
* calls impose no observable side effects.
|
|
96
|
+
*/
|
|
97
|
+
interface Logger {
|
|
98
|
+
/** Emit a `trace`-level record. No-op when `trace` is below the configured level. */
|
|
99
|
+
trace(message: string, context?: LogContext): void;
|
|
100
|
+
/** Emit a `debug`-level record. No-op when `debug` is below the configured level. */
|
|
101
|
+
debug(message: string, context?: LogContext): void;
|
|
102
|
+
/** Emit an `info`-level record. No-op when `info` is below the configured level. */
|
|
103
|
+
info(message: string, context?: LogContext): void;
|
|
104
|
+
/** Emit a `warn`-level record. No-op when `warn` is below the configured level. */
|
|
105
|
+
warn(message: string, context?: LogContext): void;
|
|
106
|
+
/** Emit an `error`-level record. No-op when `error` is below the configured level. */
|
|
107
|
+
error(message: string, context?: LogContext): void;
|
|
108
|
+
/** Emit a `fatal`-level record. No-op when `fatal` is below the configured level. */
|
|
109
|
+
fatal(message: string, context?: LogContext): void;
|
|
110
|
+
/**
|
|
111
|
+
* Return a new logger that inherits this logger's transport, level, clock, and error handler,
|
|
112
|
+
* with `bindings` merged on top of the parent's bindings. The parent logger is not affected.
|
|
113
|
+
*/
|
|
114
|
+
child(bindings: LogContext): Logger;
|
|
115
|
+
/** The minimum severity level this logger will emit. */
|
|
116
|
+
readonly level: LogLevel;
|
|
117
|
+
/** Returns `true` when records at `level` will be emitted by this logger. */
|
|
118
|
+
isLevelEnabled(level: LogLevel): boolean;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Environment hint for `resolveLoggerConfig`.
|
|
122
|
+
* The `(string & {})` tail keeps the type open for custom environment names while preserving
|
|
123
|
+
* autocomplete for the well-known values.
|
|
124
|
+
*/
|
|
125
|
+
type Environment = "test" | "development" | "production" | (string & {});
|
|
126
|
+
/** Runtime hint for `resolveLoggerConfig`. */
|
|
127
|
+
type Runtime = "browser" | "worker";
|
|
128
|
+
/** Output of `resolveLoggerConfig`. */
|
|
129
|
+
interface ResolvedLoggerConfig {
|
|
130
|
+
/** Minimum severity level selected for the environment and runtime. */
|
|
131
|
+
readonly level: LogLevel;
|
|
132
|
+
/** Transport selected for the environment and runtime. */
|
|
133
|
+
readonly transport: Transport;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Options for `createBrowserTransport`.
|
|
137
|
+
* `levelStyles` allows overriding the CSS style string applied to the level badge for any subset
|
|
138
|
+
* of levels.
|
|
139
|
+
*/
|
|
140
|
+
interface BrowserTransportOptions {
|
|
141
|
+
/**
|
|
142
|
+
* CSS style strings applied to the level badge via `%c` in `console` calls. Provide only the
|
|
143
|
+
* levels you want to override; unspecified levels use the transport's built-in defaults.
|
|
144
|
+
*/
|
|
145
|
+
readonly levelStyles?: Partial<Record<LogLevel, string>>;
|
|
146
|
+
}
|
|
147
|
+
/** Options for `createConsoleTransport`. */
|
|
148
|
+
interface ConsoleTransportOptions {
|
|
149
|
+
/**
|
|
150
|
+
* Whether to emit ANSI color codes in the output. Defaults to `true`. Set to `false` for CI
|
|
151
|
+
* environments or when piping output to a file.
|
|
152
|
+
*/
|
|
153
|
+
readonly colors?: boolean;
|
|
154
|
+
/**
|
|
155
|
+
* Controls the timestamp prefix on each line.
|
|
156
|
+
*
|
|
157
|
+
* - `"time"` — concise `HH:MM:SS` derived from `record.time` (default).
|
|
158
|
+
* - `"iso"` — full ISO 8601 string from `record.time`.
|
|
159
|
+
* - `false` — no timestamp.
|
|
160
|
+
*/
|
|
161
|
+
readonly timestamp?: "time" | "iso" | false;
|
|
162
|
+
}
|
|
163
|
+
/** Options for `createStructuredTransport`. */
|
|
164
|
+
interface StructuredTransportOptions {
|
|
165
|
+
/**
|
|
166
|
+
* When `true`, serializes the payload to a JSON string before passing it to the console
|
|
167
|
+
* method. When `false` (default), passes a plain object so that Cloudflare Workers Logs can
|
|
168
|
+
* extract and index individual fields.
|
|
169
|
+
*/
|
|
170
|
+
readonly stringify?: boolean;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* `CaptureTransport` extends `Transport` with test-ergonomic helpers.
|
|
174
|
+
*
|
|
175
|
+
* `.find(level)` is the preferred way to assert on records at a specific level in tests; it
|
|
176
|
+
* avoids iterating `.records` manually.
|
|
177
|
+
*/
|
|
178
|
+
interface CaptureTransport extends Transport {
|
|
179
|
+
/**
|
|
180
|
+
* Read-only ordered list of all records received since the last `clear()`. Returns an
|
|
181
|
+
* immutable snapshot; mutating the returned value does not affect internal storage.
|
|
182
|
+
*/
|
|
183
|
+
readonly records: readonly LogRecord[];
|
|
184
|
+
/** Remove all stored records. */
|
|
185
|
+
clear(): void;
|
|
186
|
+
/**
|
|
187
|
+
* Return all stored records whose `level` matches `level`.
|
|
188
|
+
*
|
|
189
|
+
* Preferred over filtering `.records` manually in test assertions.
|
|
190
|
+
*/
|
|
191
|
+
find(level: LogLevel): readonly LogRecord[];
|
|
192
|
+
}
|
|
193
|
+
//#endregion
|
|
194
|
+
export { Environment as a, LogRecord as c, Runtime as d, StructuredTransportOptions as f, CreateLoggerOptions as i, Logger as l, TransportErrorHandler as m, CaptureTransport as n, LogContext as o, Transport as p, ConsoleTransportOptions as r, LogLevel as s, BrowserTransportOptions as t, ResolvedLoggerConfig as u };
|
|
195
|
+
//# sourceMappingURL=types-DCSMb1cp.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/lib/auth-internal/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A single path-matching rule used to decide whether a request requires authentication.
|
|
4
|
+
*
|
|
5
|
+
* Policies are evaluated in order; the **first match wins**.
|
|
6
|
+
*/
|
|
7
|
+
interface PathPolicy {
|
|
8
|
+
/** Regular expression tested against the request pathname. */
|
|
9
|
+
pattern: RegExp;
|
|
10
|
+
/**
|
|
11
|
+
* `true` - the matching path requires authentication.
|
|
12
|
+
* `false` - the matching path is public / anonymous.
|
|
13
|
+
*/
|
|
14
|
+
authenticate: boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Controls the response when an unauthenticated request hits this path in a consuming
|
|
17
|
+
* dev-emulation layer (e.g. `cloudflareAccessPlugin`):
|
|
18
|
+
*
|
|
19
|
+
* - `true` *(default)* — redirect to a login form. Appropriate for page routes where the
|
|
20
|
+
* browser should navigate to a login UI.
|
|
21
|
+
* - `false` — return 401 instead of redirecting. Appropriate for API routes.
|
|
22
|
+
*
|
|
23
|
+
* Only meaningful when `authenticate` is `true`.
|
|
24
|
+
*/
|
|
25
|
+
redirect?: boolean;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { PathPolicy as t };
|
|
29
|
+
//# sourceMappingURL=types-DXboaWOT.d.ts.map
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { t as PathPolicy } from "../types-DXboaWOT.js";
|
|
2
|
+
import { Plugin } from "vite";
|
|
3
|
+
//#region src/lib/vite/login-page.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* @file The HTML template for the Vite dev-server login page rendered by `cloudflareAccessPlugin`
|
|
6
|
+
* (./plugin.ts). A pure HTML-string builder with no dependency on `auth-internal` or any other
|
|
7
|
+
* runtime module.
|
|
8
|
+
*/
|
|
9
|
+
/** A selectable identity rendered on the dev login form. */
|
|
10
|
+
interface DevLoginUser {
|
|
11
|
+
/** Email address used as the JWT `email` claim. */
|
|
12
|
+
email: string;
|
|
13
|
+
/** Optional human-friendly display name. */
|
|
14
|
+
name?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Optional subject claim to pin for this identity.
|
|
17
|
+
*
|
|
18
|
+
* When provided it is used **verbatim** as the JWT `sub` so the identity has a stable,
|
|
19
|
+
* realistic subject across logins. When omitted a random UUID is generated each time the user
|
|
20
|
+
* signs in (matching the shape of a real Cloudflare Access `sub`).
|
|
21
|
+
*/
|
|
22
|
+
sub?: string;
|
|
23
|
+
}
|
|
24
|
+
//#endregion
|
|
25
|
+
//#region src/lib/vite/plugin.d.ts
|
|
26
|
+
/** Configuration for {@link cloudflareAccessPlugin}. */
|
|
27
|
+
interface CloudflareAccessPluginOptions {
|
|
28
|
+
/**
|
|
29
|
+
* Path policies evaluated in order (first match wins).
|
|
30
|
+
*
|
|
31
|
+
* Pass the **same array** you give to `cloudflareAccess` in the Worker
|
|
32
|
+
* (../hono/cloudflare-access.ts) so dev and prod agree on which paths are protected.
|
|
33
|
+
*
|
|
34
|
+
* - `authenticate: false` — public (no gating, no header injection).
|
|
35
|
+
* - `authenticate: true` — protected. Unauthenticated navigations are redirected to the login
|
|
36
|
+
* form; API routes with `redirect: false` receive a 401.
|
|
37
|
+
*
|
|
38
|
+
* When omitted, **all** non-internal paths are treated as protected.
|
|
39
|
+
*/
|
|
40
|
+
policies?: PathPolicy[];
|
|
41
|
+
/**
|
|
42
|
+
* HMAC secret used to sign the dev JWT.
|
|
43
|
+
*
|
|
44
|
+
* Must match the `devSecret` passed to `cloudflareAccess` in the Worker (if overridden there).
|
|
45
|
+
* Defaults to the same well-known development key.
|
|
46
|
+
*/
|
|
47
|
+
devSecret?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Selectable identities rendered on the dev login form. When omitted the form shows a single
|
|
50
|
+
* free-text email input.
|
|
51
|
+
*/
|
|
52
|
+
users?: DevLoginUser[];
|
|
53
|
+
/** Pathname for the login form (default `"/cdn-cgi/access/login"`). */
|
|
54
|
+
loginPath?: string;
|
|
55
|
+
/** Dev JWT lifetime in seconds (default `86400` / 24 h). */
|
|
56
|
+
tokenLifetime?: number;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Create the dev-only Cloudflare Access emulation plugin.
|
|
60
|
+
*
|
|
61
|
+
* Register it **before** `@cloudflare/vite-plugin` (and any framework plugin) so its connect
|
|
62
|
+
* middleware runs first:
|
|
63
|
+
*
|
|
64
|
+
* ```ts
|
|
65
|
+
* plugins: [cloudflareAccessPlugin(), cloudflare(), react()]
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* The middleware is registered synchronously in the `configureServer` hook body (combined with
|
|
69
|
+
* `enforce: "pre"`) so that it sits ahead of the request → `workerd` dispatch handler that
|
|
70
|
+
* `@cloudflare/vite-plugin` registers from its post hook.
|
|
71
|
+
*
|
|
72
|
+
* @param options - Configuration for path policies, the dev secret, selectable login identities,
|
|
73
|
+
* the login form path, and the dev token lifetime.
|
|
74
|
+
* @returns A Vite `Plugin`.
|
|
75
|
+
*/
|
|
76
|
+
declare function cloudflareAccessPlugin(options?: CloudflareAccessPluginOptions): Plugin;
|
|
77
|
+
//#endregion
|
|
78
|
+
export { type CloudflareAccessPluginOptions, cloudflareAccessPlugin };
|
|
79
|
+
//# sourceMappingURL=index.d.ts.map
|