autotel-adapters 0.3.7 → 0.3.9

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 (87) hide show
  1. package/dist/cloudflare.cjs +60 -124
  2. package/dist/cloudflare.cjs.map +1 -1
  3. package/dist/cloudflare.d.cts +24 -24
  4. package/dist/cloudflare.d.cts.map +1 -0
  5. package/dist/cloudflare.d.ts +24 -24
  6. package/dist/cloudflare.d.ts.map +1 -0
  7. package/dist/cloudflare.js +69 -3
  8. package/dist/cloudflare.js.map +1 -1
  9. package/dist/core.cjs +94 -74
  10. package/dist/core.cjs.map +1 -1
  11. package/dist/core.d.cts +20 -19
  12. package/dist/core.d.cts.map +1 -0
  13. package/dist/core.d.ts +20 -19
  14. package/dist/core.d.ts.map +1 -0
  15. package/dist/core.js +110 -2
  16. package/dist/core.js.map +1 -1
  17. package/dist/express.cjs +67 -127
  18. package/dist/express.cjs.map +1 -1
  19. package/dist/express.d.cts +24 -24
  20. package/dist/express.d.cts.map +1 -0
  21. package/dist/express.d.ts +24 -24
  22. package/dist/express.d.ts.map +1 -0
  23. package/dist/express.js +78 -3
  24. package/dist/express.js.map +1 -1
  25. package/dist/fastify.cjs +58 -118
  26. package/dist/fastify.cjs.map +1 -1
  27. package/dist/fastify.d.cts +24 -24
  28. package/dist/fastify.d.cts.map +1 -0
  29. package/dist/fastify.d.ts +24 -24
  30. package/dist/fastify.d.ts.map +1 -0
  31. package/dist/fastify.js +69 -3
  32. package/dist/fastify.js.map +1 -1
  33. package/dist/hono.cjs +18 -48
  34. package/dist/hono.cjs.map +1 -1
  35. package/dist/hono.d.cts +6 -6
  36. package/dist/hono.d.cts.map +1 -0
  37. package/dist/hono.d.ts +6 -6
  38. package/dist/hono.d.ts.map +1 -0
  39. package/dist/hono.js +22 -3
  40. package/dist/hono.js.map +1 -1
  41. package/dist/index.cjs +27 -455
  42. package/dist/index.d.cts +9 -11
  43. package/dist/index.d.ts +9 -11
  44. package/dist/index.js +10 -10
  45. package/dist/next.cjs +56 -119
  46. package/dist/next.cjs.map +1 -1
  47. package/dist/next.d.cts +21 -21
  48. package/dist/next.d.cts.map +1 -0
  49. package/dist/next.d.ts +21 -21
  50. package/dist/next.d.ts.map +1 -0
  51. package/dist/next.js +65 -3
  52. package/dist/next.js.map +1 -1
  53. package/dist/nitro.cjs +50 -93
  54. package/dist/nitro.cjs.map +1 -1
  55. package/dist/nitro.d.cts +19 -19
  56. package/dist/nitro.d.cts.map +1 -0
  57. package/dist/nitro.d.ts +19 -19
  58. package/dist/nitro.d.ts.map +1 -0
  59. package/dist/nitro.js +62 -3
  60. package/dist/nitro.js.map +1 -1
  61. package/dist/tanstack.cjs +16 -46
  62. package/dist/tanstack.cjs.map +1 -1
  63. package/dist/tanstack.d.cts +9 -9
  64. package/dist/tanstack.d.cts.map +1 -0
  65. package/dist/tanstack.d.ts +9 -9
  66. package/dist/tanstack.d.ts.map +1 -0
  67. package/dist/tanstack.js +20 -3
  68. package/dist/tanstack.js.map +1 -1
  69. package/package.json +6 -5
  70. package/dist/chunk-2YPL66HM.js +0 -79
  71. package/dist/chunk-2YPL66HM.js.map +0 -1
  72. package/dist/chunk-6TOW47TB.js +0 -70
  73. package/dist/chunk-6TOW47TB.js.map +0 -1
  74. package/dist/chunk-DJ2OU3S6.js +0 -90
  75. package/dist/chunk-DJ2OU3S6.js.map +0 -1
  76. package/dist/chunk-FAHH33UI.js +0 -76
  77. package/dist/chunk-FAHH33UI.js.map +0 -1
  78. package/dist/chunk-HTZFHBTN.js +0 -82
  79. package/dist/chunk-HTZFHBTN.js.map +0 -1
  80. package/dist/chunk-JH5ZTTLF.js +0 -23
  81. package/dist/chunk-JH5ZTTLF.js.map +0 -1
  82. package/dist/chunk-U3U4WH42.js +0 -21
  83. package/dist/chunk-U3U4WH42.js.map +0 -1
  84. package/dist/chunk-VJZDW2DS.js +0 -87
  85. package/dist/chunk-VJZDW2DS.js.map +0 -1
  86. package/dist/index.cjs.map +0 -1
  87. package/dist/index.js.map +0 -1
package/dist/core.cjs CHANGED
@@ -1,97 +1,117 @@
1
- 'use strict';
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let autotel = require("autotel");
2
3
 
3
- var autotel = require('autotel');
4
-
5
- // src/core.ts
4
+ //#region src/core.ts
6
5
  function createUseLogger(options) {
7
- return function useLogger(context, requestLoggerOptions) {
8
- let logger;
9
- try {
10
- logger = autotel.getRequestLogger(void 0, requestLoggerOptions);
11
- } catch {
12
- throw new Error(
13
- `[autotel-adapters/${options.adapterName}] No active trace context. Wrap your handler with autotel trace instrumentation before calling useLogger().`
14
- );
15
- }
16
- if (context && options.enrich) {
17
- const extra = options.enrich(context);
18
- if (extra && Object.keys(extra).length > 0) {
19
- logger.set(extra);
20
- }
21
- }
22
- return logger;
23
- };
6
+ return function useLogger(context, requestLoggerOptions) {
7
+ let logger;
8
+ try {
9
+ logger = (0, autotel.getRequestLogger)(void 0, requestLoggerOptions);
10
+ } catch {
11
+ throw new Error(`[autotel-adapters/${options.adapterName}] No active trace context. Wrap your handler with autotel trace instrumentation before calling useLogger().`);
12
+ }
13
+ if (context && options.enrich) {
14
+ const extra = options.enrich(context);
15
+ if (extra && Object.keys(extra).length > 0) logger.set(extra);
16
+ }
17
+ return logger;
18
+ };
24
19
  }
20
+ /**
21
+ * Build a request runner bound to one framework's logger storage. The returned
22
+ * function opens a span, creates a request logger, runs `handler` inside the
23
+ * storage so `useLogger()` resolves it, records thrown errors, and emits one
24
+ * wide event when the handler settles (unless `autoEmit` is `false`).
25
+ */
25
26
  function createRequestRunner(storage) {
26
- return function runRequest(spanName, enrich, handler, options) {
27
- const wrapped = autotel.trace(
28
- { name: spanName },
29
- (ctx) => async () => {
30
- const log = autotel.getRequestLogger(ctx, options?.requestLoggerOptions);
31
- enrich(log);
32
- try {
33
- return await storage.run(log, () => handler());
34
- } catch (error) {
35
- log.error(error instanceof Error ? error : new Error(String(error)));
36
- throw error;
37
- } finally {
38
- if (options?.autoEmit !== false) {
39
- log.emitNow(options?.finalize?.());
40
- }
41
- }
42
- }
43
- );
44
- return wrapped();
45
- };
27
+ return function runRequest(spanName, enrich, handler, options) {
28
+ return (0, autotel.trace)({ name: spanName }, (ctx) => async () => {
29
+ const log = (0, autotel.getRequestLogger)(ctx, options?.requestLoggerOptions);
30
+ enrich(log);
31
+ try {
32
+ return await storage.run(log, () => handler());
33
+ } catch (error) {
34
+ log.error(error instanceof Error ? error : new Error(String(error)));
35
+ throw error;
36
+ } finally {
37
+ if (options?.autoEmit !== false) log.emitNow(options?.finalize?.());
38
+ }
39
+ })();
40
+ };
46
41
  }
