@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.
Files changed (51) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +59 -0
  3. package/THIRD-PARTY-NOTICES.md +75 -0
  4. package/dist/cli/generate-wrangler-types/index.d.ts +1 -0
  5. package/dist/cli/generate-wrangler-types/index.js +329 -0
  6. package/dist/cli/generate-wrangler-types/index.js.map +1 -0
  7. package/dist/error-CLYcAvBM.d.ts +28 -0
  8. package/dist/errors/index.d.ts +2 -0
  9. package/dist/errors/index.js +3 -0
  10. package/dist/errors-Ciipq_zr.js +58 -0
  11. package/dist/errors-Ciipq_zr.js.map +1 -0
  12. package/dist/factory-BI5gVL_P.js +220 -0
  13. package/dist/factory-BI5gVL_P.js.map +1 -0
  14. package/dist/generators-D8WWEHa1.js +165 -0
  15. package/dist/generators-D8WWEHa1.js.map +1 -0
  16. package/dist/guards/index.d.ts +2 -0
  17. package/dist/guards/index.js +2 -0
  18. package/dist/guards-6K1CVAr5.js +61 -0
  19. package/dist/guards-6K1CVAr5.js.map +1 -0
  20. package/dist/hono/index.d.ts +347 -0
  21. package/dist/hono/index.js +307 -0
  22. package/dist/hono/index.js.map +1 -0
  23. package/dist/index-434HN8jN.d.ts +43 -0
  24. package/dist/index-Byl-ZrCy.d.ts +138 -0
  25. package/dist/index-CUICemFw.d.ts +129 -0
  26. package/dist/index-DRIhR-Xn.d.ts +81 -0
  27. package/dist/index.d.ts +8 -0
  28. package/dist/index.js +8 -0
  29. package/dist/jwt-BvuKtvby.js +328 -0
  30. package/dist/jwt-BvuKtvby.js.map +1 -0
  31. package/dist/logging/index.d.ts +3 -0
  32. package/dist/logging/index.js +3 -0
  33. package/dist/logging-CGHjOVLM.js +24 -0
  34. package/dist/logging-CGHjOVLM.js.map +1 -0
  35. package/dist/policy-CvS6AvvD.js +20 -0
  36. package/dist/policy-CvS6AvvD.js.map +1 -0
  37. package/dist/problem-details/index.d.ts +4 -0
  38. package/dist/problem-details/index.js +3 -0
  39. package/dist/problem-details-CuRsLy3Q.js +37 -0
  40. package/dist/problem-details-CuRsLy3Q.js.map +1 -0
  41. package/dist/silent-CWpHE65X.js +652 -0
  42. package/dist/silent-CWpHE65X.js.map +1 -0
  43. package/dist/testing/index.d.ts +44 -0
  44. package/dist/testing/index.js +2 -0
  45. package/dist/types-Cx6NNILW.d.ts +44 -0
  46. package/dist/types-DCSMb1cp.d.ts +195 -0
  47. package/dist/types-DXboaWOT.d.ts +29 -0
  48. package/dist/vite/index.d.ts +79 -0
  49. package/dist/vite/index.js +417 -0
  50. package/dist/vite/index.js.map +1 -0
  51. package/package.json +137 -0
