@kamod-ch/otok-observability 1.0.0

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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +97 -0
  3. package/dist/error-reporting.d.ts +7 -0
  4. package/dist/error-reporting.d.ts.map +1 -0
  5. package/dist/error-reporting.js +22 -0
  6. package/dist/error-reporting.js.map +1 -0
  7. package/dist/index.d.ts +11 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +10 -0
  10. package/dist/index.js.map +1 -0
  11. package/dist/loader.d.ts +10 -0
  12. package/dist/loader.d.ts.map +1 -0
  13. package/dist/loader.js +51 -0
  14. package/dist/loader.js.map +1 -0
  15. package/dist/logger.d.ts +7 -0
  16. package/dist/logger.d.ts.map +1 -0
  17. package/dist/logger.js +37 -0
  18. package/dist/logger.js.map +1 -0
  19. package/dist/middleware.d.ts +7 -0
  20. package/dist/middleware.d.ts.map +1 -0
  21. package/dist/middleware.js +60 -0
  22. package/dist/middleware.js.map +1 -0
  23. package/dist/otel.d.ts +6 -0
  24. package/dist/otel.d.ts.map +1 -0
  25. package/dist/otel.js +12 -0
  26. package/dist/otel.js.map +1 -0
  27. package/dist/plugin.d.ts +16 -0
  28. package/dist/plugin.d.ts.map +1 -0
  29. package/dist/plugin.js +53 -0
  30. package/dist/plugin.js.map +1 -0
  31. package/dist/redaction.d.ts +8 -0
  32. package/dist/redaction.d.ts.map +1 -0
  33. package/dist/redaction.js +63 -0
  34. package/dist/redaction.js.map +1 -0
  35. package/dist/registry.d.ts +15 -0
  36. package/dist/registry.d.ts.map +1 -0
  37. package/dist/registry.js +20 -0
  38. package/dist/registry.js.map +1 -0
  39. package/dist/tracing.d.ts +10 -0
  40. package/dist/tracing.d.ts.map +1 -0
  41. package/dist/tracing.js +57 -0
  42. package/dist/tracing.js.map +1 -0
  43. package/dist/types.d.ts +71 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +2 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +71 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Kamod
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,97 @@
1
+ # @kamod-ch/otok-observability
2
+
3
+ Structured logging, request tracing, and error reporting for [Otok](https://github.com/kamod-ch/otok).
4
+
5
+ Privacy-safe by default: no form data, cookies, tokens, or secrets in logs.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @kamod-ch/otok-observability hono @kamod-ch/otok
11
+ ```
12
+
13
+ Optional OpenTelemetry bridge:
14
+
15
+ ```bash
16
+ pnpm add @opentelemetry/api
17
+ ```
18
+
19
+ ## Plugin setup
20
+
21
+ ```ts
22
+ import { defineConfig } from "@kamod-ch/otok";
23
+ import observability from "@kamod-ch/otok-observability";
24
+
25
+ export default defineConfig({
26
+ plugins: [
27
+ observability({
28
+ requestIdHeader: "x-request-id",
29
+ errorReporter: mySentryReporter,
30
+ }),
31
+ ],
32
+ });
33
+ ```
34
+
35
+ ## Middleware order
36
+
37
+ Register `observability()` immediately after `security()` so every downstream plugin and SSR handler runs inside a request span:
38
+
39
+ ```ts
40
+ plugins: [security(), observability(), i18n(), auth(), seo()];
41
+ ```
42
+
43
+ ## Traced loaders and actions
44
+
45
+ ```ts
46
+ import { defineLoader, defineAction } from "@kamod-ch/otok-observability/loader";
47
+
48
+ export const loader = defineLoader(async ({ hono }) => {
49
+ return { items: await loadItems() };
50
+ });
51
+
52
+ export const action = defineAction(async ({ hono, formData }) => {
53
+ await save(formData);
54
+ });
55
+ ```
56
+
57
+ Logs include `loaderMs`, `actionMs`, and `renderMs` without serializing `formData`.
58
+
59
+ ## OpenTelemetry
60
+
61
+ When `@opentelemetry/api` is installed, spans are exported through the global tracer provider:
62
+
63
+ ```ts
64
+ import { createOtelTracer } from "@kamod-ch/otok-observability/otel";
65
+
66
+ observability({
67
+ tracer: await createOtelTracer("my-app"),
68
+ });
69
+ ```
70
+
71
+ Works in Node and edge runtimes that support the OTEL API (exporters configured separately).
72
+
73
+ ## Error reporting
74
+
75
+ ```ts
76
+ const errorReporter: ErrorReporter = {
77
+ async capture({ error, requestId, route }) {
78
+ await sentry.captureException(error, { tags: { requestId, route } });
79
+ },
80
+ };
81
+ ```
82
+
83
+ ## Redaction
84
+
85
+ Built-in redaction covers `authorization`, `cookie`, `password`, `token`, `secret`, `_csrf`, and more. Extend with `redactKeys`.
86
+
87
+ ## API
88
+
89
+ | Export | Purpose |
90
+ | ------------------------------- | ---------------------- |
91
+ | `observability()` | Plugin factory |
92
+ | `defineLoader` / `defineAction` | Traced handlers |
93
+ | `createJsonLogger` | Structured JSON logger |
94
+ | `createRedactor` | Privacy filters |
95
+ | `createOtelTracer` | OTEL bridge |
96
+ | `createMemoryTracer` | In-process dev tracer |
97
+ | `recordRenderDuration` | SSR timing hook |
@@ -0,0 +1,7 @@
1
+ import type { ErrorReporter } from "./types.js";
2
+ /** Console error reporter for development. Never logs request bodies or cookies. */
3
+ export declare function createConsoleErrorReporter(logger: {
4
+ error(message: string, fields?: Record<string, unknown>): void;
5
+ }): ErrorReporter;
6
+ export declare function captureError(reporter: ErrorReporter | undefined, report: Parameters<ErrorReporter["capture"]>[0]): Promise<void>;
7
+ //# sourceMappingURL=error-reporting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-reporting.d.ts","sourceRoot":"","sources":["../src/error-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,oFAAoF;AACpF,wBAAgB,0BAA0B,CAAC,MAAM,EAAE;IACjD,KAAK,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAChE,GAAG,aAAa,CAehB;AAED,wBAAsB,YAAY,CAChC,QAAQ,EAAE,aAAa,GAAG,SAAS,EACnC,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,iBAIhD"}
@@ -0,0 +1,22 @@
1
+ /** Console error reporter for development. Never logs request bodies or cookies. */
2
+ export function createConsoleErrorReporter(logger) {
3
+ return {
4
+ capture(report) {
5
+ logger.error("unhandled error", {
6
+ requestId: report.requestId,
7
+ route: report.route,
8
+ method: report.method,
9
+ error: report.error instanceof Error
10
+ ? { name: report.error.name, message: report.error.message }
11
+ : { name: "Error", message: String(report.error) },
12
+ tags: report.tags,
13
+ });
14
+ },
15
+ };
16
+ }
17
+ export async function captureError(reporter, report) {
18
+ if (!reporter)
19
+ return;
20
+ await reporter.capture(report);
21
+ }
22
+ //# sourceMappingURL=error-reporting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-reporting.js","sourceRoot":"","sources":["../src/error-reporting.ts"],"names":[],"mappings":"AAEA,oFAAoF;AACpF,MAAM,UAAU,0BAA0B,CAAC,MAE1C;IACC,OAAO;QACL,OAAO,CAAC,MAAM;YACZ,MAAM,CAAC,KAAK,CAAC,iBAAiB,EAAE;gBAC9B,SAAS,EAAE,MAAM,CAAC,SAAS;gBAC3B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,MAAM,EAAE,MAAM,CAAC,MAAM;gBACrB,KAAK,EACH,MAAM,CAAC,KAAK,YAAY,KAAK;oBAC3B,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE;oBAC5D,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;gBACtD,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,QAAmC,EACnC,MAA+C;IAE/C,IAAI,CAAC,QAAQ;QAAE,OAAO;IACtB,MAAM,QAAQ,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export { createConsoleErrorReporter, captureError } from "./error-reporting.js";
2
+ export { createJsonLogger, resolveLogger } from "./logger.js";
3
+ export { defineLoader, defineAction, recordRenderDuration, recordPluginHookDuration } from "./loader.js";
4
+ export { configureObservabilityApp, createRequestIdMiddleware, createRequestLoggingMiddleware } from "./middleware.js";
5
+ export { createOtelTracer, resolveTracer } from "./otel.js";
6
+ export { default } from "./plugin.js";
7
+ export { createRedactor, type Redactor } from "./redaction.js";
8
+ export { getObservabilityRuntime, registerObservabilityRuntime, resetObservabilityRuntimeForTests, tryGetObservabilityRuntime, LOGGER_CONTEXT_KEY, REQUEST_ID_CONTEXT_KEY, TIMING_CONTEXT_KEY, type ObservabilityRuntime, } from "./registry.js";
9
+ export { createMemoryTracer, traceAsync, traceSync } from "./tracing.js";
10
+ export type { ErrorReport, ErrorReporter, HandlerTiming, LogLevel, LogRecord, Logger, ObservabilityPluginOptions, TraceSpan, Tracer, } from "./types.js";
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAC;AACvH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,iCAAiC,EACjC,0BAA0B,EAC1B,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,KAAK,oBAAoB,GAC1B,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACzE,YAAY,EACV,WAAW,EACX,aAAa,EACb,aAAa,EACb,QAAQ,EACR,SAAS,EACT,MAAM,EACN,0BAA0B,EAC1B,SAAS,EACT,MAAM,GACP,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,10 @@
1
+ export { createConsoleErrorReporter, captureError } from "./error-reporting.js";
2
+ export { createJsonLogger, resolveLogger } from "./logger.js";
3
+ export { defineLoader, defineAction, recordRenderDuration, recordPluginHookDuration } from "./loader.js";
4
+ export { configureObservabilityApp, createRequestIdMiddleware, createRequestLoggingMiddleware } from "./middleware.js";
5
+ export { createOtelTracer, resolveTracer } from "./otel.js";
6
+ export { default } from "./plugin.js";
7
+ export { createRedactor } from "./redaction.js";
8
+ export { getObservabilityRuntime, registerObservabilityRuntime, resetObservabilityRuntimeForTests, tryGetObservabilityRuntime, LOGGER_CONTEXT_KEY, REQUEST_ID_CONTEXT_KEY, TIMING_CONTEXT_KEY, } from "./registry.js";
9
+ export { createMemoryTracer, traceAsync, traceSync } from "./tracing.js";
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,8BAA8B,EAAE,MAAM,iBAAiB,CAAC;AACvH,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACtC,OAAO,EAAE,cAAc,EAAiB,MAAM,gBAAgB,CAAC;AAC/D,OAAO,EACL,uBAAuB,EACvB,4BAA4B,EAC5B,iCAAiC,EACjC,0BAA0B,EAC1B,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,GAEnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { LoaderResult, OtokActionContext, OtokContext, OtokLoader } from "@kamod-ch/otok/server";
2
+ /** Wrap a loader with tracing and duration metrics. */
3
+ export declare function defineLoader<Data extends LoaderResult>(handler: (ctx: OtokContext) => Data | Promise<Data>): OtokLoader<Data>;
4
+ /** Wrap an action with tracing and duration metrics. */
5
+ export declare function defineAction<Result>(handler: (ctx: OtokActionContext) => Result | Promise<Result>): (context: OtokActionContext) => Result | Promise<Result>;
6
+ /** Record SSR/render duration from the Otok handler. */
7
+ export declare function recordRenderDuration(hono: OtokContext["hono"], ms: number): void;
8
+ /** Record plugin hook duration. */
9
+ export declare function recordPluginHookDuration(hono: OtokContext["hono"], plugin: string, ms: number): void;
10
+ //# sourceMappingURL=loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAoBtG,uDAAuD;AACvD,wBAAgB,YAAY,CAAC,IAAI,SAAS,YAAY,EACpD,OAAO,EAAE,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAClD,UAAU,CAAC,IAAI,CAAC,CAYlB;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,MAAM,EACjC,OAAO,EAAE,CAAC,GAAG,EAAE,iBAAiB,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,GAC5D,CAAC,OAAO,EAAE,iBAAiB,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAY1D;AAED,wDAAwD;AACxD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEhF;AAED,mCAAmC;AACnC,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI,CAEpG"}
package/dist/loader.js ADDED
@@ -0,0 +1,51 @@
1
+ import { getObservabilityRuntime, TIMING_CONTEXT_KEY } from "./registry.js";
2
+ import { traceAsync } from "./tracing.js";
3
+ function recordTiming(hono, key, ms, plugin) {
4
+ const timing = hono.get(TIMING_CONTEXT_KEY) ?? {};
5
+ if (key === "pluginHooksMs" && plugin) {
6
+ timing.pluginHooksMs = { ...timing.pluginHooksMs, [plugin]: ms };
7
+ }
8
+ else if (key !== "pluginHooksMs") {
9
+ timing[key] = ms;
10
+ }
11
+ hono.set(TIMING_CONTEXT_KEY, timing);
12
+ }
13
+ /** Wrap a loader with tracing and duration metrics. */
14
+ export function defineLoader(handler) {
15
+ return async (context) => {
16
+ const runtime = getObservabilityRuntime();
17
+ if (!runtime.options.traceHandlers)
18
+ return handler(context);
19
+ const start = performance.now();
20
+ try {
21
+ return await traceAsync(runtime.tracer, `loader:${context.route}`, async () => handler(context));
22
+ }
23
+ finally {
24
+ recordTiming(context.hono, "loaderMs", Math.round(performance.now() - start));
25
+ }
26
+ };
27
+ }
28
+ /** Wrap an action with tracing and duration metrics. */
29
+ export function defineAction(handler) {
30
+ return async (context) => {
31
+ const runtime = getObservabilityRuntime();
32
+ if (!runtime.options.traceHandlers)
33
+ return handler(context);
34
+ const start = performance.now();
35
+ try {
36
+ return await traceAsync(runtime.tracer, `action:${context.route}`, async () => handler(context));
37
+ }
38
+ finally {
39
+ recordTiming(context.hono, "actionMs", Math.round(performance.now() - start));
40
+ }
41
+ };
42
+ }
43
+ /** Record SSR/render duration from the Otok handler. */
44
+ export function recordRenderDuration(hono, ms) {
45
+ recordTiming(hono, "renderMs", ms);
46
+ }
47
+ /** Record plugin hook duration. */
48
+ export function recordPluginHookDuration(hono, plugin, ms) {
49
+ recordTiming(hono, "pluginHooksMs", ms, plugin);
50
+ }
51
+ //# sourceMappingURL=loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,uBAAuB,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAC5E,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG1C,SAAS,YAAY,CACnB,IAAyB,EACzB,GAA0C,EAC1C,EAAU,EACV,MAAe;IAEf,MAAM,MAAM,GAAI,IAAI,CAAC,GAAG,CAAC,kBAA2B,CAA+B,IAAI,EAAE,CAAC;IAC1F,IAAI,GAAG,KAAK,eAAe,IAAI,MAAM,EAAE,CAAC;QACtC,MAAM,CAAC,aAAa,GAAG,EAAE,GAAG,MAAM,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,CAAC;IACnE,CAAC;SAAM,IAAI,GAAG,KAAK,eAAe,EAAE,CAAC;QACnC,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IACnB,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,kBAA2B,EAAE,MAAe,CAAC,CAAC;AACzD,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,YAAY,CAC1B,OAAmD;IAEnD,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACnG,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;QAChF,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,YAAY,CAC1B,OAA6D;IAE7D,OAAO,KAAK,EAAE,OAAO,EAAE,EAAE;QACvB,MAAM,OAAO,GAAG,uBAAuB,EAAE,CAAC;QAC1C,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,aAAa;YAAE,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC;QAE5D,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAChC,IAAI,CAAC;YACH,OAAO,MAAM,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,OAAO,CAAC,KAAK,EAAE,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC;QACnG,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;QAChF,CAAC;IACH,CAAC,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,oBAAoB,CAAC,IAAyB,EAAE,EAAU;IACxE,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;AACrC,CAAC;AAED,mCAAmC;AACnC,MAAM,UAAU,wBAAwB,CAAC,IAAyB,EAAE,MAAc,EAAE,EAAU;IAC5F,YAAY,CAAC,IAAI,EAAE,eAAe,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Logger, ObservabilityPluginOptions } from "./types.js";
2
+ export declare function createJsonLogger(options?: {
3
+ redactKeys?: string[];
4
+ base?: Record<string, unknown>;
5
+ }): Logger;
6
+ export declare function resolveLogger(options: ObservabilityPluginOptions): Logger;
7
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAuB,MAAM,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAM1F,wBAAgB,gBAAgB,CAAC,OAAO,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAO,GAAG,MAAM,CA4BhH;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,0BAA0B,GAAG,MAAM,CAEzE"}
package/dist/logger.js ADDED
@@ -0,0 +1,37 @@
1
+ import { createRedactor } from "./redaction.js";
2
+ function formatRecord(record) {
3
+ return JSON.stringify(record);
4
+ }
5
+ export function createJsonLogger(options = {}) {
6
+ const redactor = createRedactor(options.redactKeys);
7
+ const write = (level, message, fields = {}) => {
8
+ const record = {
9
+ level,
10
+ message,
11
+ timestamp: new Date().toISOString(),
12
+ ...options.base,
13
+ ...redactor.redactObject(fields),
14
+ };
15
+ const line = formatRecord(record);
16
+ if (level === "error")
17
+ console.error(line);
18
+ else if (level === "warn")
19
+ console.warn(line);
20
+ else
21
+ console.info(line);
22
+ };
23
+ const logger = {
24
+ debug: (message, fields) => write("debug", message, fields),
25
+ info: (message, fields) => write("info", message, fields),
26
+ warn: (message, fields) => write("warn", message, fields),
27
+ error: (message, fields) => write("error", message, fields),
28
+ child(fields) {
29
+ return createJsonLogger({ redactKeys: options.redactKeys, base: { ...options.base, ...fields } });
30
+ },
31
+ };
32
+ return logger;
33
+ }
34
+ export function resolveLogger(options) {
35
+ return options.logger ?? createJsonLogger({ redactKeys: options.redactKeys });
36
+ }
37
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAGhD,SAAS,YAAY,CAAC,MAAiB;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,UAAqE,EAAE;IACtG,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAEpD,MAAM,KAAK,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,SAAkC,EAAE,EAAE,EAAE;QACvF,MAAM,MAAM,GAAc;YACxB,KAAK;YACL,OAAO;YACP,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,GAAG,OAAO,CAAC,IAAI;YACf,GAAG,QAAQ,CAAC,YAAY,CAAC,MAAM,CAAC;SACjC,CAAC;QACF,MAAM,IAAI,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,OAAO;YAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;aACtC,IAAI,KAAK,KAAK,MAAM;YAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;;YACzC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,CAAC;IAEF,MAAM,MAAM,GAAW;QACrB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC;QAC3D,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;QACzD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC;QACzD,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC;QAC3D,KAAK,CAAC,MAAM;YACV,OAAO,gBAAgB,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,IAAI,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC,CAAC;QACpG,CAAC;KACF,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAmC;IAC/D,OAAO,OAAO,CAAC,MAAM,IAAI,gBAAgB,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;AAChF,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Hono } from "hono";
2
+ import { type OtokMiddleware } from "@kamod-ch/otok/server";
3
+ import { type ObservabilityRuntime } from "./registry.js";
4
+ export declare function createRequestIdMiddleware(runtime: ObservabilityRuntime): OtokMiddleware;
5
+ export declare function createRequestLoggingMiddleware(runtime: ObservabilityRuntime): OtokMiddleware;
6
+ export declare function configureObservabilityApp(app: Hono, runtime: ObservabilityRuntime): void;
7
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AACjC,OAAO,EAAoB,KAAK,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE9E,OAAO,EAIL,KAAK,oBAAoB,EAC1B,MAAM,eAAe,CAAC;AAWvB,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CASvF;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAgC5F;AAED,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAGxF"}
@@ -0,0 +1,60 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { defineMiddleware } from "@kamod-ch/otok/server";
3
+ import { captureError } from "./error-reporting.js";
4
+ import { LOGGER_CONTEXT_KEY, REQUEST_ID_CONTEXT_KEY, TIMING_CONTEXT_KEY, } from "./registry.js";
5
+ function resolveRequestId(c, runtime) {
6
+ const header = runtime.options.requestIdHeader;
7
+ const incoming = c.req.header(header);
8
+ if (incoming)
9
+ return incoming;
10
+ if (runtime.options.generateRequestId)
11
+ return randomUUID();
12
+ return "unknown";
13
+ }
14
+ export function createRequestIdMiddleware(runtime) {
15
+ return defineMiddleware(async (c, next) => {
16
+ const requestId = resolveRequestId(c, runtime);
17
+ c.set(REQUEST_ID_CONTEXT_KEY, requestId);
18
+ c.set(LOGGER_CONTEXT_KEY, runtime.logger.child({ requestId }));
19
+ c.set(TIMING_CONTEXT_KEY, {});
20
+ c.header(runtime.options.requestIdHeader, requestId);
21
+ await next();
22
+ });
23
+ }
24
+ export function createRequestLoggingMiddleware(runtime) {
25
+ return defineMiddleware(async (c, next) => {
26
+ const start = performance.now();
27
+ const url = new URL(c.req.url);
28
+ const logger = c.get(LOGGER_CONTEXT_KEY);
29
+ try {
30
+ await next();
31
+ }
32
+ catch (error) {
33
+ await captureError(runtime.errorReporter, {
34
+ error,
35
+ requestId: c.get(REQUEST_ID_CONTEXT_KEY),
36
+ route: url.pathname,
37
+ method: c.req.method,
38
+ });
39
+ throw error;
40
+ }
41
+ finally {
42
+ if (runtime.options.logRequests && logger) {
43
+ const durationMs = Math.round(performance.now() - start);
44
+ const timing = c.get(TIMING_CONTEXT_KEY) ?? {};
45
+ logger.info("request completed", {
46
+ method: c.req.method,
47
+ path: url.pathname,
48
+ status: c.res.status,
49
+ durationMs,
50
+ ...timing,
51
+ });
52
+ }
53
+ }
54
+ });
55
+ }
56
+ export function configureObservabilityApp(app, runtime) {
57
+ app.use("*", createRequestIdMiddleware(runtime));
58
+ app.use("*", createRequestLoggingMiddleware(runtime));
59
+ }
60
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../src/middleware.ts"],"names":[],"mappings":"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"}
package/dist/otel.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ import type { ObservabilityPluginOptions } from "./types.js";
2
+ export declare function resolveTracer(options: ObservabilityPluginOptions & {
3
+ serviceName?: string;
4
+ }): Promise<import("./types.js").Tracer>;
5
+ export { createOtelTracer } from "./tracing.js";
6
+ //# sourceMappingURL=otel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.d.ts","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAG7D,wBAAsB,aAAa,CACjC,OAAO,EAAE,0BAA0B,GAAG;IAAE,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,GAC7D,OAAO,CAAC,OAAO,YAAY,EAAE,MAAM,CAAC,CAMtC;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
package/dist/otel.js ADDED
@@ -0,0 +1,12 @@
1
+ import { createOtelTracer } from "./tracing.js";
2
+ export async function resolveTracer(options) {
3
+ if (options.tracer)
4
+ return options.tracer;
5
+ const otel = await createOtelTracer(options.serviceName ?? "otok");
6
+ if (otel)
7
+ return otel;
8
+ const { createMemoryTracer } = await import("./tracing.js");
9
+ return createMemoryTracer();
10
+ }
11
+ export { createOtelTracer } from "./tracing.js";
12
+ //# sourceMappingURL=otel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"otel.js","sourceRoot":"","sources":["../src/otel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAA8D;IAE9D,IAAI,OAAO,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM,CAAC;IAC1C,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,CAAC;IACnE,IAAI,IAAI;QAAE,OAAO,IAAI,CAAC;IACtB,MAAM,EAAE,kBAAkB,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IAC5D,OAAO,kBAAkB,EAAE,CAAC;AAC9B,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { configureObservabilityApp } from "./middleware.js";
2
+ import type { ObservabilityPluginOptions } from "./types.js";
3
+ /**
4
+ * Otok observability plugin — request IDs, structured logs, tracing, and error reporting.
5
+ *
6
+ * ```ts
7
+ * import observability from "@kamod-ch/otok-observability";
8
+ *
9
+ * export default defineConfig({
10
+ * plugins: [observability({ serviceName: "my-app" })],
11
+ * });
12
+ * ```
13
+ */
14
+ export default function observability(options?: ObservabilityPluginOptions): import("@kamod-ch/otok-config").OtokPlugin<unknown>;
15
+ export { configureObservabilityApp };
16
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAI5D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAe7D;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,OAAO,GAAE,0BAA+B,uDAuB7E;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAC"}
package/dist/plugin.js ADDED
@@ -0,0 +1,53 @@
1
+ import { definePlugin } from "@kamod-ch/otok";
2
+ import { createConsoleErrorReporter } from "./error-reporting.js";
3
+ import { configureObservabilityApp } from "./middleware.js";
4
+ import { resolveLogger } from "./logger.js";
5
+ import { registerObservabilityRuntime } from "./registry.js";
6
+ import { resolveTracer } from "./otel.js";
7
+ const observabilityPluginFactory = definePlugin({
8
+ name: "@kamod-ch/otok-observability",
9
+ version: "1.0.0",
10
+ schema: {
11
+ parse(input) {
12
+ if (input != null && typeof input !== "object") {
13
+ throw new Error("observability() options must be an object");
14
+ }
15
+ return (input ?? {});
16
+ },
17
+ },
18
+ });
19
+ /**
20
+ * Otok observability plugin — request IDs, structured logs, tracing, and error reporting.
21
+ *
22
+ * ```ts
23
+ * import observability from "@kamod-ch/otok-observability";
24
+ *
25
+ * export default defineConfig({
26
+ * plugins: [observability({ serviceName: "my-app" })],
27
+ * });
28
+ * ```
29
+ */
30
+ export default function observability(options = {}) {
31
+ const plugin = observabilityPluginFactory(options);
32
+ plugin.configureApp = async ({ app }) => {
33
+ const logger = resolveLogger(options);
34
+ const tracer = await resolveTracer({ ...options, serviceName: options.serviceName ?? "otok" });
35
+ const runtime = {
36
+ options: {
37
+ requestIdHeader: options.requestIdHeader ?? "x-request-id",
38
+ generateRequestId: options.generateRequestId ?? true,
39
+ logRequests: options.logRequests ?? true,
40
+ traceHandlers: options.traceHandlers ?? true,
41
+ ...options,
42
+ },
43
+ logger,
44
+ tracer,
45
+ errorReporter: options.errorReporter ?? createConsoleErrorReporter(logger),
46
+ };
47
+ registerObservabilityRuntime(runtime);
48
+ configureObservabilityApp(app, runtime);
49
+ };
50
+ return plugin;
51
+ }
52
+ export { configureObservabilityApp };
53
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAE,yBAAyB,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,4BAA4B,EAA6B,MAAM,eAAe,CAAC;AACxF,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,MAAM,0BAA0B,GAAG,YAAY,CAA6B;IAC1E,IAAI,EAAE,8BAA8B;IACpC,OAAO,EAAE,OAAO;IAChB,MAAM,EAAE;QACN,KAAK,CAAC,KAAK;YACT,IAAI,KAAK,IAAI,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;gBAC/C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;YAC/D,CAAC;YACD,OAAO,CAAC,KAAK,IAAI,EAAE,CAA+B,CAAC;QACrD,CAAC;KACF;CACF,CAAC,CAAC;AAEH;;;;;;;;;;GAUG;AACH,MAAM,CAAC,OAAO,UAAU,aAAa,CAAC,UAAsC,EAAE;IAC5E,MAAM,MAAM,GAAG,0BAA0B,CAAC,OAAO,CAAC,CAAC;IAEnD,MAAM,CAAC,YAAY,GAAG,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QACtC,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;QACtC,MAAM,MAAM,GAAG,MAAM,aAAa,CAAC,EAAE,GAAG,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,MAAM,EAAE,CAAC,CAAC;QAC/F,MAAM,OAAO,GAAyB;YACpC,OAAO,EAAE;gBACP,eAAe,EAAE,OAAO,CAAC,eAAe,IAAI,cAAc;gBAC1D,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,IAAI,IAAI;gBACpD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,IAAI;gBACxC,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,IAAI;gBAC5C,GAAG,OAAO;aACX;YACD,MAAM;YACN,MAAM;YACN,aAAa,EAAE,OAAO,CAAC,aAAa,IAAI,0BAA0B,CAAC,MAAM,CAAC;SAC3E,CAAC;QACF,4BAA4B,CAAC,OAAO,CAAC,CAAC;QACtC,yBAAyB,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,OAAO,EAAE,yBAAyB,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ export declare function createRedactor(extraKeys?: string[]): {
2
+ redactObject: (input: Record<string, unknown>) => Record<string, unknown>;
3
+ redactHeaders(headers: Headers): Record<string, string>;
4
+ redactFormData(formData: FormData): Record<string, string>;
5
+ redactValue: (key: string, value: unknown) => unknown;
6
+ };
7
+ export type Redactor = ReturnType<typeof createRedactor>;
8
+ //# sourceMappingURL=redaction.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.d.ts","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"AAiBA,wBAAgB,cAAc,CAAC,SAAS,GAAE,MAAM,EAAO;0BAcxB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;2BAgBrD,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;6BAO9B,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;uBAlClC,MAAM,SAAS,OAAO,KAAG,OAAO;EA2C3D;AAED,MAAM,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC"}
@@ -0,0 +1,63 @@
1
+ const DEFAULT_REDACT = [
2
+ "authorization",
3
+ "cookie",
4
+ "set-cookie",
5
+ "password",
6
+ "token",
7
+ "secret",
8
+ "api_key",
9
+ "api-key",
10
+ "_csrf",
11
+ "session",
12
+ "credit_card",
13
+ "creditcard",
14
+ ];
15
+ const REDACTED = "[REDACTED]";
16
+ export function createRedactor(extraKeys = []) {
17
+ const keys = new Set([...DEFAULT_REDACT, ...extraKeys].map((k) => k.toLowerCase()));
18
+ const redactValue = (key, value) => {
19
+ if (keys.has(key.toLowerCase()))
20
+ return REDACTED;
21
+ if (value && typeof value === "object" && !Array.isArray(value)) {
22
+ return redactObject(value);
23
+ }
24
+ if (Array.isArray(value)) {
25
+ return value.map((item, index) => redactValue(String(index), item));
26
+ }
27
+ return value;
28
+ };
29
+ const redactObject = (input) => {
30
+ const output = {};
31
+ for (const [key, value] of Object.entries(input)) {
32
+ if (keys.has(key.toLowerCase())) {
33
+ output[key] = REDACTED;
34
+ }
35
+ else if (value && typeof value === "object" && !Array.isArray(value)) {
36
+ output[key] = redactObject(value);
37
+ }
38
+ else {
39
+ output[key] = value;
40
+ }
41
+ }
42
+ return output;
43
+ };
44
+ return {
45
+ redactObject,
46
+ redactHeaders(headers) {
47
+ const result = {};
48
+ headers.forEach((value, key) => {
49
+ result[key] = keys.has(key.toLowerCase()) ? REDACTED : value;
50
+ });
51
+ return result;
52
+ },
53
+ redactFormData(formData) {
54
+ const result = {};
55
+ for (const [key, value] of formData.entries()) {
56
+ result[key] = keys.has(key.toLowerCase()) ? REDACTED : String(value);
57
+ }
58
+ return result;
59
+ },
60
+ redactValue,
61
+ };
62
+ }
63
+ //# sourceMappingURL=redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.js","sourceRoot":"","sources":["../src/redaction.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { ObservabilityPluginOptions } from "./types.js";
2
+ export interface ObservabilityRuntime {
3
+ options: Required<Pick<ObservabilityPluginOptions, "requestIdHeader" | "generateRequestId" | "logRequests" | "traceHandlers">> & ObservabilityPluginOptions;
4
+ logger: import("./types.js").Logger;
5
+ tracer: import("./types.js").Tracer;
6
+ errorReporter?: import("./types.js").ErrorReporter;
7
+ }
8
+ export declare function registerObservabilityRuntime(runtimeValue: ObservabilityRuntime): void;
9
+ export declare function getObservabilityRuntime(): ObservabilityRuntime;
10
+ export declare function tryGetObservabilityRuntime(): ObservabilityRuntime | null;
11
+ export declare function resetObservabilityRuntimeForTests(): void;
12
+ export declare const REQUEST_ID_CONTEXT_KEY = "requestId";
13
+ export declare const LOGGER_CONTEXT_KEY = "logger";
14
+ export declare const TIMING_CONTEXT_KEY = "handlerTiming";
15
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,YAAY,CAAC;AAI7D,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,QAAQ,CACf,IAAI,CAAC,0BAA0B,EAAE,iBAAiB,GAAG,mBAAmB,GAAG,aAAa,GAAG,eAAe,CAAC,CAC5G,GACC,0BAA0B,CAAC;IAC7B,MAAM,EAAE,OAAO,YAAY,EAAE,MAAM,CAAC;IACpC,MAAM,EAAE,OAAO,YAAY,EAAE,MAAM,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,YAAY,EAAE,aAAa,CAAC;CACpD;AAED,wBAAgB,4BAA4B,CAAC,YAAY,EAAE,oBAAoB,GAAG,IAAI,CAErF;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,CAK9D;AAED,wBAAgB,0BAA0B,IAAI,oBAAoB,GAAG,IAAI,CAExE;AAED,wBAAgB,iCAAiC,IAAI,IAAI,CAExD;AAED,eAAO,MAAM,sBAAsB,cAAc,CAAC;AAClD,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAC3C,eAAO,MAAM,kBAAkB,kBAAkB,CAAC"}
@@ -0,0 +1,20 @@
1
+ let runtime = null;
2
+ export function registerObservabilityRuntime(runtimeValue) {
3
+ runtime = runtimeValue;
4
+ }
5
+ export function getObservabilityRuntime() {
6
+ if (!runtime) {
7
+ throw new Error("otok-observability: plugin not registered. Add observability() to otok.config.ts plugins.");
8
+ }
9
+ return runtime;
10
+ }
11
+ export function tryGetObservabilityRuntime() {
12
+ return runtime;
13
+ }
14
+ export function resetObservabilityRuntimeForTests() {
15
+ runtime = null;
16
+ }
17
+ export const REQUEST_ID_CONTEXT_KEY = "requestId";
18
+ export const LOGGER_CONTEXT_KEY = "logger";
19
+ export const TIMING_CONTEXT_KEY = "handlerTiming";
20
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAEA,IAAI,OAAO,GAAgC,IAAI,CAAC;AAYhD,MAAM,UAAU,4BAA4B,CAAC,YAAkC;IAC7E,OAAO,GAAG,YAAY,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,0BAA0B;IACxC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,iCAAiC;IAC/C,OAAO,GAAG,IAAI,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,WAAW,CAAC;AAClD,MAAM,CAAC,MAAM,kBAAkB,GAAG,QAAQ,CAAC;AAC3C,MAAM,CAAC,MAAM,kBAAkB,GAAG,eAAe,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { TraceSpan, Tracer } from "./types.js";
2
+ /** Lightweight in-process tracer when OpenTelemetry is unavailable. */
3
+ export declare function createMemoryTracer(): Tracer & {
4
+ spans: TraceSpan[];
5
+ };
6
+ /** Bridge to OpenTelemetry when `@opentelemetry/api` is installed. */
7
+ export declare function createOtelTracer(serviceName: string): Promise<Tracer | null>;
8
+ export declare function traceAsync<T>(tracer: Tracer, name: string, fn: () => Promise<T>): Promise<T>;
9
+ export declare function traceSync<T>(tracer: Tracer, name: string, fn: () => T): T;
10
+ //# sourceMappingURL=tracing.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEpD,uEAAuE;AACvE,wBAAgB,kBAAkB,IAAI,MAAM,GAAG;IAAE,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,CAcpE;AAED,sEAAsE;AACtE,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAoBlF;AAED,wBAAsB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAOlG;AAED,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAOzE"}
@@ -0,0 +1,57 @@
1
+ /** Lightweight in-process tracer when OpenTelemetry is unavailable. */
2
+ export function createMemoryTracer() {
3
+ const spans = [];
4
+ return {
5
+ spans,
6
+ startSpan(name, attributes) {
7
+ const span = { name, start: performance.now(), attributes };
8
+ spans.push(span);
9
+ return span;
10
+ },
11
+ endSpan(span) {
12
+ span.end = performance.now();
13
+ },
14
+ };
15
+ }
16
+ /** Bridge to OpenTelemetry when `@opentelemetry/api` is installed. */
17
+ export async function createOtelTracer(serviceName) {
18
+ try {
19
+ const api = await import("@opentelemetry/api");
20
+ const tracer = api.trace.getTracer(serviceName);
21
+ return {
22
+ startSpan(name, attributes) {
23
+ const otelSpan = tracer.startSpan(name, { attributes });
24
+ const span = { name, start: performance.now(), attributes };
25
+ span.otelSpan = otelSpan;
26
+ return span;
27
+ },
28
+ endSpan(span) {
29
+ span.end = performance.now();
30
+ const otelSpan = span.otelSpan;
31
+ otelSpan?.end();
32
+ },
33
+ };
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ export async function traceAsync(tracer, name, fn) {
40
+ const span = tracer.startSpan(name);
41
+ try {
42
+ return await fn();
43
+ }
44
+ finally {
45
+ tracer.endSpan(span);
46
+ }
47
+ }
48
+ export function traceSync(tracer, name, fn) {
49
+ const span = tracer.startSpan(name);
50
+ try {
51
+ return fn();
52
+ }
53
+ finally {
54
+ tracer.endSpan(span);
55
+ }
56
+ }
57
+ //# sourceMappingURL=tracing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.js","sourceRoot":"","sources":["../src/tracing.ts"],"names":[],"mappings":"AAEA,uEAAuE;AACvE,MAAM,UAAU,kBAAkB;IAChC,MAAM,KAAK,GAAgB,EAAE,CAAC;IAE9B,OAAO;QACL,KAAK;QACL,SAAS,CAAC,IAAI,EAAE,UAAU;YACxB,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC;YACvE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,IAAI;YACV,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;QAC/B,CAAC;KACF,CAAC;AACJ,CAAC;AAED,sEAAsE;AACtE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,WAAmB;IACxD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;QAC/C,MAAM,MAAM,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QAChD,OAAO;YACL,SAAS,CAAC,IAAI,EAAE,UAAU;gBACxB,MAAM,QAAQ,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,CAAC,CAAC;gBACxD,MAAM,IAAI,GAAc,EAAE,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,GAAG,EAAE,EAAE,UAAU,EAAE,CAAC;gBACtE,IAAkD,CAAC,QAAQ,GAAG,QAAQ,CAAC;gBACxE,OAAO,IAAI,CAAC;YACd,CAAC;YACD,OAAO,CAAC,IAAI;gBACV,IAAI,CAAC,GAAG,GAAG,WAAW,CAAC,GAAG,EAAE,CAAC;gBAC7B,MAAM,QAAQ,GAAI,IAAmD,CAAC,QAAQ,CAAC;gBAC/E,QAAQ,EAAE,GAAG,EAAE,CAAC;YAClB,CAAC;SACF,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAI,MAAc,EAAE,IAAY,EAAE,EAAoB;IACpF,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAI,MAAc,EAAE,IAAY,EAAE,EAAW;IACpE,MAAM,IAAI,GAAG,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,OAAO,EAAE,EAAE,CAAC;IACd,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,71 @@
1
+ export type LogLevel = "debug" | "info" | "warn" | "error";
2
+ export interface LogRecord {
3
+ level: LogLevel;
4
+ message: string;
5
+ timestamp: string;
6
+ requestId?: string;
7
+ method?: string;
8
+ path?: string;
9
+ status?: number;
10
+ durationMs?: number;
11
+ span?: string;
12
+ error?: {
13
+ name: string;
14
+ message: string;
15
+ };
16
+ [key: string]: unknown;
17
+ }
18
+ export interface Logger {
19
+ debug(message: string, fields?: Record<string, unknown>): void;
20
+ info(message: string, fields?: Record<string, unknown>): void;
21
+ warn(message: string, fields?: Record<string, unknown>): void;
22
+ error(message: string, fields?: Record<string, unknown>): void;
23
+ child(fields: Record<string, unknown>): Logger;
24
+ }
25
+ export interface ErrorReport {
26
+ error: unknown;
27
+ requestId?: string;
28
+ route?: string;
29
+ method?: string;
30
+ tags?: Record<string, string>;
31
+ }
32
+ export interface ErrorReporter {
33
+ capture(report: ErrorReport): void | Promise<void>;
34
+ }
35
+ export interface TraceSpan {
36
+ name: string;
37
+ start: number;
38
+ end?: number;
39
+ attributes?: Record<string, string | number | boolean>;
40
+ }
41
+ export interface Tracer {
42
+ startSpan(name: string, attributes?: Record<string, string | number | boolean>): TraceSpan;
43
+ endSpan(span: TraceSpan): void;
44
+ }
45
+ export interface ObservabilityPluginOptions {
46
+ /** Service name for OpenTelemetry. */
47
+ serviceName?: string;
48
+ /** Header name for request ID. Default: `x-request-id`. */
49
+ requestIdHeader?: string;
50
+ /** Generate request IDs when missing. Default: true. */
51
+ generateRequestId?: boolean;
52
+ /** Structured logger. Default: JSON console logger. */
53
+ logger?: Logger;
54
+ /** Error reporting provider (Sentry, etc.). */
55
+ errorReporter?: ErrorReporter;
56
+ /** OpenTelemetry tracer bridge. */
57
+ tracer?: Tracer;
58
+ /** Additional header/cookie/query keys to redact from logs. */
59
+ redactKeys?: string[];
60
+ /** Log successful requests. Default: true. */
61
+ logRequests?: boolean;
62
+ /** Trace loaders and actions via defineLoader/defineAction wrappers. Default: true. */
63
+ traceHandlers?: boolean;
64
+ }
65
+ export interface HandlerTiming {
66
+ loaderMs?: number;
67
+ actionMs?: number;
68
+ renderMs?: number;
69
+ pluginHooksMs?: Record<string, number>;
70
+ }
71
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@kamod-ch/otok-observability",
3
+ "version": "1.0.0",
4
+ "description": "Structured logging, tracing, and error reporting for Otok apps.",
5
+ "homepage": "https://github.com/kamod-ch/otok/tree/main/packages/otok-observability#readme",
6
+ "bugs": {
7
+ "url": "https://github.com/kamod-ch/otok/issues"
8
+ },
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/kamod-ch/otok.git",
13
+ "directory": "packages/otok-observability"
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "type": "module",
20
+ "exports": {
21
+ ".": {
22
+ "types": "./dist/index.d.ts",
23
+ "default": "./dist/index.js"
24
+ },
25
+ "./middleware": {
26
+ "types": "./dist/middleware.d.ts",
27
+ "default": "./dist/middleware.js"
28
+ },
29
+ "./loader": {
30
+ "types": "./dist/loader.d.ts",
31
+ "default": "./dist/loader.js"
32
+ },
33
+ "./logger": {
34
+ "types": "./dist/logger.d.ts",
35
+ "default": "./dist/logger.js"
36
+ },
37
+ "./otel": {
38
+ "types": "./dist/otel.d.ts",
39
+ "default": "./dist/otel.js"
40
+ }
41
+ },
42
+ "publishConfig": {
43
+ "access": "public"
44
+ },
45
+ "devDependencies": {
46
+ "@kamod-ch/otok": "1.0.0",
47
+ "@kamod-ch/otok-test": "1.0.0",
48
+ "@opentelemetry/api": "^1.9.0",
49
+ "@types/node": "^24.12.2",
50
+ "hono": "^4.13.8",
51
+ "typescript": "~6.0.2",
52
+ "vitest": "^4.1.2"
53
+ },
54
+ "peerDependencies": {
55
+ "@kamod-ch/otok": ">=0.6.1",
56
+ "hono": ">=4"
57
+ },
58
+ "peerDependenciesMeta": {
59
+ "@opentelemetry/api": {
60
+ "optional": true
61
+ }
62
+ },
63
+ "engines": {
64
+ "node": ">=20"
65
+ },
66
+ "scripts": {
67
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
68
+ "typecheck": "tsc -p tsconfig.json --noEmit",
69
+ "test": "vitest run"
70
+ }
71
+ }