47
42
  function createAdapterToolkit(options) {
48
- return {
49
- useLogger: createUseLogger(options),
50
- parseError: autotel.parseError,
51
- createStructuredError: autotel.createStructuredError,
52
- createDrainPipeline: autotel.createDrainPipeline
53
- };
43
+ return {
44
+ useLogger: createUseLogger(options),
45
+ parseError: autotel.parseError,
46
+ createStructuredError: autotel.createStructuredError,
47
+ createDrainPipeline: autotel.createDrainPipeline
48
+ };
54
49
  }
55
50
  function resolveEnv(envKeys) {
56
- if (!envKeys) return void 0;
57
- for (const key of envKeys) {
58
- const value = process.env[key];
59
- if (value) return value;
60
- }
61
- return void 0;
51
+ if (!envKeys) return void 0;
52
+ for (const key of envKeys) {
53
+ const value = process.env[key];
54
+ if (value) return value;
55
+ }
62
56
  }
57
+ /**
58
+ * Returns true when at least one env-backed field is not provided via
59
+ * `overrides`, meaning runtime config may still contribute and should be
60
+ * probed to preserve precedence (`overrides > runtime > env`).
61
+ *
62
+ * @example
63
+ * ```ts
64
+ * const FIELDS: ConfigField<MyAdapterConfig>[] = [
65
+ * { key: 'token', env: ['MY_ADAPTER_TOKEN'] },
66
+ * { key: 'endpoint', env: ['MY_ADAPTER_URL'] },
67
+ * ]
68
+ *
69
+ * if (shouldProbeRuntime(FIELDS, overrides)) {
70
+ * runtimeConfig = await loadRuntimeConfig()
71
+ * }
72
+ * ```
73
+ */
63
74
  function shouldProbeRuntime(fields, overrides) {
64
- return fields.some(({ key, env }) => {
65
- if (!env || env.length === 0) return false;
66
- if (overrides?.[key] !== void 0) return false;
67
- return true;
68
- });
75
+ return fields.some(({ key, env }) => {
76
+ if (!env || env.length === 0) return false;
77
+ if (overrides?.[key] !== void 0) return false;
78
+ return true;
79
+ });
69
80
  }
81
+ /**
82
+ * Resolve adapter configuration with the standard priority chain:
83
+ *
84
+ * 1. `overrides` passed to the adapter factory
85
+ * 2. `runtimeConfig.autotel.{namespace}.{key}` (if a probe was performed)
86
+ * 3. `runtimeConfig.{namespace}.{key}` (if a probe was performed)
87
+ * 4. `process.env[envKey]` for each env in `field.env`
88
+ *
89
+ * Pass an async `probe` to defer the runtime config lookup so it is only
90
+ * invoked when runtime resolution is needed (i.e. at least one env-backed
91
+ * field is not set by overrides). Adapters that have no probe target may pass
92
+ * `() => Promise.resolve(undefined)`.
93
+ */
70
94
  async function resolveAdapterConfig(namespace, fields, overrides, probe) {
71
- const runtimeConfig = shouldProbeRuntime(fields, overrides) ? await probe() : void 0;
72
- const autotelNs = runtimeConfig?.autotel?.[namespace];
73
- const rootNs = runtimeConfig?.[namespace];
74
- const config = {};
75
- for (const { key, env } of fields) {
76
- config[key] = overrides?.[key] ?? autotelNs?.[key] ?? rootNs?.[key] ?? resolveEnv(env);
77
- }
78
- return config;
95
+ const runtimeConfig = shouldProbeRuntime(fields, overrides) ? await probe() : void 0;
96
+ const autotelNs = runtimeConfig?.autotel?.[namespace];
97
+ const rootNs = runtimeConfig?.[namespace];
98
+ const config = {};
99
+ for (const { key, env } of fields) config[key] = overrides?.[key] ?? autotelNs?.[key] ?? rootNs?.[key] ?? resolveEnv(env);
100
+ return config;
79
101
  }
80
102
  function getHeader(headers, name) {
81
- if (!headers) return void 0;
82
- if ("get" in headers && typeof headers.get === "function") {
83
- return headers.get(name) ?? void 0;
84
- }
85
- const dictionary = headers;
86
- const value = dictionary[name] ?? dictionary[name.toLowerCase()];
87
- return typeof value === "string" ? value : void 0;
103
+ if (!headers) return void 0;
104
+ if ("get" in headers && typeof headers.get === "function") return headers.get(name) ?? void 0;
105
+ const dictionary = headers;
106
+ const value = dictionary[name] ?? dictionary[name.toLowerCase()];
107
+ return typeof value === "string" ? value : void 0;
88
108
  }
89
109
 
110
+ //#endregion
90
111
  exports.createAdapterToolkit = createAdapterToolkit;
91
112
  exports.createRequestRunner = createRequestRunner;
92
113
  exports.createUseLogger = createUseLogger;
93
114
  exports.getHeader = getHeader;
94
115
  exports.resolveAdapterConfig = resolveAdapterConfig;
95
116
  exports.shouldProbeRuntime = shouldProbeRuntime;
96
- //# sourceMappingURL=core.cjs.map
97
117
  //# sourceMappingURL=core.cjs.map