@@ -0,0 +1,652 @@
1
+ import { r as valueOrDefault } from "./guards-6K1CVAr5.js";
2
+ //#region src/lib/logging/levels.ts
3
+ /**
4
+ * Stable numeric weights for each log level.
5
+ *
6
+ * A record is emitted when: `LOG_LEVELS[record.level] >= LOG_LEVELS[logger.level]`
7
+ */
8
+ const LOG_LEVELS = {
9
+ trace: 10,
10
+ debug: 20,
11
+ info: 30,
12
+ warn: 40,
13
+ error: 50,
14
+ fatal: 60
15
+ };
16
+ /**
17
+ * Return the numeric weight for `level`.
18
+ *
19
+ * Throws a `TypeError` for any value that is not a recognized `LogLevel`. TypeScript consumers
20
+ * should rely on the `LogLevel` union type and never reach this error path under normal usage.
21
+ * Deliberately not implemented with `throwIfNull`: this throws a `TypeError` for an unrecognized
22
+ * string, not a `null`/`undefined` guard, so using that helper would change the thrown error
23
+ * type.
24
+ *
25
+ * @param level - The level to look up.
26
+ * @returns The numeric weight for `level`.
27
+ * @throws {TypeError} If `level` is not one of the six recognized `LogLevel` values.
28
+ */
29
+ function levelValue(level) {
30
+ const value = LOG_LEVELS[level];
31
+ if (value === void 0) throw new TypeError(`Unknown log level: ${String(level)}. Expected one of: ${Object.keys(LOG_LEVELS).join(", ")}`);
32
+ return value;
33
+ }
34
+ //#endregion
35
+ //#region src/lib/logging/internal/optional-field.ts
36
+ /**
37
+ * @file An internal helper for the logging subpath — not one of the toolkit's public defensive
38
+ * guards (`src/lib/guards`) and not exported from `src/lib/logging/index.ts`.
39
+ */
40
+ /**
41
+ * Returns `{ [prop]: o[prop] }` when `prop` is an own property of `o` with a non-`undefined`
42
+ * value, otherwise returns `{}`.
43
+ *
44
+ * Intended for safely spreading optional fields onto plain objects without introducing
45
+ * `undefined`-valued keys:
46
+ *
47
+ * ```ts
48
+ * const result = {
49
+ * name: err.name,
50
+ * ...optionalField(err, "stack"),
51
+ * };
52
+ * ```
53
+ *
54
+ * @param o - The object to read `prop` from.
55
+ * @param prop - The property to conditionally include.
56
+ * @returns `{ [prop]: o[prop] }` when defined, otherwise `{}`.
57
+ */
58
+ function optionalField(o, prop) {
59
+ return o[prop] !== void 0 ? { [prop]: o[prop] } : {};
60
+ }
61
+ //#endregion
62
+ //#region src/lib/logging/serialize.ts
63
+ /**
64
+ * @file Error serialization for the logging subpath.
65
+ *
66
+ * `serializeError()` converts `Error` instances to plain objects so transports can safely
67
+ * forward structured context without raw `Error` values escaping into JSON serialization or
68
+ * console methods. Only top-level context values are serialized by the logger (`logger.ts`);
69
+ * nested errors are left as-is unless they appear as a direct `cause` of a top-level error.
70
+ */
71
+ /**
72
+ * Serialize `value` if it is an `Error`; return it unchanged otherwise.
73
+ *
74
+ * - Non-`Error` values are returned as-is.
75
+ * - `Error` instances become plain objects with `name`, `message`, and optionally `stack` and
76
+ * `cause`.
77
+ * - `cause` is shallowly serialized when it is itself an `Error`.
78
+ *
79
+ * @param value - The value to serialize, if it is an `Error`.
80
+ * @returns A plain-object serialization of `value` when it is an `Error`, otherwise `value`
81
+ * unchanged.
82
+ */
83
+ function serializeError(value) {
84
+ if (!(value instanceof Error)) return value;
85
+ const serialized = {
86
+ name: value.name,
87
+ message: value.message,
88
+ ...optionalField(value, "stack")
89
+ };
90
+ if (value.cause !== void 0) serialized.cause = value.cause instanceof Error ? {
91
+ name: value.cause.name,
92
+ message: value.cause.message,
93
+ ...optionalField(value.cause, "stack")
94
+ } : value.cause;
95
+ return serialized;
96
+ }
97
+ //#endregion
98
+ //#region src/lib/logging/logger.ts
99
+ /**
100
+ * @file The core logger implementation. This is the framework-agnostic core that the
101
+ * `cloudflareLogger` Hono middleware wraps — it must never import `hono`.
102
+ *
103
+ * `createLogger()` constructs a `Logger` that:
104
+ * - Filters records below the configured level before touching context.
105
+ * - Merges bindings and per-call context into a new object (never mutates input).
106
+ * - Serializes top-level `Error` values in context before delivering to transport.
107
+ * - Wraps transport delivery in try/catch so transport failures never escape.
108
+ * - Supports child loggers that inherit transport, level, clock, and error handler.
109
+ */
110
+ /**
111
+ * Internal factory used by both `createLogger` and child loggers.
112
+ *
113
+ * All logger state is captured in the closure; no class is used. Both root loggers and child
114
+ * loggers are created through this function, which keeps the child creation path identical to
115
+ * the root path.
116
+ *
117
+ * @param level - Minimum level to emit.
118
+ * @param transport - Destination for emitted records.
119
+ * @param bindings - Key-value pairs merged into every record's context.
120
+ * @param clock - Produces the timestamp for each record.
121
+ * @param onTransportError - Optional callback for transport failures.
122
+ * @returns A `Logger` bound to the supplied state.
123
+ */
124
+ function makeLogger(level, transport, bindings, clock, onTransportError) {
125
+ const currentLevelValue = levelValue(level);
126
+ /**
127
+ * Returns `true` when records at `candidate` severity will be emitted. Used both for the
128
+ * public `isLevelEnabled` method and internally before constructing a record.
129
+ *
130
+ * @param candidate - The level to test against the configured minimum level.
131
+ * @returns `true` when `candidate` is at or above the configured minimum level.
132
+ */
133
+ function isLevelEnabled(candidate) {
134
+ return levelValue(candidate) >= currentLevelValue;
135
+ }
136
+ /**
137
+ * Core emit path shared by all six level methods.
138
+ *
139
+ * Exits immediately when `logLevel` is below the configured minimum so that disabled calls
140
+ * never access the `context` argument. When enabled, merges bindings with per-call context,
141
+ * serializes top-level `Error` values, builds the `LogRecord`, and delivers it to the
142
+ * transport inside a try/catch.
143
+ *
144
+ * @param logLevel - Severity of this record.
145
+ * @param message - Human-readable description of the event.
146
+ * @param context - Optional per-call structured context.
147
+ */
148
+ function emit(logLevel, message, context) {
149
+ if (!isLevelEnabled(logLevel)) return;
150
+ const merged = context !== void 0 ? {
151
+ ...bindings,
152
+ ...context
153
+ } : { ...bindings };
154
+ const serializedContext = {};
155
+ for (const key of Object.keys(merged)) serializedContext[key] = serializeError(merged[key]);
156
+ const record = {
157
+ time: clock().toISOString(),
158
+ level: logLevel,
159
+ levelValue: levelValue(logLevel),
160
+ message,
161
+ context: serializedContext
162
+ };
163
+ try {
164
+ transport.log(record);
165
+ } catch (error) {
166
+ try {
167
+ onTransportError?.(error, record);
168
+ } catch {}
169
+ }
170
+ }
171
+ return {
172
+ get level() {
173
+ return level;
174
+ },
175
+ isLevelEnabled,
176
+ trace(message, context) {
177
+ emit("trace", message, context);
178
+ },
179
+ debug(message, context) {
180
+ emit("debug", message, context);
181
+ },
182
+ info(message, context) {
183
+ emit("info", message, context);
184
+ },
185
+ warn(message, context) {
186
+ emit("warn", message, context);
187
+ },
188
+ error(message, context) {
189
+ emit("error", message, context);
190
+ },
191
+ fatal(message, context) {
192
+ emit("fatal", message, context);
193
+ },
194
+ child(childBindings) {
195
+ return makeLogger(level, transport, {
196
+ ...bindings,
197
+ ...childBindings
198
+ }, clock, onTransportError);
199
+ }
200
+ };
201
+ }
202
+ /**
203
+ * Create a new `Logger` with the provided options.
204
+ *
205
+ * - `options.transport` is required.
206
+ * - `options.level` defaults to `"info"`.
207
+ * - `options.clock` defaults to `() => new Date()`.
208
+ * - `options.bindings` are merged into every emitted record.
209
+ * - `options.onTransportError` receives transport errors without crashing the app.
210
+ *
211
+ * @param options - Logger construction options.
212
+ * @returns A new `Logger`.
213
+ */
214
+ function createLogger(options) {
215
+ const { transport, level = "info", bindings = {}, clock = () => /* @__PURE__ */ new Date(), onTransportError } = options;
216
+ return makeLogger(level, transport, bindings, clock, onTransportError);
217
+ }
218
+ //#endregion
219
+ //#region src/lib/logging/internal/console.ts
220
+ /**
221
+ * Return the named console method from `c`, falling back to `c.log` if the method is absent or
222
+ * not a function.
223
+ *
224
+ * Rationale: logging must not crash because a host environment is missing a specific console
225
+ * method. `console.log` is the safest baseline and is present in every JS environment that
226
+ * supports `console` at all.
227
+ *
228
+ * @param c - The console-like object to query.
229
+ * @param method - The preferred method name.
230
+ * @returns The requested method if callable, otherwise `c.log`.
231
+ */
232
+ function getConsoleMethod(c, method) {
233
+ const candidate = c[method];
234
+ if (typeof candidate === "function") return candidate.bind(c);
235
+ return c.log.bind(c);
236
+ }
237
+ //#endregion
238
+ //#region src/lib/logging/transports/browser.ts
239
+ /**
240
+ * @file A transport that formats records for browser DevTools using `%c` styled level badges.
241
+ *
242
+ * `createBrowserTransport()` maps severity levels to appropriate console methods and passes the
243
+ * context object as a separate argument when non-empty, so DevTools can expand it interactively.
244
+ *
245
+ * Level-to-method mapping:
246
+ * trace, debug → console.debug
247
+ * info → console.info
248
+ * warn → console.warn
249
+ * error, fatal → console.error
250
+ */
251
+ /** Default CSS badge styles keyed by level. */
252
+ const DEFAULT_STYLES = {
253
+ trace: "color: #9ca3af; font-weight: bold",
254
+ debug: "color: #6b7280; font-weight: bold",
255
+ info: "color: #3b82f6; font-weight: bold",
256
+ warn: "color: #f59e0b; font-weight: bold",
257
+ error: "color: #ef4444; font-weight: bold",
258
+ fatal: "color: #dc2626; font-weight: bold; text-decoration: underline"
259
+ };
260
+ /** Map each log level to the preferred console method name. */
261
+ const LEVEL_METHOD$1 = {
262
+ trace: "debug",
263
+ debug: "debug",
264
+ info: "info",
265
+ warn: "warn",
266
+ error: "error",
267
+ fatal: "error"
268
+ };
269
+ /**
270
+ * Create a browser transport optimized for DevTools output.
271
+ *
272
+ * @param options - Optional level style overrides.
273
+ * @param _console - Injected console-like object (defaults to global `console`). Used in tests.
274
+ * @returns A `Transport` that writes styled records to the browser console.
275
+ */
276
+ function createBrowserTransport(options, _console = console) {
277
+ const levelStyles = {
278
+ ...DEFAULT_STYLES,
279
+ ...options?.levelStyles
280
+ };
281
+ return { log(record) {
282
+ const methodName = LEVEL_METHOD$1[record.level];
283
+ const method = getConsoleMethod(_console, methodName);
284
+ const style = levelStyles[record.level];
285
+ const badge = record.level.toUpperCase();
286
+ if (Object.keys(record.context).length > 0) method(`%c${badge}`, style, record.message, record.context);
287
+ else method(`%c${badge}`, style, record.message);
288
+ } };
289
+ }
290
+ //#endregion
291
+ //#region src/lib/logging/transports/capture.ts
292
+ /**
293
+ * Create a capture transport that stores records in memory.
294
+ *
295
+ * @returns A `CaptureTransport` with `.records`, `.clear()`, and `.find()`.
296
+ */
297
+ function createCaptureTransport() {
298
+ let internal = [];
299
+ return {
300
+ log(record) {
301
+ internal.push(record);
302
+ },
303
+ get records() {
304
+ return internal.slice();
305
+ },
306
+ clear() {
307
+ internal = [];
308
+ },
309
+ find(level) {
310
+ return internal.filter((r) => r.level === level);
311
+ }
312
+ };
313
+ }
314
+ //#endregion
315
+ //#region src/lib/logging/internal/safe-json.ts
316
+ /**
317
+ * @file Internal safe JSON/string formatting for the logging subpath. Not exported from
318
+ * `src/lib/logging/index.ts`; used by `createConsoleTransport` and `createStructuredTransport`.
319
+ *
320
+ * `safeStringify()` serializes arbitrary values to a compact JSON string while handling the
321
+ * common non-JSON types that appear in structured log context:
322
+ * - Circular references → `"[Circular]"` (a shared/diamond reference reachable via two
323
+ * non-nested paths — e.g. `{ a: shared, b: shared }` — is NOT a circular reference and is
324
+ * serialized in full at both locations; only true ancestor cycles are replaced)
325
+ * - `bigint` → `"<n>n"` (e.g. `42n` → `"42n"`)
326
+ * - `symbol` → `"Symbol(description)"`
327
+ * - `function` → `"[Function name]"` or `"[Function (anonymous)]"`
328
+ * - `undefined` → omitted from objects, `"undefined"` at top level
329
+ */
330
+ /**
331
+ * A stable placeholder emitted when `JSON.stringify` itself throws unexpectedly (e.g. a getter
332
+ * that throws mid-serialization after the circular-reference check has passed).
333
+ */
334
+ const FALLBACK = "[FormattingError]";
335
+ /**
336
+ * Convert a single value to a JSON-safe replacement.
337
+ *
338
+ * Called from the `JSON.stringify` replacer for every value encountered during serialization.
339
+ * Non-JSON-safe primitives (`bigint`, `symbol`, `function`) are converted to descriptive
340
+ * strings. All other values are returned unchanged so that `JSON.stringify` handles them
341
+ * normally.
342
+ *
343
+ * Exported for direct unit testing so the default return path is reachable without going
344
+ * through the full replacer loop.
345
+ *
346
+ * @param value - The raw value at the current key.
347
+ * @returns A JSON-safe replacement value.
348
+ */
349
+ function replaceNonJsonValue(value) {
350
+ if (typeof value === "bigint") return `${value.toString()}n`;
351
+ if (typeof value === "symbol") return value.toString();
352
+ if (typeof value === "function") {
353
+ const name = value.name;
354
+ return name ? `[Function ${name}]` : "[Function (anonymous)]";
355
+ }
356
+ return value;
357
+ }
358
+ /**
359
+ * Serialize `value` to a compact JSON string.
360
+ *
361
+ * Handles:
362
+ * - Circular references (replaced with `"[Circular]"`); shared/diamond references (the same
363
+ * object reachable via two different, non-nested paths) are NOT treated as circular and are
364
+ * serialized in full at every location
365
+ * - `bigint` (serialized as `"<n>n"`)
366
+ * - `symbol` (serialized as `"Symbol(description)"`)
367
+ * - `function` (serialized as `"[Function name]"`)
368
+ * - `undefined` at the top level (returns `"undefined"`)
369
+ * - Unexpected formatter errors (returns `"[FormattingError]"`)
370
+ *
371
+ * @param value - The value to serialize.
372
+ * @returns A JSON string representation.
373
+ */
374
+ function safeStringify(value) {
375
+ if (value === void 0) return "undefined";
376
+ const stack = [];
377
+ try {
378
+ return JSON.stringify(value, function replacer(_key, val) {
379
+ if (typeof val === "bigint" || typeof val === "symbol" || typeof val === "function") return replaceNonJsonValue(val);
380
+ if (val !== null && typeof val === "object") {
381
+ const holderIndex = stack.indexOf(this);
382
+ if (holderIndex === -1) stack.push(this);
383
+ else stack.length = holderIndex + 1;
384
+ if (stack.includes(val)) return "[Circular]";
385
+ stack.push(val);
386
+ }
387
+ return val;
388
+ });
389
+ } catch {
390
+ return FALLBACK;
391
+ }
392
+ }
393
+ //#endregion
394
+ //#region src/lib/logging/internal/sanitize.ts
395
+ /**
396
+ * @file An internal helper for the logging subpath — not exported from
397
+ * `src/lib/logging/index.ts`.
398
+ *
399
+ * `sanitizeTerminalText()` neutralizes terminal-injection risk (SEC-007) in strings that are
400
+ * about to be written to a real terminal by `createConsoleTransport()`. `record.message` is
401
+ * caller-supplied and may embed attacker-controlled data (e.g. an email address or path). Left
402
+ * unescaped, it could contain newlines that forge fake log lines, or ANSI escape sequences
403
+ * (`\x1b...`) that manipulate the terminal (colors, cursor movement, title changes) when the
404
+ * output is later viewed through a real terminal such as `wrangler tail`.
405
+ *
406
+ * `record.context` does not need the same treatment: `createConsoleTransport()` always renders
407
+ * it via `safeStringify()` (`JSON.stringify` under the hood), which already escapes every C0
408
+ * control character — including `\x1b` — as `\uXXXX` per the JSON spec.
409
+ */
410
+ /**
411
+ * Control characters (C0: `\x00`-`\x1f`, plus DEL `\x7f`) that could forge terminal output or
412
+ * trigger ANSI escape sequences. Every terminal escape sequence begins with `\x1b` (ESC), so
413
+ * escaping it alone is sufficient to neutralize ANSI injection; the rest of the range is
414
+ * escaped defensively for the same reason.
415
+ */
416
+ const CONTROL_CHAR_PATTERN = /[\x00-\x1f\x7f]/g;
417
+ /** Readable escape sequences for the most common control characters. */
418
+ const NAMED_ESCAPES = {
419
+ "\n": "\\n",
420
+ "\r": "\\r",
421
+ " ": "\\t"
422
+ };
423
+ /**
424
+ * Replace every C0 control character and DEL in `value` with a visible, non-executable escape
425
+ * sequence.
426
+ *
427
+ * Common whitespace controls (`\n`, `\r`, `\t`) are rendered as their familiar backslash
428
+ * escapes; every other control character (including ESC, `\x1b`) is rendered as a two-digit hex
429
+ * escape (`\xHH`). This preserves the original information for debugging while preventing the
430
+ * string from forging additional log lines or executing terminal escape sequences.
431
+ *
432
+ * @param value - The raw string to sanitize before writing it to a terminal.
433
+ * @returns `value` with every control character replaced by a visible escape sequence.
434
+ */
435
+ function sanitizeTerminalText(value) {
436
+ return value.replace(CONTROL_CHAR_PATTERN, (char) => {
437
+ const named = NAMED_ESCAPES[char];
438
+ if (named !== void 0) return named;
439
+ return `\\x${char.charCodeAt(0).toString(16).padStart(2, "0")}`;
440
+ });
441
+ }
442
+ //#endregion
443
+ //#region src/lib/logging/transports/console.ts
444
+ /**
445
+ * @file A transport that formats records as human-readable single-line output intended for
446
+ * terminal environments including `wrangler dev`.
447
+ *
448
+ * `createConsoleTransport()` supports optional ANSI color codes and configurable timestamp
449
+ * formats.
450
+ *
451
+ * `record.message` is sanitized via `sanitizeTerminalText()` (SEC-007) before it is written,
452
+ * escaping control/ANSI characters so caller-supplied data cannot forge additional log lines or
453
+ * inject terminal escape sequences when the output is later viewed in a real terminal (e.g.
454
+ * `wrangler tail`).
455
+ *
456
+ * Level-to-method mapping:
457
+ * trace, debug, info → console.log
458
+ * warn, error, fatal → console.error
459
+ *
460
+ * Output format:
461
+ * [timestamp] LEVEL message [{"key":"value"}]
462
+ */
463
+ const RESET = "\x1B[0m";
464
+ /** Map each level to its ANSI color code. */
465
+ const LEVEL_COLOR = {
466
+ trace: "\x1B[90m",
467
+ debug: "\x1B[37m",
468
+ info: "\x1B[36m",
469
+ warn: "\x1B[33m",
470
+ error: "\x1B[31m",
471
+ fatal: "\x1B[35m"
472
+ };
473
+ /**
474
+ * Extract an `HH:MM:SS` time string from an ISO 8601 timestamp. Falls back to the first 8
475
+ * characters if the expected `T` separator is absent.
476
+ *
477
+ * Exported for direct unit testing of the fallback branch.
478
+ *
479
+ * @param isoString - An ISO 8601 timestamp string.
480
+ * @returns The `HH:MM:SS` portion, or the first 8 characters if no `T` separator is found.
481
+ */
482
+ function extractTime(isoString) {
483
+ const tIndex = isoString.indexOf("T");
484
+ if (tIndex === -1) return isoString.slice(0, 8);
485
+ return isoString.slice(tIndex + 1, tIndex + 9);
486
+ }
487
+ /** Fixed-width (5 chars) uppercase level labels. */
488
+ const LEVEL_LABEL = {
489
+ trace: "TRACE",
490
+ debug: "DEBUG",
491
+ info: "INFO ",
492
+ warn: "WARN ",
493
+ error: "ERROR",
494
+ fatal: "FATAL"
495
+ };
496
+ /**
497
+ * Create a console transport for terminal/wrangler dev output.
498
+ *
499
+ * @param options - Timestamp and color options.
500
+ * @param _console - Injected console-like object (defaults to global `console`). Used in tests.
501
+ * @returns A `Transport` that writes formatted lines to the terminal.
502
+ */
503
+ function createConsoleTransport(options, _console = console) {
504
+ const colors = valueOrDefault(options?.colors, true);
505
+ const timestamp = valueOrDefault(options?.timestamp, "time");
506
+ return { log(record) {
507
+ const method = getConsoleMethod(_console, record.level === "warn" || record.level === "error" || record.level === "fatal" ? "error" : "log");
508
+ const parts = [];
509
+ if (timestamp === "time") {
510
+ const ts = extractTime(record.time);
511
+ parts.push(colors ? `\x1b[90m${ts}${RESET}` : ts);
512
+ } else if (timestamp === "iso") parts.push(colors ? `\x1b[90m${record.time}${RESET}` : record.time);
513
+ const label = LEVEL_LABEL[record.level];
514
+ if (colors) {
515
+ const color = LEVEL_COLOR[record.level];
516
+ parts.push(`${color}${label}${RESET}`);
517
+ } else parts.push(label);
518
+ parts.push(sanitizeTerminalText(record.message));
519
+ if (Object.keys(record.context).length > 0) parts.push(safeStringify(record.context));
520
+ method(parts.join(" "));
521
+ } };
522
+ }
523
+ //#endregion
524
+ //#region src/lib/logging/transports/structured.ts
525
+ /**
526
+ * @file A transport that emits records as structured payloads intended for Cloudflare Workers
527
+ * Logs.
528
+ *
529
+ * Workers Logs automatically extracts and indexes fields from JSON object logs, so
530
+ * `createStructuredTransport()` defaults to object logging (`stringify: false`) rather than
531
+ * string logging.
532
+ *
533
+ * Payload shape: `{ time, level, message, ...context }`
534
+ * Reserved keys (`time`, `level`, `message`) from the record take precedence over identically
535
+ * named context keys.
536
+ *
537
+ * Level-to-method mapping:
538
+ * trace, debug → console.debug
539
+ * info → console.log
540
+ * warn → console.warn
541
+ * error, fatal → console.error
542
+ */
543
+ /** Map each log level to the preferred console method name. */
544
+ const LEVEL_METHOD = {
545
+ trace: "debug",
546
+ debug: "debug",
547
+ info: "log",
548
+ warn: "warn",
549
+ error: "error",
550
+ fatal: "error"
551
+ };
552
+ /**
553
+ * Create a structured transport for Cloudflare Workers Logs.
554
+ *
555
+ * @param options - Optional stringify flag.
556
+ * @param _console - Injected console-like object (defaults to global `console`). Used in tests.
557
+ * @returns A `Transport` that writes structured payloads to the console.
558
+ */
559
+ function createStructuredTransport(options, _console = console) {
560
+ const stringify = valueOrDefault(options?.stringify, false);
561
+ return { log(record) {
562
+ const methodName = LEVEL_METHOD[record.level];
563
+ const method = getConsoleMethod(_console, methodName);
564
+ const payload = {
565
+ ...record.context,
566
+ time: record.time,
567
+ level: record.level,
568
+ message: record.message
569
+ };
570
+ if (stringify) method(safeStringify(payload));
571
+ else method(payload);
572
+ } };
573
+ }
574
+ //#endregion
575
+ //#region src/lib/logging/resolve.ts
576
+ /**
577
+ * @file A default-config helper that maps an environment + runtime pair to a ready-to-use
578
+ * `{ level, transport }` pair.
579
+ *
580
+ * `resolveLoggerConfig()` is optional policy — `createLogger` does not require it. Applications
581
+ * that need environment-specific configuration without hand-wiring transports can call this
582
+ * helper and pass the result directly to `createLogger`.
583
+ *
584
+ * Policy table:
585
+ *
586
+ * | Environment | Runtime | Level | Transport |
587
+ * |---------------|-----------|---------|------------|
588
+ * | test | browser | trace | capture |
589
+ * | test | worker | trace | capture |
590
+ * | development | browser | info | browser |
591
+ * | development | worker | debug | console |
592
+ * | production | browser | warn | browser |
593
+ * | production | worker | warn | structured |
594
+ * | unknown | browser | warn | browser |
595
+ * | unknown | worker | warn | structured |
596
+ *
597
+ * There is no `detectRuntime()` helper in the public API. Applications are expected to know
598
+ * whether they are constructing a browser logger or a Worker logger.
599
+ */
600
+ /**
601
+ * Resolve a `{ level, transport }` configuration for the given environment and runtime.
602
+ *
603
+ * Each call creates a **fresh** transport instance. If you call this helper more than once with
604
+ * the same arguments you will receive independent transport instances, which is intentional for
605
+ * test isolation.
606
+ *
607
+ * Unknown or `undefined` environments are treated as `"production"`.
608
+ *
609
+ * @param environment - One of `"test"`, `"development"`, `"production"`, or any other string.
610
+ * `undefined` maps to production behavior.
611
+ * @param runtime - Either `"browser"` or `"worker"`.
612
+ * @returns A fresh `ResolvedLoggerConfig` ready to pass to `createLogger`.
613
+ */
614
+ function resolveLoggerConfig(environment, runtime) {
615
+ const env = environment === "test" || environment === "development" ? environment : "production";
616
+ if (env === "test") return {
617
+ level: "trace",
618
+ transport: createCaptureTransport()
619
+ };
620
+ if (env === "development") {
621
+ if (runtime === "browser") return {
622
+ level: "info",
623
+ transport: createBrowserTransport()
624
+ };
625
+ return {
626
+ level: "debug",
627
+ transport: createConsoleTransport()
628
+ };
629
+ }
630
+ if (runtime === "browser") return {
631
+ level: "warn",
632
+ transport: createBrowserTransport()
633
+ };
634
+ return {
635
+ level: "warn",
636
+ transport: createStructuredTransport()
637
+ };
638
+ }
639
+ //#endregion
640
+ //#region src/lib/logging/transports/silent.ts
641
+ /**
642
+ * Create a silent transport that discards all records.
643
+ *
644
+ * @returns A `Transport` that does nothing.
645
+ */
646
+ function createSilentTransport() {
647
+ return { log() {} };
648
+ }
649
+ //#endregion
650
+ export { createCaptureTransport as a, serializeError as c, createConsoleTransport as i, resolveLoggerConfig as n, createBrowserTransport as o, createStructuredTransport as r, createLogger as s, createSilentTransport as t };
651
+
652
+ //# sourceMappingURL=silent-CWpHE65X.js.map