@adatechnology/logger 0.0.2

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/dist/index.js ADDED
@@ -0,0 +1,567 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var __decorateClass = (decorators, target, key, kind) => {
19
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
20
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
21
+ if (decorator = decorators[i])
22
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
23
+ if (kind && result) __defProp(target, key, result);
24
+ return result;
25
+ };
26
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
27
+
28
+ // src/index.ts
29
+ var index_exports = {};
30
+ __export(index_exports, {
31
+ DEFAULT_LOGGER_CONFIG: () => DEFAULT_LOGGER_CONFIG,
32
+ LOGGER_PROVIDER: () => LOGGER_PROVIDER,
33
+ LoggerModule: () => LoggerModule,
34
+ RequestContextMiddleware: () => RequestContextMiddleware,
35
+ getContext: () => getContext,
36
+ runWithContext: () => runWithContext
37
+ });
38
+ module.exports = __toCommonJS(index_exports);
39
+
40
+ // src/logger.module.ts
41
+ var import_common4 = require("@nestjs/common");
42
+
43
+ // src/logger.provider.ts
44
+ var import_common = require("@nestjs/common");
45
+
46
+ // src/implementations/winston/winston.logger.token.ts
47
+ var WINSTON_LOGGER = "WINSTON_LOGGER";
48
+ var WINSTON_RAW = "WINSTON_RAW";
49
+ var WINSTON_OBFUSCATOR = "WINSTON_OBFUSCATOR";
50
+
51
+ // src/logger.provider.ts
52
+ var LoggerProvider = class {
53
+ constructor(implementation) {
54
+ this.implementation = implementation;
55
+ }
56
+ debug(...args) {
57
+ return this.implementation.debug(...args);
58
+ }
59
+ info(...args) {
60
+ return this.implementation.info(...args);
61
+ }
62
+ warn(...args) {
63
+ return this.implementation.warn(...args);
64
+ }
65
+ error(...args) {
66
+ return this.implementation.error(...args);
67
+ }
68
+ setContext(context) {
69
+ if (typeof this.implementation.setContext === "function") {
70
+ return this.implementation.setContext(context);
71
+ }
72
+ return;
73
+ }
74
+ };
75
+ LoggerProvider = __decorateClass([
76
+ (0, import_common.Injectable)(),
77
+ __decorateParam(0, (0, import_common.Inject)(WINSTON_LOGGER))
78
+ ], LoggerProvider);
79
+
80
+ // src/logger.token.ts
81
+ var LOGGER_PROVIDER = "LOGGER_PROVIDER";
82
+
83
+ // src/implementations/winston/winston.logger.module.ts
84
+ var import_common3 = require("@nestjs/common");
85
+ var import_winston = require("winston");
86
+ var import_util = require("util");
87
+
88
+ // src/implementations/winston/winston.logger.provider.ts
89
+ var import_common2 = require("@nestjs/common");
90
+
91
+ // src/context/async-context.service.ts
92
+ var import_async_hooks = require("async_hooks");
93
+ var asyncLocalStorage = new import_async_hooks.AsyncLocalStorage();
94
+ function getContext() {
95
+ return asyncLocalStorage.getStore();
96
+ }
97
+ function runWithContext(ctx, fn) {
98
+ return asyncLocalStorage.run(ctx, fn);
99
+ }
100
+
101
+ // src/logger.constant.ts
102
+ var DEFAULT_SENSITIVE_KEYS = [
103
+ "password",
104
+ "pass",
105
+ "pwd",
106
+ "token",
107
+ "accessToken",
108
+ "refreshToken",
109
+ "authorization",
110
+ "auth",
111
+ "secret",
112
+ "ssn",
113
+ "creditCard"
114
+ ];
115
+ var EMPTY_STRING = "";
116
+ var MASK = {
117
+ REPLACEMENT: "****",
118
+ MIN_LENGTH: 4,
119
+ EDGE_CHARS: 2
120
+ };
121
+ var MASK_REPLACEMENT = MASK.REPLACEMENT;
122
+ var MASK_MIN_LENGTH = MASK.MIN_LENGTH;
123
+ var MASK_EDGE_CHARS = MASK.EDGE_CHARS;
124
+ var ID_FALLBACK_SEPARATOR = "-";
125
+
126
+ // src/implementations/winston/winston.logger.provider.ts
127
+ var WinstonLoggerProvider = class {
128
+ constructor(logger, obfuscator) {
129
+ this.logger = logger;
130
+ this.obfuscator = obfuscator;
131
+ }
132
+ context;
133
+ debug(messageOrPayload, meta, context) {
134
+ this.handleLog("debug" /* DEBUG */, messageOrPayload, meta, context);
135
+ }
136
+ info(messageOrPayload, meta, context) {
137
+ this.handleLog("info" /* INFO */, messageOrPayload, meta, context);
138
+ }
139
+ warn(messageOrPayload, meta, context) {
140
+ this.handleLog("warn" /* WARN */, messageOrPayload, meta, context);
141
+ }
142
+ error(messageOrPayload, meta, context) {
143
+ this.handleLog("error" /* ERROR */, messageOrPayload, meta, context);
144
+ }
145
+ setContext(context) {
146
+ this.context = context;
147
+ }
148
+ handleLog(level, messageOrPayload, meta, context) {
149
+ let payload;
150
+ if (typeof messageOrPayload === "string") {
151
+ payload = {
152
+ message: messageOrPayload,
153
+ meta,
154
+ context: context || this.context
155
+ };
156
+ } else {
157
+ payload = {
158
+ ...messageOrPayload,
159
+ context: messageOrPayload.context || context || this.context,
160
+ meta: { ...messageOrPayload.meta, ...meta }
161
+ };
162
+ }
163
+ this.log({ level, payload });
164
+ }
165
+ log(params) {
166
+ const { level, payload } = params;
167
+ const { message, context, meta, ...rest } = payload;
168
+ const messageText = message ?? EMPTY_STRING;
169
+ const messageContext = context ?? this.context;
170
+ const obfuscatedMeta = this.obfuscator ? this.obfuscator(meta) : meta;
171
+ const requestContext = getContext();
172
+ const requestIdFromContext = requestContext?.requestId;
173
+ const logInfo = {
174
+ ...rest,
175
+ context: messageContext,
176
+ requestId: requestIdFromContext || payload.requestId,
177
+ meta: obfuscatedMeta
178
+ };
179
+ this.logger.log(level, messageText, logInfo);
180
+ }
181
+ };
182
+ WinstonLoggerProvider = __decorateClass([
183
+ (0, import_common2.Injectable)(),
184
+ __decorateParam(0, (0, import_common2.Inject)(WINSTON_RAW)),
185
+ __decorateParam(1, (0, import_common2.Inject)(WINSTON_OBFUSCATOR))
186
+ ], WinstonLoggerProvider);
187
+
188
+ // src/implementations/winston/winston.logger.constants.ts
189
+ var DEFAULT_LOG_LEVEL = "info";
190
+
191
+ // src/obfuscator.ts
192
+ function isObject(value) {
193
+ return value !== null && typeof value === "object" && !Array.isArray(value);
194
+ }
195
+ function maskString(str) {
196
+ if (str.length <= MASK.MIN_LENGTH) return MASK.REPLACEMENT;
197
+ return str.slice(0, MASK.EDGE_CHARS) + MASK.REPLACEMENT + str.slice(-MASK.EDGE_CHARS);
198
+ }
199
+ function normalizeEntries(entries) {
200
+ const keys = [];
201
+ const custom = /* @__PURE__ */ new Map();
202
+ if (!entries || entries.length === 0) return { keys, custom };
203
+ for (const entry of entries) {
204
+ if (typeof entry === "string") {
205
+ keys.push(entry);
206
+ } else if (entry && typeof entry === "object" && "key" in entry && typeof entry.key === "string" && typeof entry.obfuscator === "function") {
207
+ custom.set(entry.key.toLowerCase(), entry.obfuscator);
208
+ }
209
+ }
210
+ return { keys, custom };
211
+ }
212
+ function defaultObfuscator(params) {
213
+ const { obj, entries } = params;
214
+ if (obj == null) return obj;
215
+ if (Array.isArray(obj)) {
216
+ return obj.map((item) => defaultObfuscator({ obj: item, entries }));
217
+ }
218
+ if (!isObject(obj)) return obj;
219
+ const { keys: extraKeys, custom } = normalizeEntries(entries);
220
+ const keys = DEFAULT_SENSITIVE_KEYS.concat(extraKeys || []);
221
+ function splitIntoWords(k) {
222
+ const withSpaces = k.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[_\-.]+/g, " ");
223
+ return withSpaces.split(/\s+/).filter(Boolean);
224
+ }
225
+ const out = {};
226
+ for (const key of Object.keys(obj)) {
227
+ const value = obj[key];
228
+ const lowerKey = key.toLowerCase();
229
+ if (custom.has(lowerKey)) {
230
+ try {
231
+ out[key] = custom.get(lowerKey)(value);
232
+ } catch (error) {
233
+ out[key] = MASK.REPLACEMENT;
234
+ }
235
+ } else if (
236
+ // match when key exactly equals a sensitive token OR
237
+ // when any token equals one of the camelCase/sep-separated words
238
+ keys.some((s) => {
239
+ const sens = s.toLowerCase();
240
+ if (lowerKey === sens) return true;
241
+ const words = splitIntoWords(lowerKey);
242
+ return words.some((w) => w === sens);
243
+ })
244
+ ) {
245
+ if (typeof value === "string") out[key] = maskString(value);
246
+ else out[key] = MASK.REPLACEMENT;
247
+ } else if (isObject(value) || Array.isArray(value)) {
248
+ out[key] = defaultObfuscator({ obj: value, entries });
249
+ } else {
250
+ out[key] = value;
251
+ }
252
+ }
253
+ return out;
254
+ }
255
+ function buildDefaultObfuscator(additional) {
256
+ return (v) => defaultObfuscator({ obj: v, entries: additional });
257
+ }
258
+
259
+ // src/implementations/winston/winston.logger.module.ts
260
+ var WinstonImplementationModule = class {
261
+ static forRoot(config) {
262
+ const providers = this.createProviders(config);
263
+ return {
264
+ module: WinstonImplementationModule,
265
+ providers,
266
+ exports: [WINSTON_LOGGER]
267
+ };
268
+ }
269
+ static forRootAsync(options) {
270
+ return {
271
+ module: WinstonImplementationModule,
272
+ imports: options.imports || [],
273
+ providers: [
274
+ {
275
+ provide: "LOGGER_CONFIG",
276
+ useFactory: options.useFactory,
277
+ inject: options.inject || []
278
+ },
279
+ {
280
+ provide: WINSTON_RAW,
281
+ useFactory: (config) => {
282
+ return this.createWinstonLogger(config);
283
+ },
284
+ inject: ["LOGGER_CONFIG"]
285
+ },
286
+ {
287
+ provide: WINSTON_OBFUSCATOR,
288
+ useFactory: (config) => {
289
+ return config?.obfuscator ?? buildDefaultObfuscator(config?.obfuscatorKeys);
290
+ },
291
+ inject: ["LOGGER_CONFIG"]
292
+ },
293
+ {
294
+ provide: WINSTON_LOGGER,
295
+ useClass: WinstonLoggerProvider
296
+ }
297
+ ],
298
+ exports: [WINSTON_LOGGER]
299
+ };
300
+ }
301
+ static createProviders(config) {
302
+ const winstonLogger = this.createWinstonLogger(config);
303
+ const obfuscator = config?.obfuscator ?? buildDefaultObfuscator(config?.obfuscatorKeys);
304
+ return [
305
+ {
306
+ provide: WINSTON_RAW,
307
+ useValue: winstonLogger
308
+ },
309
+ {
310
+ provide: WINSTON_OBFUSCATOR,
311
+ useValue: obfuscator
312
+ },
313
+ {
314
+ provide: WINSTON_LOGGER,
315
+ useClass: WinstonLoggerProvider
316
+ }
317
+ ];
318
+ }
319
+ static createWinstonLogger(config) {
320
+ const isProduction = config?.isProduction ?? process.env.NODE_ENV === "production";
321
+ const useColors = config?.colorize !== false;
322
+ const standardFields = (0, import_winston.format)((info) => {
323
+ const meta = info.meta;
324
+ if (meta) {
325
+ if (meta.requestId && !info.requestId) {
326
+ info.requestId = meta.requestId;
327
+ delete meta.requestId;
328
+ }
329
+ if (meta.context && !info.context) {
330
+ info.context = meta.context;
331
+ delete meta.context;
332
+ }
333
+ if (meta.source && !info.source) {
334
+ info.source = meta.source;
335
+ delete meta.source;
336
+ }
337
+ if (meta.lib && !info.lib) {
338
+ info.lib = meta.lib;
339
+ delete meta.lib;
340
+ }
341
+ if (meta.libVersion && !info.libVersion) {
342
+ info.libVersion = meta.libVersion;
343
+ delete meta.libVersion;
344
+ }
345
+ if (meta.libMethod && !info.libMethod) {
346
+ info.libMethod = meta.libMethod;
347
+ delete meta.libMethod;
348
+ }
349
+ if (meta.appName && !info.appName) {
350
+ info.appName = meta.appName;
351
+ delete meta.appName;
352
+ }
353
+ if (meta.appVersion && !info.appVersion) {
354
+ info.appVersion = meta.appVersion;
355
+ delete meta.appVersion;
356
+ }
357
+ if (meta.logContext && !info.source) {
358
+ const lc = meta.logContext;
359
+ if (lc.className && lc.methodName) {
360
+ info.source = `${lc.className}.${lc.methodName}`;
361
+ } else if (lc.className) {
362
+ info.source = lc.className;
363
+ } else if (lc.methodName) {
364
+ info.source = lc.methodName;
365
+ }
366
+ }
367
+ }
368
+ info.requestId = info.requestId || "no-request-id";
369
+ info.context = info.context || config?.context || "App";
370
+ info.appName = info.appName || config?.appName;
371
+ info.appVersion = info.appVersion || config?.appVersion;
372
+ info.lib = info.lib || config?.lib;
373
+ info.libVersion = info.libVersion || config?.libVersion;
374
+ return info;
375
+ });
376
+ const levelColorizer = import_winston.format.colorize();
377
+ const developmentFormat = import_winston.format.printf(
378
+ (info) => {
379
+ const {
380
+ level,
381
+ message,
382
+ timestamp,
383
+ requestId,
384
+ context,
385
+ source,
386
+ meta,
387
+ stack,
388
+ appName,
389
+ appVersion,
390
+ lib,
391
+ libMethod,
392
+ libVersion
393
+ } = info;
394
+ const colors = {
395
+ reset: "\x1B[0m",
396
+ gray: "\x1B[90m",
397
+ cyan: "\x1B[36m",
398
+ magenta: "\x1B[35m",
399
+ yellow: "\x1B[33m",
400
+ red: "\x1B[31m",
401
+ green: "\x1B[32m",
402
+ bold: "\x1B[1m"
403
+ };
404
+ const colorize = (color, text) => useColors ? `${color}${text}${colors.reset}` : text;
405
+ const coloredLevel = useColors ? levelColorizer.colorize(level, level.toUpperCase()) : level.toUpperCase();
406
+ const coloredTime = colorize(colors.gray, timestamp);
407
+ const coloredRequestId = colorize(colors.cyan, requestId);
408
+ let appDisplay = "";
409
+ if (appName) {
410
+ const appText = appVersion ? `${appName}@${appVersion}` : appName;
411
+ appDisplay = `[${colorize(colors.green, `App-${appText}`)}]`;
412
+ }
413
+ let libDisplay = "";
414
+ if (lib) {
415
+ const libText = libVersion ? `${lib}:${libVersion}` : lib;
416
+ libDisplay = `[${colorize(colors.yellow, libText)}]`;
417
+ }
418
+ const mag = colors.magenta;
419
+ let sourceDisplay = "";
420
+ let libMethodDisplay = "";
421
+ if (source) {
422
+ sourceDisplay = `[${colorize(mag, source)}]`;
423
+ }
424
+ if (lib) {
425
+ const methodPath = libMethod ? `${context}.${libMethod}` : context;
426
+ libMethodDisplay = `[${colorize(mag, methodPath)}]`;
427
+ if (source === context || source === methodPath) {
428
+ sourceDisplay = "";
429
+ }
430
+ } else if (!source) {
431
+ libMethodDisplay = `[${colorize(mag, context)}]`;
432
+ } else if (source.startsWith(`${context}.`) || source === context) {
433
+ libMethodDisplay = `[${colorize(mag, source)}]`;
434
+ sourceDisplay = "";
435
+ } else {
436
+ libMethodDisplay = `[${colorize(mag, context)}]`;
437
+ sourceDisplay = `[${colorize(mag, source)}]`;
438
+ }
439
+ let output = `${appDisplay}${libDisplay}[${coloredRequestId}][${coloredTime}]${sourceDisplay}${libMethodDisplay}[${coloredLevel}] - ${message}`;
440
+ if (meta && typeof meta === "object" && Object.keys(meta).length > 0) {
441
+ const inspectedMeta = (0, import_util.inspect)(meta, {
442
+ colors: useColors,
443
+ depth: null,
444
+ compact: true,
445
+ sorted: true,
446
+ breakLength: Infinity
447
+ });
448
+ output += ` - ${inspectedMeta}`;
449
+ }
450
+ if (stack) {
451
+ output += `
452
+ ${colorize(colors.red, stack)}`;
453
+ }
454
+ return output;
455
+ }
456
+ );
457
+ const formats = [
458
+ import_winston.format.timestamp(),
459
+ import_winston.format.errors({ stack: true }),
460
+ import_winston.format.splat(),
461
+ standardFields()
462
+ ];
463
+ if (isProduction) {
464
+ formats.push(import_winston.format.json());
465
+ } else {
466
+ formats.push(developmentFormat);
467
+ }
468
+ const defaultFormat = import_winston.format.combine(...formats);
469
+ const consoleTransport = new import_winston.transports.Console({
470
+ format: defaultFormat
471
+ });
472
+ const defaultOptions = {
473
+ level: config?.level || process.env.LOG_LEVEL || DEFAULT_LOG_LEVEL,
474
+ format: defaultFormat,
475
+ transports: [consoleTransport]
476
+ };
477
+ const mergedOptions = Object.assign(
478
+ {},
479
+ defaultOptions,
480
+ config?.loggerOptions || {}
481
+ );
482
+ return (0, import_winston.createLogger)(mergedOptions);
483
+ }
484
+ };
485
+ WinstonImplementationModule = __decorateClass([
486
+ (0, import_common3.Module)({})
487
+ ], WinstonImplementationModule);
488
+
489
+ // src/logger.module.ts
490
+ var LoggerModule = class {
491
+ static forRoot(config) {
492
+ const implModule = WinstonImplementationModule.forRoot(config);
493
+ const provider = {
494
+ provide: LOGGER_PROVIDER,
495
+ useClass: LoggerProvider
496
+ };
497
+ if (config && config.requestScoped) {
498
+ provider.scope = import_common4.Scope.REQUEST;
499
+ }
500
+ return {
501
+ module: LoggerModule,
502
+ imports: [implModule],
503
+ providers: [provider],
504
+ exports: [LOGGER_PROVIDER]
505
+ };
506
+ }
507
+ static forRootAsync(options) {
508
+ return {
509
+ module: LoggerModule,
510
+ imports: [
511
+ ...options.imports || [],
512
+ WinstonImplementationModule.forRootAsync(options)
513
+ ],
514
+ providers: [
515
+ {
516
+ provide: LOGGER_PROVIDER,
517
+ useClass: LoggerProvider
518
+ }
519
+ ],
520
+ exports: [LOGGER_PROVIDER]
521
+ };
522
+ }
523
+ };
524
+ LoggerModule = __decorateClass([
525
+ (0, import_common4.Global)(),
526
+ (0, import_common4.Module)({})
527
+ ], LoggerModule);
528
+
529
+ // src/middleware/request-context.middleware.ts
530
+ var import_common5 = require("@nestjs/common");
531
+ var import_crypto = require("crypto");
532
+
533
+ // src/request-id.constants.ts
534
+ var DEFAULT_HTTP_REQUEST_ID_HEADER = "x-request-id";
535
+ var DEFAULT_HTTP_REQUEST_ID_FALLBACKS = ["x-correlation-id"];
536
+ var HEADERS_PARAMS = {
537
+ REQUEST_ID: DEFAULT_HTTP_REQUEST_ID_HEADER,
538
+ FALLBACKS: DEFAULT_HTTP_REQUEST_ID_FALLBACKS
539
+ };
540
+
541
+ // src/middleware/request-context.middleware.ts
542
+ var RequestContextMiddleware = class {
543
+ use(req, _res, next) {
544
+ const existing = req.headers?.[HEADERS_PARAMS.REQUEST_ID] || req.headers?.[HEADERS_PARAMS.FALLBACKS[0]];
545
+ const id = existing || (typeof import_crypto.randomUUID === "function" ? (0, import_crypto.randomUUID)() : `${Date.now()}${ID_FALLBACK_SEPARATOR}${Math.random()}`);
546
+ asyncLocalStorage.run({ requestId: id }, () => next());
547
+ }
548
+ };
549
+ RequestContextMiddleware = __decorateClass([
550
+ (0, import_common5.Injectable)()
551
+ ], RequestContextMiddleware);
552
+
553
+ // src/logger.config.ts
554
+ var DEFAULT_LOGGER_CONFIG = {
555
+ requestScoped: false,
556
+ level: "info",
557
+ colorize: true
558
+ };
559
+ // Annotate the CommonJS export names for ESM import in node:
560
+ 0 && (module.exports = {
561
+ DEFAULT_LOGGER_CONFIG,
562
+ LOGGER_PROVIDER,
563
+ LoggerModule,
564
+ RequestContextMiddleware,
565
+ getContext,
566
+ runWithContext
567
+ });
package/package.json ADDED
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "@adatechnology/logger",
3
+ "version": "0.0.2",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "type": "commonjs",
8
+ "main": "dist/index.js",
9
+ "types": "dist/index.d.ts",
10
+ "peerDependencies": {
11
+ "@nestjs/common": "^11.0.16",
12
+ "@nestjs/core": "^11"
13
+ },
14
+ "devDependencies": {
15
+ "@esbuild-plugins/tsconfig-paths": "^0.1.2",
16
+ "tsup": "^8.5.1"
17
+ },
18
+ "dependencies": {
19
+ "winston": "^3.9.0"
20
+ },
21
+ "scripts": {
22
+ "prebuild": "rm -rf dist",
23
+ "build": "tsup src/index.ts --dts --tsconfig tsconfig.tsup.json",
24
+ "build:watch": "tsup src/index.ts --watch --dts --tsconfig tsconfig.tsup.json",
25
+ "check": "tsc -p tsconfig.json --noEmit"
26
+ }
27
+ }
@@ -0,0 +1,17 @@
1
+ import { AsyncLocalStorage } from "async_hooks";
2
+ import { RequestContext } from "./async-context.types";
3
+
4
+ export const asyncLocalStorage = new AsyncLocalStorage<
5
+ Record<string, unknown>
6
+ >();
7
+
8
+ export function getContext(): RequestContext {
9
+ return asyncLocalStorage.getStore();
10
+ }
11
+
12
+ export function runWithContext<T>(
13
+ ctx: Record<string, unknown>,
14
+ fn: () => T,
15
+ ): T {
16
+ return asyncLocalStorage.run(ctx, fn as any);
17
+ }
@@ -0,0 +1 @@
1
+ export type RequestContext = Record<string, unknown> | undefined;
@@ -0,0 +1 @@
1
+ export const DEFAULT_LOG_LEVEL = "info";