package/dist/core.cjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core.ts"],"names":["getRequestLogger","trace","parseError","createStructuredError","createDrainPipeline"],"mappings":"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","file":"core.cjs","sourcesContent":["import type { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n createDrainPipeline,\n createStructuredError,\n getRequestLogger,\n parseError,\n trace,\n type ParsedError,\n type RequestLogger,\n type RequestLoggerOptions,\n type RequestLogSnapshot,\n type DrainPipelineOptions,\n type PipelineDrainFn,\n type StructuredError,\n type StructuredErrorInput,\n} from 'autotel';\n\nexport interface AdapterUseLoggerOptions<TContext> {\n adapterName: string;\n enrich?: (context: TContext) => Record<string, unknown> | undefined;\n}\n\nexport interface AdapterToolkit<TContext> {\n useLogger: (\n context?: TContext,\n options?: RequestLoggerOptions,\n ) => RequestLogger;\n parseError: (error: unknown) => ParsedError;\n createStructuredError: (input: StructuredErrorInput) => StructuredError;\n createDrainPipeline: <T = unknown>(\n options?: DrainPipelineOptions<T>,\n ) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;\n}\n\nexport function createUseLogger<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n) {\n return function useLogger(\n context?: TContext,\n requestLoggerOptions?: RequestLoggerOptions,\n ): RequestLogger {\n let logger: RequestLogger;\n try {\n logger = getRequestLogger(undefined, requestLoggerOptions);\n } catch {\n throw new Error(\n `[autotel-adapters/${options.adapterName}] No active trace context. ` +\n `Wrap your handler with autotel trace instrumentation before calling useLogger().`,\n );\n }\n\n if (context && options.enrich) {\n const extra = options.enrich(context);\n if (extra && Object.keys(extra).length > 0) {\n logger.set(extra);\n }\n }\n\n return logger;\n };\n}\n\nexport interface RequestRunnerOptions {\n requestLoggerOptions?: RequestLoggerOptions;\n /** Emit one wide event automatically when the handler settles. Default `true`. */\n autoEmit?: boolean;\n /** Fields merged into the wide event at emit time (e.g. response status). */\n finalize?: () => Record<string, unknown> | undefined;\n}\n\n/**\n * Build a request runner bound to one framework's logger storage. The returned\n * function opens a span, creates a request logger, runs `handler` inside the\n * storage so `useLogger()` resolves it, records thrown errors, and emits one\n * wide event when the handler settles (unless `autoEmit` is `false`).\n */\nexport function createRequestRunner(storage: AsyncLocalStorage<RequestLogger>) {\n return function runRequest<T>(\n spanName: string,\n enrich: (log: RequestLogger) => void,\n handler: () => T | Promise<T>,\n options?: RequestRunnerOptions,\n ): Promise<T> {\n const wrapped = trace(\n { name: spanName },\n (ctx) => async (): Promise<T> => {\n const log = getRequestLogger(ctx, options?.requestLoggerOptions);\n enrich(log);\n try {\n return await storage.run(log, () => handler());\n } catch (error) {\n log.error(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n if (options?.autoEmit !== false) {\n log.emitNow(options?.finalize?.());\n }\n }\n },\n );\n return wrapped();\n };\n}\n\nexport function createAdapterToolkit<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n): AdapterToolkit<TContext> {\n return {\n useLogger: createUseLogger(options),\n parseError,\n createStructuredError,\n createDrainPipeline,\n };\n}\n\n/**\n * Description of a single adapter config field. `env` is the ordered list of\n * environment variables to fall back to.\n */\nexport interface ConfigField<T> {\n key: keyof T & string;\n env?: string[];\n}\n\nfunction resolveEnv(envKeys?: string[]): string | undefined {\n if (!envKeys) return undefined;\n for (const key of envKeys) {\n const value = process.env[key];\n if (value) return value;\n }\n return undefined;\n}\n\n/**\n * Returns true when at least one env-backed field is not provided via\n * `overrides`, meaning runtime config may still contribute and should be\n * probed to preserve precedence (`overrides > runtime > env`).\n *\n * @example\n * ```ts\n * const FIELDS: ConfigField<MyAdapterConfig>[] = [\n * { key: 'token', env: ['MY_ADAPTER_TOKEN'] },\n * { key: 'endpoint', env: ['MY_ADAPTER_URL'] },\n * ]\n *\n * if (shouldProbeRuntime(FIELDS, overrides)) {\n * runtimeConfig = await loadRuntimeConfig()\n * }\n * ```\n */\nexport function shouldProbeRuntime<T>(\n fields: ConfigField<T>[],\n overrides?: Partial<T>,\n): boolean {\n return fields.some(({ key, env }) => {\n if (!env || env.length === 0) return false;\n if (overrides?.[key] !== undefined) return false;\n return true;\n });\n}\n\n/**\n * Resolve adapter configuration with the standard priority chain:\n *\n * 1. `overrides` passed to the adapter factory\n * 2. `runtimeConfig.autotel.{namespace}.{key}` (if a probe was performed)\n * 3. `runtimeConfig.{namespace}.{key}` (if a probe was performed)\n * 4. `process.env[envKey]` for each env in `field.env`\n *\n * Pass an async `probe` to defer the runtime config lookup so it is only\n * invoked when runtime resolution is needed (i.e. at least one env-backed\n * field is not set by overrides). Adapters that have no probe target may pass\n * `() => Promise.resolve(undefined)`.\n */\nexport async function resolveAdapterConfig<T>(\n namespace: string,\n fields: ConfigField<T>[],\n overrides: Partial<T> | undefined,\n probe: () => Promise<Record<string, any> | undefined>,\n): Promise<Partial<T>> {\n const runtimeConfig = shouldProbeRuntime(fields, overrides)\n ? await probe()\n : undefined;\n const autotelNs = runtimeConfig?.autotel?.[namespace];\n const rootNs = runtimeConfig?.[namespace];\n\n const config: Record<string, unknown> = {};\n for (const { key, env } of fields) {\n config[key] =\n overrides?.[key] ??\n autotelNs?.[key] ??\n rootNs?.[key] ??\n resolveEnv(env);\n }\n\n return config as Partial<T>;\n}\n\nexport type HeadersLike =\n | { get(name: string): string | null }\n | Record<string, string | undefined>;\n\nexport function getHeader(\n headers: HeadersLike | undefined,\n name: string,\n): string | undefined {\n if (!headers) return undefined;\n if ('get' in headers && typeof headers.get === 'function') {\n return headers.get(name) ?? undefined;\n }\n const dictionary = headers as Record<string, string | undefined>;\n const value = dictionary[name] ?? dictionary[name.toLowerCase()];\n return typeof value === 'string' ? value : undefined;\n}\n\nexport type {\n RequestLogger,\n RequestLoggerOptions,\n RequestLogSnapshot,\n ParsedError,\n StructuredError,\n StructuredErrorInput,\n DrainPipelineOptions,\n PipelineDrainFn,\n};\n"]}
1
+ {"version":3,"file":"core.cjs","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n createDrainPipeline,\n createStructuredError,\n getRequestLogger,\n parseError,\n trace,\n type ParsedError,\n type RequestLogger,\n type RequestLoggerOptions,\n type RequestLogSnapshot,\n type DrainPipelineOptions,\n type PipelineDrainFn,\n type StructuredError,\n type StructuredErrorInput,\n} from 'autotel';\n\nexport interface AdapterUseLoggerOptions<TContext> {\n adapterName: string;\n enrich?: (context: TContext) => Record<string, unknown> | undefined;\n}\n\nexport interface AdapterToolkit<TContext> {\n useLogger: (\n context?: TContext,\n options?: RequestLoggerOptions,\n ) => RequestLogger;\n parseError: (error: unknown) => ParsedError;\n createStructuredError: (input: StructuredErrorInput) => StructuredError;\n createDrainPipeline: <T = unknown>(\n options?: DrainPipelineOptions<T>,\n ) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;\n}\n\nexport function createUseLogger<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n) {\n return function useLogger(\n context?: TContext,\n requestLoggerOptions?: RequestLoggerOptions,\n ): RequestLogger {\n let logger: RequestLogger;\n try {\n logger = getRequestLogger(undefined, requestLoggerOptions);\n } catch {\n throw new Error(\n `[autotel-adapters/${options.adapterName}] No active trace context. ` +\n `Wrap your handler with autotel trace instrumentation before calling useLogger().`,\n );\n }\n\n if (context && options.enrich) {\n const extra = options.enrich(context);\n if (extra && Object.keys(extra).length > 0) {\n logger.set(extra);\n }\n }\n\n return logger;\n };\n}\n\nexport interface RequestRunnerOptions {\n requestLoggerOptions?: RequestLoggerOptions;\n /** Emit one wide event automatically when the handler settles. Default `true`. */\n autoEmit?: boolean;\n /** Fields merged into the wide event at emit time (e.g. response status). */\n finalize?: () => Record<string, unknown> | undefined;\n}\n\n/**\n * Build a request runner bound to one framework's logger storage. The returned\n * function opens a span, creates a request logger, runs `handler` inside the\n * storage so `useLogger()` resolves it, records thrown errors, and emits one\n * wide event when the handler settles (unless `autoEmit` is `false`).\n */\nexport function createRequestRunner(storage: AsyncLocalStorage<RequestLogger>) {\n return function runRequest<T>(\n spanName: string,\n enrich: (log: RequestLogger) => void,\n handler: () => T | Promise<T>,\n options?: RequestRunnerOptions,\n ): Promise<T> {\n const wrapped = trace(\n { name: spanName },\n (ctx) => async (): Promise<T> => {\n const log = getRequestLogger(ctx, options?.requestLoggerOptions);\n enrich(log);\n try {\n return await storage.run(log, () => handler());\n } catch (error) {\n log.error(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n if (options?.autoEmit !== false) {\n log.emitNow(options?.finalize?.());\n }\n }\n },\n );\n return wrapped();\n };\n}\n\nexport function createAdapterToolkit<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n): AdapterToolkit<TContext> {\n return {\n useLogger: createUseLogger(options),\n parseError,\n createStructuredError,\n createDrainPipeline,\n };\n}\n\n/**\n * Description of a single adapter config field. `env` is the ordered list of\n * environment variables to fall back to.\n */\nexport interface ConfigField<T> {\n key: keyof T & string;\n env?: string[];\n}\n\nfunction resolveEnv(envKeys?: string[]): string | undefined {\n if (!envKeys) return undefined;\n for (const key of envKeys) {\n const value = process.env[key];\n if (value) return value;\n }\n return undefined;\n}\n\n/**\n * Returns true when at least one env-backed field is not provided via\n * `overrides`, meaning runtime config may still contribute and should be\n * probed to preserve precedence (`overrides > runtime > env`).\n *\n * @example\n * ```ts\n * const FIELDS: ConfigField<MyAdapterConfig>[] = [\n * { key: 'token', env: ['MY_ADAPTER_TOKEN'] },\n * { key: 'endpoint', env: ['MY_ADAPTER_URL'] },\n * ]\n *\n * if (shouldProbeRuntime(FIELDS, overrides)) {\n * runtimeConfig = await loadRuntimeConfig()\n * }\n * ```\n */\nexport function shouldProbeRuntime<T>(\n fields: ConfigField<T>[],\n overrides?: Partial<T>,\n): boolean {\n return fields.some(({ key, env }) => {\n if (!env || env.length === 0) return false;\n if (overrides?.[key] !== undefined) return false;\n return true;\n });\n}\n\n/**\n * Resolve adapter configuration with the standard priority chain:\n *\n * 1. `overrides` passed to the adapter factory\n * 2. `runtimeConfig.autotel.{namespace}.{key}` (if a probe was performed)\n * 3. `runtimeConfig.{namespace}.{key}` (if a probe was performed)\n * 4. `process.env[envKey]` for each env in `field.env`\n *\n * Pass an async `probe` to defer the runtime config lookup so it is only\n * invoked when runtime resolution is needed (i.e. at least one env-backed\n * field is not set by overrides). Adapters that have no probe target may pass\n * `() => Promise.resolve(undefined)`.\n */\nexport async function resolveAdapterConfig<T>(\n namespace: string,\n fields: ConfigField<T>[],\n overrides: Partial<T> | undefined,\n probe: () => Promise<Record<string, any> | undefined>,\n): Promise<Partial<T>> {\n const runtimeConfig = shouldProbeRuntime(fields, overrides)\n ? await probe()\n : undefined;\n const autotelNs = runtimeConfig?.autotel?.[namespace];\n const rootNs = runtimeConfig?.[namespace];\n\n const config: Record<string, unknown> = {};\n for (const { key, env } of fields) {\n config[key] =\n overrides?.[key] ??\n autotelNs?.[key] ??\n rootNs?.[key] ??\n resolveEnv(env);\n }\n\n return config as Partial<T>;\n}\n\nexport type HeadersLike =\n | { get(name: string): string | null }\n | Record<string, string | undefined>;\n\nexport function getHeader(\n headers: HeadersLike | undefined,\n name: string,\n): string | undefined {\n if (!headers) return undefined;\n if ('get' in headers && typeof headers.get === 'function') {\n return headers.get(name) ?? undefined;\n }\n const dictionary = headers as Record<string, string | undefined>;\n const value = dictionary[name] ?? dictionary[name.toLowerCase()];\n return typeof value === 'string' ? value : undefined;\n}\n\nexport type {\n RequestLogger,\n RequestLoggerOptions,\n RequestLogSnapshot,\n ParsedError,\n StructuredError,\n StructuredErrorInput,\n DrainPipelineOptions,\n PipelineDrainFn,\n};\n"],"mappings":";;;;AAkCA,SAAgB,gBACd,SACA;CACA,OAAO,SAAS,UACd,SACA,sBACe;EACf,IAAI;EACJ,IAAI;GACF,uCAA0B,QAAW,oBAAoB;EAC3D,QAAQ;GACN,MAAM,IAAI,MACR,qBAAqB,QAAQ,YAAY,4GAE3C;EACF;EAEA,IAAI,WAAW,QAAQ,QAAQ;GAC7B,MAAM,QAAQ,QAAQ,OAAO,OAAO;GACpC,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,GACvC,OAAO,IAAI,KAAK;EAEpB;EAEA,OAAO;CACT;AACF;;;;;;;AAgBA,SAAgB,oBAAoB,SAA2C;CAC7E,OAAO,SAAS,WACd,UACA,QACA,SACA,SACY;EAkBZ,0BAhBE,EAAE,MAAM,SAAS,IAChB,QAAQ,YAAwB;GAC/B,MAAM,oCAAuB,KAAK,SAAS,oBAAoB;GAC/D,OAAO,GAAG;GACV,IAAI;IACF,OAAO,MAAM,QAAQ,IAAI,WAAW,QAAQ,CAAC;GAC/C,SAAS,OAAO;IACd,IAAI,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;IACnE,MAAM;GACR,UAAU;IACR,IAAI,SAAS,aAAa,OACxB,IAAI,QAAQ,SAAS,WAAW,CAAC;GAErC;EACF,CAEW,CAAC,CAAC;CACjB;AACF;AAEA,SAAgB,qBACd,SAC0B;CAC1B,OAAO;EACL,WAAW,gBAAgB,OAAO;EAClC;EACA;EACA;CACF;AACF;AAWA,SAAS,WAAW,SAAwC;CAC1D,IAAI,CAAC,SAAS,OAAO;CACrB,KAAK,MAAM,OAAO,SAAS;EACzB,MAAM,QAAQ,QAAQ,IAAI;EAC1B,IAAI,OAAO,OAAO;CACpB;AAEF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBACd,QACA,WACS;CACT,OAAO,OAAO,MAAM,EAAE,KAAK,UAAU;EACnC,IAAI,CAAC,OAAO,IAAI,WAAW,GAAG,OAAO;EACrC,IAAI,YAAY,SAAS,QAAW,OAAO;EAC3C,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;;;AAeA,eAAsB,qBACpB,WACA,QACA,WACA,OACqB;CACrB,MAAM,gBAAgB,mBAAmB,QAAQ,SAAS,IACtD,MAAM,MAAM,IACZ;CACJ,MAAM,YAAY,eAAe,UAAU;CAC3C,MAAM,SAAS,gBAAgB;CAE/B,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,EAAE,KAAK,SAAS,QACzB,OAAO,OACL,YAAY,QACZ,YAAY,QACZ,SAAS,QACT,WAAW,GAAG;CAGlB,OAAO;AACT;AAMA,SAAgB,UACd,SACA,MACoB;CACpB,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,SAAS,WAAW,OAAO,QAAQ,QAAQ,YAC7C,OAAO,QAAQ,IAAI,IAAI,KAAK;CAE9B,MAAM,aAAa;CACnB,MAAM,QAAQ,WAAW,SAAS,WAAW,KAAK,YAAY;CAC9D,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C"}
package/dist/core.d.cts CHANGED
@@ -1,24 +1,24 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { RequestLoggerOptions, RequestLogger, ParsedError, StructuredErrorInput, StructuredError, DrainPipelineOptions, PipelineDrainFn } from 'autotel';
3
- export { DrainPipelineOptions, ParsedError, PipelineDrainFn, RequestLogSnapshot, RequestLogger, RequestLoggerOptions, StructuredError, StructuredErrorInput } from 'autotel';
1
+ import { AsyncLocalStorage } from "node:async_hooks";
2
+ import { DrainPipelineOptions, ParsedError, PipelineDrainFn, RequestLogSnapshot, RequestLogger, RequestLoggerOptions, StructuredError, StructuredErrorInput } from "autotel";
4
3
 
4
+ //#region src/core.d.ts
5
5
  interface AdapterUseLoggerOptions<TContext> {
6
- adapterName: string;
7
- enrich?: (context: TContext) => Record<string, unknown> | undefined;
6
+ adapterName: string;
7
+ enrich?: (context: TContext) => Record<string, unknown> | undefined;
8
8
  }
9
9
  interface AdapterToolkit<TContext> {
10
- useLogger: (context?: TContext, options?: RequestLoggerOptions) => RequestLogger;
11
- parseError: (error: unknown) => ParsedError;
12
- createStructuredError: (input: StructuredErrorInput) => StructuredError;
13
- createDrainPipeline: <T = unknown>(options?: DrainPipelineOptions<T>) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;
10
+ useLogger: (context?: TContext, options?: RequestLoggerOptions) => RequestLogger;
11
+ parseError: (error: unknown) => ParsedError;
12
+ createStructuredError: (input: StructuredErrorInput) => StructuredError;
13
+ createDrainPipeline: <T = unknown>(options?: DrainPipelineOptions<T>) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;
14
14
  }
15
15
  declare function createUseLogger<TContext = unknown>(options: AdapterUseLoggerOptions<TContext>): (context?: TContext, requestLoggerOptions?: RequestLoggerOptions) => RequestLogger;
16
16
  interface RequestRunnerOptions {
17
- requestLoggerOptions?: RequestLoggerOptions;
18
- /** Emit one wide event automatically when the handler settles. Default `true`. */
19
- autoEmit?: boolean;
20
- /** Fields merged into the wide event at emit time (e.g. response status). */
21
- finalize?: () => Record<string, unknown> | undefined;
17
+ requestLoggerOptions?: RequestLoggerOptions;
18
+ /** Emit one wide event automatically when the handler settles. Default `true`. */
19
+ autoEmit?: boolean;
20
+ /** Fields merged into the wide event at emit time (e.g. response status). */
21
+ finalize?: () => Record<string, unknown> | undefined;
22
22
  }
23
23
  /**
24
24
  * Build a request runner bound to one framework's logger storage. The returned
@@ -33,8 +33,8 @@ declare function createAdapterToolkit<TContext = unknown>(options: AdapterUseLog
33
33
  * environment variables to fall back to.
34
34
  */
35
35
  interface ConfigField<T> {
36
- key: keyof T & string;
37
- env?: string[];
36
+ key: keyof T & string;
37
+ env?: string[];
38
38
  }
39
39
  /**
40
40
  * Returns true when at least one env-backed field is not provided via
@@ -69,8 +69,9 @@ declare function shouldProbeRuntime<T>(fields: ConfigField<T>[], overrides?: Par
69
69
  */
70
70
  declare function resolveAdapterConfig<T>(namespace: string, fields: ConfigField<T>[], overrides: Partial<T> | undefined, probe: () => Promise<Record<string, any> | undefined>): Promise<Partial<T>>;
71
71
  type HeadersLike = {
72
- get(name: string): string | null;
72
+ get(name: string): string | null;
73
73
  } | Record<string, string | undefined>;
74
74
  declare function getHeader(headers: HeadersLike | undefined, name: string): string | undefined;
75
-
76
- export { type AdapterToolkit, type AdapterUseLoggerOptions, type ConfigField, type HeadersLike, type RequestRunnerOptions, createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime };
75
+ //#endregion
76
+ export { AdapterToolkit, AdapterUseLoggerOptions, ConfigField, type DrainPipelineOptions, HeadersLike, type ParsedError, type PipelineDrainFn, type RequestLogSnapshot, type RequestLogger, type RequestLoggerOptions, RequestRunnerOptions, type StructuredError, type StructuredErrorInput, createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime };
77
+ //# sourceMappingURL=core.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.cts","names":[],"sources":["../src/core.ts"],"mappings":";;;;UAiBiB,uBAAA;EACf,WAAA;EACA,MAAA,IAAU,OAAA,EAAS,QAAA,KAAa,MAAM;AAAA;AAAA,UAGvB,cAAA;EACf,SAAA,GACE,OAAA,GAAU,QAAA,EACV,OAAA,GAAU,oBAAA,KACP,aAAA;EACL,UAAA,GAAa,KAAA,cAAmB,WAAA;EAChC,qBAAA,GAAwB,KAAA,EAAO,oBAAA,KAAyB,eAAA;EACxD,mBAAA,gBACE,OAAA,GAAU,oBAAA,CAAqB,CAAA,OAC3B,KAAA,GAAQ,KAAA,EAAO,CAAA,cAAe,OAAA,WAAkB,eAAA,CAAgB,CAAA;AAAA;AAAA,iBAGxD,eAAA,qBACd,OAAA,EAAS,uBAAA,CAAwB,QAAA,KAG/B,OAAA,GAAU,QAAA,EACV,oBAAA,GAAuB,oBAAA,KACtB,aAAA;AAAA,UAsBY,oBAAA;EACf,oBAAA,GAAuB,oBAAA;EA5Ce;EA8CtC,QAAA;EA3C6B;EA6C7B,QAAA,SAAiB,MAAM;AAAA;;;;;;;iBAST,mBAAA,CAAoB,OAAA,EAAS,iBAAA,CAAkB,aAAA,QAE3D,QAAA,UACA,MAAA,GAAS,GAAA,EAAK,aAAA,WACd,OAAA,QAAe,CAAA,GAAI,OAAA,CAAQ,CAAA,GAC3B,OAAA,GAAU,oBAAA,KACT,OAAA,CAAQ,CAAA;AAAA,iBAsBG,oBAAA,qBACd,OAAA,EAAS,uBAAA,CAAwB,QAAA,IAChC,cAAA,CAAe,QAAA;;;;;UAaD,WAAA;EACf,GAAA,QAAW,CAAC;EACZ,GAAA;AAAA;;;;;;;;;;;;;;;;;;iBA6Bc,kBAAA,IACd,MAAA,EAAQ,WAAA,CAAY,CAAA,KACpB,SAAA,GAAY,OAAA,CAAQ,CAAA;;;;;;AAzHmD;AAGzE;;;;;;;iBA4IsB,oBAAA,IACpB,SAAA,UACA,MAAA,EAAQ,WAAA,CAAY,CAAA,KACpB,SAAA,EAAW,OAAA,CAAQ,CAAA,eACnB,KAAA,QAAa,OAAA,CAAQ,MAAA,6BACpB,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAAA,KAmBP,WAAA;EACN,GAAA,CAAI,IAAA;AAAA,IACN,MAAM;AAAA,iBAEM,SAAA,CACd,OAAA,EAAS,WAAW,cACpB,IAAA"}
package/dist/core.d.ts CHANGED
@@ -1,24 +1,24 @@
1
- import { AsyncLocalStorage } from 'node:async_hooks';
2
- import { RequestLoggerOptions, RequestLogger, ParsedError, StructuredErrorInput, StructuredError, DrainPipelineOptions, PipelineDrainFn } from 'autotel';
3
- export { DrainPipelineOptions, ParsedError, PipelineDrainFn, RequestLogSnapshot, RequestLogger, RequestLoggerOptions, StructuredError, StructuredErrorInput } from 'autotel';
1
+ import { DrainPipelineOptions, ParsedError, PipelineDrainFn, RequestLogSnapshot, RequestLogger, RequestLoggerOptions, StructuredError, StructuredErrorInput } from "autotel";
2
+ import { AsyncLocalStorage } from "node:async_hooks";
4
3
 
4
+ //#region src/core.d.ts
5
5
  interface AdapterUseLoggerOptions<TContext> {
6
- adapterName: string;
7
- enrich?: (context: TContext) => Record<string, unknown> | undefined;
6
+ adapterName: string;
7
+ enrich?: (context: TContext) => Record<string, unknown> | undefined;
8
8
  }
9
9
  interface AdapterToolkit<TContext> {
10
- useLogger: (context?: TContext, options?: RequestLoggerOptions) => RequestLogger;
11
- parseError: (error: unknown) => ParsedError;
12
- createStructuredError: (input: StructuredErrorInput) => StructuredError;
13
- createDrainPipeline: <T = unknown>(options?: DrainPipelineOptions<T>) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;
10
+ useLogger: (context?: TContext, options?: RequestLoggerOptions) => RequestLogger;
11
+ parseError: (error: unknown) => ParsedError;
12
+ createStructuredError: (input: StructuredErrorInput) => StructuredError;
13
+ createDrainPipeline: <T = unknown>(options?: DrainPipelineOptions<T>) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;
14
14
  }
15
15
  declare function createUseLogger<TContext = unknown>(options: AdapterUseLoggerOptions<TContext>): (context?: TContext, requestLoggerOptions?: RequestLoggerOptions) => RequestLogger;
16
16
  interface RequestRunnerOptions {
17
- requestLoggerOptions?: RequestLoggerOptions;
18
- /** Emit one wide event automatically when the handler settles. Default `true`. */
19
- autoEmit?: boolean;
20
- /** Fields merged into the wide event at emit time (e.g. response status). */
21
- finalize?: () => Record<string, unknown> | undefined;
17
+ requestLoggerOptions?: RequestLoggerOptions;
18
+ /** Emit one wide event automatically when the handler settles. Default `true`. */
19
+ autoEmit?: boolean;
20
+ /** Fields merged into the wide event at emit time (e.g. response status). */
21
+ finalize?: () => Record<string, unknown> | undefined;
22
22
  }
23
23
  /**
24
24
  * Build a request runner bound to one framework's logger storage. The returned
@@ -33,8 +33,8 @@ declare function createAdapterToolkit<TContext = unknown>(options: AdapterUseLog
33
33
  * environment variables to fall back to.
34
34
  */
35
35
  interface ConfigField<T> {
36
- key: keyof T & string;
37
- env?: string[];
36
+ key: keyof T & string;
37
+ env?: string[];
38
38
  }
39
39
  /**
40
40
  * Returns true when at least one env-backed field is not provided via
@@ -69,8 +69,9 @@ declare function shouldProbeRuntime<T>(fields: ConfigField<T>[], overrides?: Par
69
69
  */
70
70
  declare function resolveAdapterConfig<T>(namespace: string, fields: ConfigField<T>[], overrides: Partial<T> | undefined, probe: () => Promise<Record<string, any> | undefined>): Promise<Partial<T>>;
71
71
  type HeadersLike = {
72
- get(name: string): string | null;
72
+ get(name: string): string | null;
73
73
  } | Record<string, string | undefined>;
74
74
  declare function getHeader(headers: HeadersLike | undefined, name: string): string | undefined;
75
-
76
- export { type AdapterToolkit, type AdapterUseLoggerOptions, type ConfigField, type HeadersLike, type RequestRunnerOptions, createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime };
75
+ //#endregion
76
+ export { AdapterToolkit, AdapterUseLoggerOptions, ConfigField, type DrainPipelineOptions, HeadersLike, type ParsedError, type PipelineDrainFn, type RequestLogSnapshot, type RequestLogger, type RequestLoggerOptions, RequestRunnerOptions, type StructuredError, type StructuredErrorInput, createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime };
77
+ //# sourceMappingURL=core.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"core.d.ts","names":[],"sources":["../src/core.ts"],"mappings":";;;;UAiBiB,uBAAA;EACf,WAAA;EACA,MAAA,IAAU,OAAA,EAAS,QAAA,KAAa,MAAM;AAAA;AAAA,UAGvB,cAAA;EACf,SAAA,GACE,OAAA,GAAU,QAAA,EACV,OAAA,GAAU,oBAAA,KACP,aAAA;EACL,UAAA,GAAa,KAAA,cAAmB,WAAA;EAChC,qBAAA,GAAwB,KAAA,EAAO,oBAAA,KAAyB,eAAA;EACxD,mBAAA,gBACE,OAAA,GAAU,oBAAA,CAAqB,CAAA,OAC3B,KAAA,GAAQ,KAAA,EAAO,CAAA,cAAe,OAAA,WAAkB,eAAA,CAAgB,CAAA;AAAA;AAAA,iBAGxD,eAAA,qBACd,OAAA,EAAS,uBAAA,CAAwB,QAAA,KAG/B,OAAA,GAAU,QAAA,EACV,oBAAA,GAAuB,oBAAA,KACtB,aAAA;AAAA,UAsBY,oBAAA;EACf,oBAAA,GAAuB,oBAAA;EA5Ce;EA8CtC,QAAA;EA3C6B;EA6C7B,QAAA,SAAiB,MAAM;AAAA;;;;;;;iBAST,mBAAA,CAAoB,OAAA,EAAS,iBAAA,CAAkB,aAAA,QAE3D,QAAA,UACA,MAAA,GAAS,GAAA,EAAK,aAAA,WACd,OAAA,QAAe,CAAA,GAAI,OAAA,CAAQ,CAAA,GAC3B,OAAA,GAAU,oBAAA,KACT,OAAA,CAAQ,CAAA;AAAA,iBAsBG,oBAAA,qBACd,OAAA,EAAS,uBAAA,CAAwB,QAAA,IAChC,cAAA,CAAe,QAAA;;;;;UAaD,WAAA;EACf,GAAA,QAAW,CAAC;EACZ,GAAA;AAAA;;;;;;;;;;;;;;;;;;iBA6Bc,kBAAA,IACd,MAAA,EAAQ,WAAA,CAAY,CAAA,KACpB,SAAA,GAAY,OAAA,CAAQ,CAAA;;;;;;AAzHmD;AAGzE;;;;;;;iBA4IsB,oBAAA,IACpB,SAAA,UACA,MAAA,EAAQ,WAAA,CAAY,CAAA,KACpB,SAAA,EAAW,OAAA,CAAQ,CAAA,eACnB,KAAA,QAAa,OAAA,CAAQ,MAAA,6BACpB,OAAA,CAAQ,OAAA,CAAQ,CAAA;AAAA,KAmBP,WAAA;EACN,GAAA,CAAI,IAAA;AAAA,IACN,MAAM;AAAA,iBAEM,SAAA,CACd,OAAA,EAAS,WAAW,cACpB,IAAA"}
package/dist/core.js CHANGED
@@ -1,3 +1,111 @@
1
- export { createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime } from './chunk-DJ2OU3S6.js';
2
- //# sourceMappingURL=core.js.map
1
+ import { createDrainPipeline, createStructuredError, getRequestLogger, parseError, trace } from "autotel";
2
+
3
+ //#region src/core.ts
4
+ function createUseLogger(options) {
5
+ return function useLogger(context, requestLoggerOptions) {
6
+ let logger;
7
+ try {
8
+ logger = getRequestLogger(void 0, requestLoggerOptions);
9
+ } catch {
10
+ throw new Error(`[autotel-adapters/${options.adapterName}] No active trace context. Wrap your handler with autotel trace instrumentation before calling useLogger().`);
11
+ }
12
+ if (context && options.enrich) {
13
+ const extra = options.enrich(context);
14
+ if (extra && Object.keys(extra).length > 0) logger.set(extra);
15
+ }
16
+ return logger;
17
+ };
18
+ }
19
+ /**
20
+ * Build a request runner bound to one framework's logger storage. The returned
21
+ * function opens a span, creates a request logger, runs `handler` inside the
22
+ * storage so `useLogger()` resolves it, records thrown errors, and emits one
23
+ * wide event when the handler settles (unless `autoEmit` is `false`).
24
+ */
25
+ function createRequestRunner(storage) {
26
+ return function runRequest(spanName, enrich, handler, options) {
27
+ return trace({ name: spanName }, (ctx) => async () => {
28
+ const log = getRequestLogger(ctx, options?.requestLoggerOptions);
29
+ enrich(log);
30
+ try {
31
+ return await storage.run(log, () => handler());
32
+ } catch (error) {
33
+ log.error(error instanceof Error ? error : new Error(String(error)));
34
+ throw error;
35
+ } finally {
36
+ if (options?.autoEmit !== false) log.emitNow(options?.finalize?.());
37
+ }
38
+ })();
39
+ };
40
+ }
41
+ function createAdapterToolkit(options) {
42
+ return {
43
+ useLogger: createUseLogger(options),
44
+ parseError,
45
+ createStructuredError,
46
+ createDrainPipeline
47
+ };
48
+ }
49
+ function resolveEnv(envKeys) {
50
+ if (!envKeys) return void 0;
51
+ for (const key of envKeys) {
52
+ const value = process.env[key];
53
+ if (value) return value;
54
+ }
55
+ }
56
+ /**
57
+ * Returns true when at least one env-backed field is not provided via
58
+ * `overrides`, meaning runtime config may still contribute and should be
59
+ * probed to preserve precedence (`overrides > runtime > env`).
60
+ *
61
+ * @example
62
+ * ```ts
63
+ * const FIELDS: ConfigField<MyAdapterConfig>[] = [
64
+ * { key: 'token', env: ['MY_ADAPTER_TOKEN'] },
65
+ * { key: 'endpoint', env: ['MY_ADAPTER_URL'] },
66
+ * ]
67
+ *
68
+ * if (shouldProbeRuntime(FIELDS, overrides)) {
69
+ * runtimeConfig = await loadRuntimeConfig()
70
+ * }
71
+ * ```
72
+ */
73
+ function shouldProbeRuntime(fields, overrides) {
74
+ return fields.some(({ key, env }) => {
75
+ if (!env || env.length === 0) return false;
76
+ if (overrides?.[key] !== void 0) return false;
77
+ return true;
78
+ });
79
+ }
80
+ /**
81
+ * Resolve adapter configuration with the standard priority chain:
82
+ *
83
+ * 1. `overrides` passed to the adapter factory
84
+ * 2. `runtimeConfig.autotel.{namespace}.{key}` (if a probe was performed)
85
+ * 3. `runtimeConfig.{namespace}.{key}` (if a probe was performed)
86
+ * 4. `process.env[envKey]` for each env in `field.env`
87
+ *
88
+ * Pass an async `probe` to defer the runtime config lookup so it is only
89
+ * invoked when runtime resolution is needed (i.e. at least one env-backed
90
+ * field is not set by overrides). Adapters that have no probe target may pass
91
+ * `() => Promise.resolve(undefined)`.
92
+ */
93
+ async function resolveAdapterConfig(namespace, fields, overrides, probe) {
94
+ const runtimeConfig = shouldProbeRuntime(fields, overrides) ? await probe() : void 0;
95
+ const autotelNs = runtimeConfig?.autotel?.[namespace];
96
+ const rootNs = runtimeConfig?.[namespace];
97
+ const config = {};
98
+ for (const { key, env } of fields) config[key] = overrides?.[key] ?? autotelNs?.[key] ?? rootNs?.[key] ?? resolveEnv(env);
99
+ return config;
100
+ }
101
+ function getHeader(headers, name) {
102
+ if (!headers) return void 0;
103
+ if ("get" in headers && typeof headers.get === "function") return headers.get(name) ?? void 0;
104
+ const dictionary = headers;
105
+ const value = dictionary[name] ?? dictionary[name.toLowerCase()];
106
+ return typeof value === "string" ? value : void 0;
107
+ }
108
+
109
+ //#endregion
110
+ export { createAdapterToolkit, createRequestRunner, createUseLogger, getHeader, resolveAdapterConfig, shouldProbeRuntime };
3
111
  //# sourceMappingURL=core.js.map
package/dist/core.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"core.js"}
1
+ {"version":3,"file":"core.js","names":[],"sources":["../src/core.ts"],"sourcesContent":["import type { AsyncLocalStorage } from 'node:async_hooks';\nimport {\n createDrainPipeline,\n createStructuredError,\n getRequestLogger,\n parseError,\n trace,\n type ParsedError,\n type RequestLogger,\n type RequestLoggerOptions,\n type RequestLogSnapshot,\n type DrainPipelineOptions,\n type PipelineDrainFn,\n type StructuredError,\n type StructuredErrorInput,\n} from 'autotel';\n\nexport interface AdapterUseLoggerOptions<TContext> {\n adapterName: string;\n enrich?: (context: TContext) => Record<string, unknown> | undefined;\n}\n\nexport interface AdapterToolkit<TContext> {\n useLogger: (\n context?: TContext,\n options?: RequestLoggerOptions,\n ) => RequestLogger;\n parseError: (error: unknown) => ParsedError;\n createStructuredError: (input: StructuredErrorInput) => StructuredError;\n createDrainPipeline: <T = unknown>(\n options?: DrainPipelineOptions<T>,\n ) => (drain: (batch: T[]) => void | Promise<void>) => PipelineDrainFn<T>;\n}\n\nexport function createUseLogger<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n) {\n return function useLogger(\n context?: TContext,\n requestLoggerOptions?: RequestLoggerOptions,\n ): RequestLogger {\n let logger: RequestLogger;\n try {\n logger = getRequestLogger(undefined, requestLoggerOptions);\n } catch {\n throw new Error(\n `[autotel-adapters/${options.adapterName}] No active trace context. ` +\n `Wrap your handler with autotel trace instrumentation before calling useLogger().`,\n );\n }\n\n if (context && options.enrich) {\n const extra = options.enrich(context);\n if (extra && Object.keys(extra).length > 0) {\n logger.set(extra);\n }\n }\n\n return logger;\n };\n}\n\nexport interface RequestRunnerOptions {\n requestLoggerOptions?: RequestLoggerOptions;\n /** Emit one wide event automatically when the handler settles. Default `true`. */\n autoEmit?: boolean;\n /** Fields merged into the wide event at emit time (e.g. response status). */\n finalize?: () => Record<string, unknown> | undefined;\n}\n\n/**\n * Build a request runner bound to one framework's logger storage. The returned\n * function opens a span, creates a request logger, runs `handler` inside the\n * storage so `useLogger()` resolves it, records thrown errors, and emits one\n * wide event when the handler settles (unless `autoEmit` is `false`).\n */\nexport function createRequestRunner(storage: AsyncLocalStorage<RequestLogger>) {\n return function runRequest<T>(\n spanName: string,\n enrich: (log: RequestLogger) => void,\n handler: () => T | Promise<T>,\n options?: RequestRunnerOptions,\n ): Promise<T> {\n const wrapped = trace(\n { name: spanName },\n (ctx) => async (): Promise<T> => {\n const log = getRequestLogger(ctx, options?.requestLoggerOptions);\n enrich(log);\n try {\n return await storage.run(log, () => handler());\n } catch (error) {\n log.error(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n if (options?.autoEmit !== false) {\n log.emitNow(options?.finalize?.());\n }\n }\n },\n );\n return wrapped();\n };\n}\n\nexport function createAdapterToolkit<TContext = unknown>(\n options: AdapterUseLoggerOptions<TContext>,\n): AdapterToolkit<TContext> {\n return {\n useLogger: createUseLogger(options),\n parseError,\n createStructuredError,\n createDrainPipeline,\n };\n}\n\n/**\n * Description of a single adapter config field. `env` is the ordered list of\n * environment variables to fall back to.\n */\nexport interface ConfigField<T> {\n key: keyof T & string;\n env?: string[];\n}\n\nfunction resolveEnv(envKeys?: string[]): string | undefined {\n if (!envKeys) return undefined;\n for (const key of envKeys) {\n const value = process.env[key];\n if (value) return value;\n }\n return undefined;\n}\n\n/**\n * Returns true when at least one env-backed field is not provided via\n * `overrides`, meaning runtime config may still contribute and should be\n * probed to preserve precedence (`overrides > runtime > env`).\n *\n * @example\n * ```ts\n * const FIELDS: ConfigField<MyAdapterConfig>[] = [\n * { key: 'token', env: ['MY_ADAPTER_TOKEN'] },\n * { key: 'endpoint', env: ['MY_ADAPTER_URL'] },\n * ]\n *\n * if (shouldProbeRuntime(FIELDS, overrides)) {\n * runtimeConfig = await loadRuntimeConfig()\n * }\n * ```\n */\nexport function shouldProbeRuntime<T>(\n fields: ConfigField<T>[],\n overrides?: Partial<T>,\n): boolean {\n return fields.some(({ key, env }) => {\n if (!env || env.length === 0) return false;\n if (overrides?.[key] !== undefined) return false;\n return true;\n });\n}\n\n/**\n * Resolve adapter configuration with the standard priority chain:\n *\n * 1. `overrides` passed to the adapter factory\n * 2. `runtimeConfig.autotel.{namespace}.{key}` (if a probe was performed)\n * 3. `runtimeConfig.{namespace}.{key}` (if a probe was performed)\n * 4. `process.env[envKey]` for each env in `field.env`\n *\n * Pass an async `probe` to defer the runtime config lookup so it is only\n * invoked when runtime resolution is needed (i.e. at least one env-backed\n * field is not set by overrides). Adapters that have no probe target may pass\n * `() => Promise.resolve(undefined)`.\n */\nexport async function resolveAdapterConfig<T>(\n namespace: string,\n fields: ConfigField<T>[],\n overrides: Partial<T> | undefined,\n probe: () => Promise<Record<string, any> | undefined>,\n): Promise<Partial<T>> {\n const runtimeConfig = shouldProbeRuntime(fields, overrides)\n ? await probe()\n : undefined;\n const autotelNs = runtimeConfig?.autotel?.[namespace];\n const rootNs = runtimeConfig?.[namespace];\n\n const config: Record<string, unknown> = {};\n for (const { key, env } of fields) {\n config[key] =\n overrides?.[key] ??\n autotelNs?.[key] ??\n rootNs?.[key] ??\n resolveEnv(env);\n }\n\n return config as Partial<T>;\n}\n\nexport type HeadersLike =\n | { get(name: string): string | null }\n | Record<string, string | undefined>;\n\nexport function getHeader(\n headers: HeadersLike | undefined,\n name: string,\n): string | undefined {\n if (!headers) return undefined;\n if ('get' in headers && typeof headers.get === 'function') {\n return headers.get(name) ?? undefined;\n }\n const dictionary = headers as Record<string, string | undefined>;\n const value = dictionary[name] ?? dictionary[name.toLowerCase()];\n return typeof value === 'string' ? value : undefined;\n}\n\nexport type {\n RequestLogger,\n RequestLoggerOptions,\n RequestLogSnapshot,\n ParsedError,\n StructuredError,\n StructuredErrorInput,\n DrainPipelineOptions,\n PipelineDrainFn,\n};\n"],"mappings":";;;AAkCA,SAAgB,gBACd,SACA;CACA,OAAO,SAAS,UACd,SACA,sBACe;EACf,IAAI;EACJ,IAAI;GACF,SAAS,iBAAiB,QAAW,oBAAoB;EAC3D,QAAQ;GACN,MAAM,IAAI,MACR,qBAAqB,QAAQ,YAAY,4GAE3C;EACF;EAEA,IAAI,WAAW,QAAQ,QAAQ;GAC7B,MAAM,QAAQ,QAAQ,OAAO,OAAO;GACpC,IAAI,SAAS,OAAO,KAAK,KAAK,CAAC,CAAC,SAAS,GACvC,OAAO,IAAI,KAAK;EAEpB;EAEA,OAAO;CACT;AACF;;;;;;;AAgBA,SAAgB,oBAAoB,SAA2C;CAC7E,OAAO,SAAS,WACd,UACA,QACA,SACA,SACY;EAkBZ,OAjBgB,MACd,EAAE,MAAM,SAAS,IAChB,QAAQ,YAAwB;GAC/B,MAAM,MAAM,iBAAiB,KAAK,SAAS,oBAAoB;GAC/D,OAAO,GAAG;GACV,IAAI;IACF,OAAO,MAAM,QAAQ,IAAI,WAAW,QAAQ,CAAC;GAC/C,SAAS,OAAO;IACd,IAAI,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;IACnE,MAAM;GACR,UAAU;IACR,IAAI,SAAS,aAAa,OACxB,IAAI,QAAQ,SAAS,WAAW,CAAC;GAErC;EACF,CAEW,CAAC,CAAC;CACjB;AACF;AAEA,SAAgB,qBACd,SAC0B;CAC1B,OAAO;EACL,WAAW,gBAAgB,OAAO;EAClC;EACA;EACA;CACF;AACF;AAWA,SAAS,WAAW,SAAwC;CAC1D,IAAI,CAAC,SAAS,OAAO;CACrB,KAAK,MAAM,OAAO,SAAS;EACzB,MAAM,QAAQ,QAAQ,IAAI;EAC1B,IAAI,OAAO,OAAO;CACpB;AAEF;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,mBACd,QACA,WACS;CACT,OAAO,OAAO,MAAM,EAAE,KAAK,UAAU;EACnC,IAAI,CAAC,OAAO,IAAI,WAAW,GAAG,OAAO;EACrC,IAAI,YAAY,SAAS,QAAW,OAAO;EAC3C,OAAO;CACT,CAAC;AACH;;;;;;;;;;;;;;AAeA,eAAsB,qBACpB,WACA,QACA,WACA,OACqB;CACrB,MAAM,gBAAgB,mBAAmB,QAAQ,SAAS,IACtD,MAAM,MAAM,IACZ;CACJ,MAAM,YAAY,eAAe,UAAU;CAC3C,MAAM,SAAS,gBAAgB;CAE/B,MAAM,SAAkC,CAAC;CACzC,KAAK,MAAM,EAAE,KAAK,SAAS,QACzB,OAAO,OACL,YAAY,QACZ,YAAY,QACZ,SAAS,QACT,WAAW,GAAG;CAGlB,OAAO;AACT;AAMA,SAAgB,UACd,SACA,MACoB;CACpB,IAAI,CAAC,SAAS,OAAO;CACrB,IAAI,SAAS,WAAW,OAAO,QAAQ,QAAQ,YAC7C,OAAO,QAAQ,IAAI,IAAI,KAAK;CAE9B,MAAM,aAAa;CACnB,MAAM,QAAQ,WAAW,SAAS,WAAW,KAAK,YAAY;CAC9D,OAAO,OAAO,UAAU,WAAW,QAAQ;AAC7C"}