@adjedaini/clockwork-node 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +225 -0
  3. package/dist/globals.d.ts +27 -0
  4. package/dist/index.d.ts +61 -0
  5. package/dist/index.js +695 -0
  6. package/dist/public/assets/index-B2HEyS_P.css +1 -0
  7. package/dist/public/assets/index-B83PrqXa.css +1 -0
  8. package/dist/public/assets/index-CdsiP1dN.css +1 -0
  9. package/dist/public/assets/index-Df9idoqY.js +198 -0
  10. package/dist/public/assets/index-KmGT-iQM.js +198 -0
  11. package/dist/public/assets/index-znhjCgo1.js +198 -0
  12. package/dist/public/index.html +13 -0
  13. package/node_modules/@adjedaini/clockwork-core/dist/index.d.ts +53 -0
  14. package/node_modules/@adjedaini/clockwork-core/dist/index.js +192 -0
  15. package/node_modules/@adjedaini/clockwork-core/package.json +17 -0
  16. package/node_modules/@adjedaini/clockwork-core/src/index.ts +194 -0
  17. package/node_modules/@adjedaini/clockwork-core/src/ring-buffer.ts +47 -0
  18. package/node_modules/@adjedaini/clockwork-core/tsconfig.build.json +6 -0
  19. package/node_modules/@adjedaini/clockwork-core/tsconfig.json +10 -0
  20. package/node_modules/@adjedaini/clockwork-core/tsup.config.ts +13 -0
  21. package/node_modules/@adjedaini/clockwork-db-interceptor/dist/index.d.ts +33 -0
  22. package/node_modules/@adjedaini/clockwork-db-interceptor/dist/index.js +163 -0
  23. package/node_modules/@adjedaini/clockwork-db-interceptor/package.json +18 -0
  24. package/node_modules/@adjedaini/clockwork-db-interceptor/src/index.ts +28 -0
  25. package/node_modules/@adjedaini/clockwork-db-interceptor/src/mysql2.ts +84 -0
  26. package/node_modules/@adjedaini/clockwork-db-interceptor/src/pg.ts +56 -0
  27. package/node_modules/@adjedaini/clockwork-db-interceptor/tsconfig.build.json +6 -0
  28. package/node_modules/@adjedaini/clockwork-db-interceptor/tsconfig.json +10 -0
  29. package/node_modules/@adjedaini/clockwork-db-interceptor/tsup.config.ts +13 -0
  30. package/node_modules/@adjedaini/clockwork-log-interceptor/dist/index.d.ts +25 -0
  31. package/node_modules/@adjedaini/clockwork-log-interceptor/dist/index.js +153 -0
  32. package/node_modules/@adjedaini/clockwork-log-interceptor/package.json +16 -0
  33. package/node_modules/@adjedaini/clockwork-log-interceptor/src/index.ts +14 -0
  34. package/node_modules/@adjedaini/clockwork-log-interceptor/src/pino.ts +78 -0
  35. package/node_modules/@adjedaini/clockwork-log-interceptor/src/winston.ts +66 -0
  36. package/node_modules/@adjedaini/clockwork-log-interceptor/tsconfig.build.json +4 -0
  37. package/node_modules/@adjedaini/clockwork-log-interceptor/tsconfig.json +10 -0
  38. package/node_modules/@adjedaini/clockwork-log-interceptor/tsup.config.ts +13 -0
  39. package/node_modules/@adjedaini/clockwork-plugins/dist/index.d.ts +45 -0
  40. package/node_modules/@adjedaini/clockwork-plugins/dist/index.js +172 -0
  41. package/node_modules/@adjedaini/clockwork-plugins/package.json +19 -0
  42. package/node_modules/@adjedaini/clockwork-plugins/src/console.ts +70 -0
  43. package/node_modules/@adjedaini/clockwork-plugins/src/context.ts +30 -0
  44. package/node_modules/@adjedaini/clockwork-plugins/src/index.ts +50 -0
  45. package/node_modules/@adjedaini/clockwork-plugins/src/process-errors.ts +33 -0
  46. package/node_modules/@adjedaini/clockwork-plugins/tsconfig.build.json +1 -0
  47. package/node_modules/@adjedaini/clockwork-plugins/tsconfig.json +16 -0
  48. package/node_modules/@adjedaini/clockwork-plugins/tsup.config.ts +13 -0
  49. package/node_modules/@adjedaini/clockwork-shared/dist/index.d.ts +97 -0
  50. package/node_modules/@adjedaini/clockwork-shared/dist/index.js +18 -0
  51. package/node_modules/@adjedaini/clockwork-shared/package.json +14 -0
  52. package/node_modules/@adjedaini/clockwork-shared/src/index.ts +96 -0
  53. package/node_modules/@adjedaini/clockwork-shared/tsconfig.build.json +6 -0
  54. package/node_modules/@adjedaini/clockwork-shared/tsconfig.json +9 -0
  55. package/node_modules/@adjedaini/clockwork-shared/tsup.config.ts +13 -0
  56. package/node_modules/@adjedaini/clockwork-transport-http/dist/index.d.ts +75 -0
  57. package/node_modules/@adjedaini/clockwork-transport-http/dist/index.js +306 -0
  58. package/node_modules/@adjedaini/clockwork-transport-http/package.json +18 -0
  59. package/node_modules/@adjedaini/clockwork-transport-http/src/index.ts +277 -0
  60. package/node_modules/@adjedaini/clockwork-transport-http/src/sanitize.ts +92 -0
  61. package/node_modules/@adjedaini/clockwork-transport-http/src/types.ts +37 -0
  62. package/node_modules/@adjedaini/clockwork-transport-http/tsconfig.build.json +6 -0
  63. package/node_modules/@adjedaini/clockwork-transport-http/tsconfig.json +10 -0
  64. package/node_modules/@adjedaini/clockwork-transport-http/tsup.config.ts +13 -0
  65. package/package.json +69 -0
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Winston plugin: intercepts winston logger output and attaches to current request.
3
+ * Only applied if the 'winston' module is installed.
4
+ */
5
+
6
+ import type { ClockworkPlugin, IPluginContext } from '@adjedaini/clockwork-core';
7
+ import type { LogData } from '@adjedaini/clockwork-shared';
8
+
9
+ const LEVEL_MAP: Record<string, LogData['level']> = {
10
+ error: 'error',
11
+ warn: 'warning',
12
+ warning: 'warning',
13
+ info: 'info',
14
+ http: 'info',
15
+ verbose: 'debug',
16
+ debug: 'debug',
17
+ silly: 'debug',
18
+ };
19
+
20
+ function wrapWinston(ctx: IPluginContext): () => void {
21
+ let winstonId: string;
22
+ try {
23
+ winstonId = require.resolve('winston');
24
+ } catch {
25
+ return () => {};
26
+ }
27
+ const mod = require.cache[winstonId] as { exports: { createLogger?: (opts?: unknown) => WinstonLogger } } | undefined;
28
+ if (!mod?.exports?.createLogger) return () => {};
29
+
30
+ const winston = mod.exports;
31
+ const originalCreateLogger = winston.createLogger!.bind(winston);
32
+
33
+ winston.createLogger = function (opts?: unknown) {
34
+ const logger = originalCreateLogger(opts) as WinstonLogger;
35
+ const origLog = logger.log?.bind(logger);
36
+ if (typeof origLog !== 'function') return logger;
37
+
38
+ logger.log = function (this: WinstonLogger, levelOrMeta: string | object, msg?: string | (() => void), ...args: unknown[]) {
39
+ const requestId = ctx.getRequestId();
40
+ if (requestId) {
41
+ const level = typeof levelOrMeta === 'string' ? levelOrMeta : 'info';
42
+ const message = typeof msg === 'string' ? msg : (typeof levelOrMeta === 'object' && levelOrMeta !== null && 'message' in levelOrMeta)
43
+ ? String((levelOrMeta as { message?: unknown }).message)
44
+ : String(msg ?? levelOrMeta);
45
+ const levelMapped = LEVEL_MAP[level] ?? 'info';
46
+ ctx.core.captureNativeLog(requestId, levelMapped, message, undefined);
47
+ }
48
+ return origLog(levelOrMeta as string, msg as string, ...args);
49
+ };
50
+
51
+ return logger;
52
+ };
53
+
54
+ return function restore() {
55
+ winston.createLogger = originalCreateLogger;
56
+ };
57
+ }
58
+
59
+ interface WinstonLogger {
60
+ log?(level: string, msg: string, ...args: unknown[]): unknown;
61
+ }
62
+
63
+ export const winstonPlugin: ClockworkPlugin = {
64
+ name: 'winston',
65
+ install: wrapWinston,
66
+ };
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": { "composite": false }
4
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"],
9
+ "references": [{ "path": "../core" }, { "path": "../shared" }]
10
+ }
@@ -0,0 +1,13 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { defineConfig } from 'tsup';
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+
7
+ export default defineConfig({
8
+ entry: ['src/index.ts'],
9
+ format: ['cjs'],
10
+ dts: true,
11
+ outDir: 'dist',
12
+ tsconfig: path.join(__dirname, 'tsconfig.build.json'),
13
+ });
@@ -0,0 +1,45 @@
1
+ import { IPluginContext, ClockworkPlugin } from '@adjedaini/clockwork-core';
2
+ import { NextLike } from '@adjedaini/clockwork-transport-http';
3
+ export { defaultLogPlugins, pinoPlugin, winstonPlugin } from '@adjedaini/clockwork-log-interceptor';
4
+ export { defaultDbPlugins, mysql2Plugin, pgPlugin } from '@adjedaini/clockwork-db-interceptor';
5
+
6
+ /**
7
+ * Context plugin: provides AsyncLocalStorage and request-scoped getRequestId.
8
+ * Must be installed first so other plugins receive a working getRequestId.
9
+ */
10
+
11
+ /** Extended context that allows the context plugin to register getRequestId and runner. */
12
+ interface ContextPluginContext extends IPluginContext {
13
+ registerContext(getRequestId: () => string | undefined, contextRunner: (requestId: string, next: NextLike) => void): void;
14
+ }
15
+ declare const contextPlugin: ClockworkPlugin;
16
+
17
+ /**
18
+ * Console plugin: intercepts console.* (native log) and attaches to current request.
19
+ */
20
+
21
+ declare const consolePlugin: ClockworkPlugin;
22
+
23
+ /**
24
+ * Process errors plugin: captures uncaughtException and unhandledRejection.
25
+ */
26
+
27
+ declare const processErrorsPlugin: ClockworkPlugin;
28
+
29
+ /**
30
+ * @adjedaini/clockwork-plugins
31
+ * Built-in plugins (context, console, process-errors) and default plugin composition.
32
+ */
33
+
34
+ /** Context + console + processErrors. Context must be first. */
35
+ declare const defaultCorePlugins: ClockworkPlugin[];
36
+ /** Build default plugin list from options. */
37
+ declare function getDefaultPlugins(options: {
38
+ console?: boolean;
39
+ errors?: boolean;
40
+ logPlugins?: boolean;
41
+ db?: boolean;
42
+ dbPlugins?: ClockworkPlugin[];
43
+ }): ClockworkPlugin[];
44
+
45
+ export { type ContextPluginContext, consolePlugin, contextPlugin, defaultCorePlugins, getDefaultPlugins, processErrorsPlugin };
@@ -0,0 +1,172 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ consolePlugin: () => consolePlugin,
24
+ contextPlugin: () => contextPlugin,
25
+ defaultCorePlugins: () => defaultCorePlugins,
26
+ defaultDbPlugins: () => import_clockwork_db_interceptor2.defaultDbPlugins,
27
+ defaultLogPlugins: () => import_clockwork_log_interceptor2.defaultLogPlugins,
28
+ getDefaultPlugins: () => getDefaultPlugins,
29
+ mysql2Plugin: () => import_clockwork_db_interceptor2.mysql2Plugin,
30
+ pgPlugin: () => import_clockwork_db_interceptor2.pgPlugin,
31
+ pinoPlugin: () => import_clockwork_log_interceptor2.pinoPlugin,
32
+ processErrorsPlugin: () => processErrorsPlugin,
33
+ winstonPlugin: () => import_clockwork_log_interceptor2.winstonPlugin
34
+ });
35
+ module.exports = __toCommonJS(index_exports);
36
+
37
+ // src/context.ts
38
+ var import_node_async_hooks = require("async_hooks");
39
+ var contextPlugin = {
40
+ name: "context",
41
+ install(ctx) {
42
+ const storage = new import_node_async_hooks.AsyncLocalStorage();
43
+ const getRequestId = () => storage.getStore()?.requestId;
44
+ const contextRunner = (requestId, next) => {
45
+ storage.run({ requestId }, next);
46
+ };
47
+ ctx.registerContext(getRequestId, contextRunner);
48
+ return () => {
49
+ };
50
+ }
51
+ };
52
+
53
+ // src/console.ts
54
+ var CONSOLE_METHODS = ["log", "info", "warn", "error", "debug"];
55
+ function formatArgs(args) {
56
+ return args.map((a) => {
57
+ if (typeof a === "string") return a;
58
+ try {
59
+ return typeof a === "object" && a !== null ? JSON.stringify(a) : String(a);
60
+ } catch {
61
+ return String(a);
62
+ }
63
+ }).join(" ");
64
+ }
65
+ function patchConsole(core, getRequestId) {
66
+ const original = {};
67
+ for (const method of CONSOLE_METHODS) {
68
+ const orig = console[method];
69
+ if (typeof orig === "function") {
70
+ original[method] = orig.bind(console);
71
+ }
72
+ }
73
+ const levelMap = {
74
+ log: "info",
75
+ info: "info",
76
+ warn: "warning",
77
+ error: "error",
78
+ debug: "debug"
79
+ };
80
+ for (const method of CONSOLE_METHODS) {
81
+ const orig = original[method];
82
+ if (typeof orig !== "function") continue;
83
+ console[method] = function(...args) {
84
+ const requestId = getRequestId();
85
+ if (requestId) {
86
+ const message = formatArgs(args);
87
+ const level = levelMap[method];
88
+ core.captureNativeLog(requestId, level, message, void 0);
89
+ }
90
+ return orig.apply(console, args);
91
+ };
92
+ }
93
+ return function restore() {
94
+ for (const method of CONSOLE_METHODS) {
95
+ if (original[method]) {
96
+ console[method] = original[method];
97
+ }
98
+ }
99
+ };
100
+ }
101
+ var consolePlugin = {
102
+ name: "console",
103
+ install(ctx) {
104
+ return patchConsole(ctx.core, ctx.getRequestId);
105
+ }
106
+ };
107
+
108
+ // src/process-errors.ts
109
+ function patchProcessErrors(core, getRequestId) {
110
+ const onUncaught = (err) => {
111
+ const requestId = getRequestId();
112
+ core.captureError(err, requestId);
113
+ };
114
+ const onRejection = (reason) => {
115
+ const requestId = getRequestId();
116
+ const err = reason instanceof Error ? reason : new Error(String(reason));
117
+ core.captureError(err, requestId);
118
+ };
119
+ process.on("uncaughtException", onUncaught);
120
+ process.on("unhandledRejection", onRejection);
121
+ return function restore() {
122
+ process.off("uncaughtException", onUncaught);
123
+ process.off("unhandledRejection", onRejection);
124
+ };
125
+ }
126
+ var processErrorsPlugin = {
127
+ name: "processErrors",
128
+ install(ctx) {
129
+ return patchProcessErrors(ctx.core, ctx.getRequestId);
130
+ }
131
+ };
132
+
133
+ // src/index.ts
134
+ var import_clockwork_log_interceptor = require("@adjedaini/clockwork-log-interceptor");
135
+ var import_clockwork_db_interceptor = require("@adjedaini/clockwork-db-interceptor");
136
+ var import_clockwork_log_interceptor2 = require("@adjedaini/clockwork-log-interceptor");
137
+ var import_clockwork_db_interceptor2 = require("@adjedaini/clockwork-db-interceptor");
138
+ var defaultCorePlugins = [
139
+ contextPlugin,
140
+ consolePlugin,
141
+ processErrorsPlugin
142
+ ];
143
+ function getDefaultPlugins(options) {
144
+ const {
145
+ console: enableConsole = true,
146
+ errors: enableErrors = true,
147
+ logPlugins: enableLogPlugins = false,
148
+ db: enableDb = false,
149
+ dbPlugins = []
150
+ } = options;
151
+ const list = [contextPlugin];
152
+ if (enableConsole) list.push(consolePlugin);
153
+ if (enableErrors) list.push(processErrorsPlugin);
154
+ if (enableLogPlugins) list.push(...import_clockwork_log_interceptor.defaultLogPlugins);
155
+ if (enableDb && dbPlugins.length === 0) list.push(...import_clockwork_db_interceptor.defaultDbPlugins);
156
+ else if (dbPlugins.length > 0) list.push(...dbPlugins);
157
+ return list;
158
+ }
159
+ // Annotate the CommonJS export names for ESM import in node:
160
+ 0 && (module.exports = {
161
+ consolePlugin,
162
+ contextPlugin,
163
+ defaultCorePlugins,
164
+ defaultDbPlugins,
165
+ defaultLogPlugins,
166
+ getDefaultPlugins,
167
+ mysql2Plugin,
168
+ pgPlugin,
169
+ pinoPlugin,
170
+ processErrorsPlugin,
171
+ winstonPlugin
172
+ });
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "@adjedaini/clockwork-plugins",
3
+ "version": "0.0.1",
4
+ "private": true,
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": { "build": "tsup" },
8
+ "dependencies": {
9
+ "@adjedaini/clockwork-core": "*",
10
+ "@adjedaini/clockwork-shared": "*",
11
+ "@adjedaini/clockwork-transport-http": "*",
12
+ "@adjedaini/clockwork-db-interceptor": "*",
13
+ "@adjedaini/clockwork-log-interceptor": "*"
14
+ },
15
+ "devDependencies": {
16
+ "tsup": "^8.0.0",
17
+ "typescript": "^5.5.0"
18
+ }
19
+ }
@@ -0,0 +1,70 @@
1
+ /**
2
+ * Console plugin: intercepts console.* (native log) and attaches to current request.
3
+ */
4
+
5
+ import type { MonitorCore } from '@adjedaini/clockwork-core';
6
+ import type { ClockworkPlugin, IPluginContext } from '@adjedaini/clockwork-core';
7
+
8
+ const CONSOLE_METHODS = ['log', 'info', 'warn', 'error', 'debug'] as const;
9
+ type ConsoleMethod = (typeof CONSOLE_METHODS)[number];
10
+
11
+ function formatArgs(args: unknown[]): string {
12
+ return args
13
+ .map((a) => {
14
+ if (typeof a === 'string') return a;
15
+ try {
16
+ return typeof a === 'object' && a !== null ? JSON.stringify(a) : String(a);
17
+ } catch {
18
+ return String(a);
19
+ }
20
+ })
21
+ .join(' ');
22
+ }
23
+
24
+ function patchConsole(core: MonitorCore, getRequestId: () => string | undefined): () => void {
25
+ const original: Partial<Record<ConsoleMethod, (...args: unknown[]) => void>> = {};
26
+ for (const method of CONSOLE_METHODS) {
27
+ const orig = console[method];
28
+ if (typeof orig === 'function') {
29
+ original[method] = orig.bind(console);
30
+ }
31
+ }
32
+
33
+ const levelMap: Record<ConsoleMethod, 'debug' | 'info' | 'warning' | 'error'> = {
34
+ log: 'info',
35
+ info: 'info',
36
+ warn: 'warning',
37
+ error: 'error',
38
+ debug: 'debug',
39
+ };
40
+
41
+ for (const method of CONSOLE_METHODS) {
42
+ const orig = original[method];
43
+ if (typeof orig !== 'function') continue;
44
+
45
+ (console as unknown as Record<string, (...args: unknown[]) => void>)[method] = function (...args: unknown[]) {
46
+ const requestId = getRequestId();
47
+ if (requestId) {
48
+ const message = formatArgs(args);
49
+ const level = levelMap[method];
50
+ core.captureNativeLog(requestId, level, message, undefined);
51
+ }
52
+ return orig.apply(console, args);
53
+ };
54
+ }
55
+
56
+ return function restore() {
57
+ for (const method of CONSOLE_METHODS) {
58
+ if (original[method]) {
59
+ (console as unknown as Record<string, (...args: unknown[]) => void>)[method] = original[method]!;
60
+ }
61
+ }
62
+ };
63
+ }
64
+
65
+ export const consolePlugin: ClockworkPlugin = {
66
+ name: 'console',
67
+ install(ctx: IPluginContext): () => void {
68
+ return patchConsole(ctx.core, ctx.getRequestId);
69
+ },
70
+ };
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Context plugin: provides AsyncLocalStorage and request-scoped getRequestId.
3
+ * Must be installed first so other plugins receive a working getRequestId.
4
+ */
5
+
6
+ import { AsyncLocalStorage } from 'node:async_hooks';
7
+ import type { ClockworkPlugin, IPluginContext } from '@adjedaini/clockwork-core';
8
+ import type { ClockworkContext } from '@adjedaini/clockwork-shared';
9
+ import type { NextLike } from '@adjedaini/clockwork-transport-http';
10
+
11
+ /** Extended context that allows the context plugin to register getRequestId and runner. */
12
+ export interface ContextPluginContext extends IPluginContext {
13
+ registerContext(
14
+ getRequestId: () => string | undefined,
15
+ contextRunner: (requestId: string, next: NextLike) => void
16
+ ): void;
17
+ }
18
+
19
+ export const contextPlugin: ClockworkPlugin = {
20
+ name: 'context',
21
+ install(ctx: ContextPluginContext): () => void {
22
+ const storage = new AsyncLocalStorage<ClockworkContext>();
23
+ const getRequestId = (): string | undefined => storage.getStore()?.requestId;
24
+ const contextRunner = (requestId: string, next: NextLike): void => {
25
+ storage.run({ requestId }, next);
26
+ };
27
+ ctx.registerContext(getRequestId, contextRunner);
28
+ return () => {};
29
+ },
30
+ };
@@ -0,0 +1,50 @@
1
+ /**
2
+ * @adjedaini/clockwork-plugins
3
+ * Built-in plugins (context, console, process-errors) and default plugin composition.
4
+ */
5
+
6
+ import type { ClockworkPlugin } from '@adjedaini/clockwork-core';
7
+ import { contextPlugin } from './context';
8
+ import { consolePlugin } from './console';
9
+ import { processErrorsPlugin } from './process-errors';
10
+ import { defaultLogPlugins } from '@adjedaini/clockwork-log-interceptor';
11
+ import { defaultDbPlugins } from '@adjedaini/clockwork-db-interceptor';
12
+
13
+ export type { ContextPluginContext } from './context';
14
+
15
+ export { contextPlugin, consolePlugin, processErrorsPlugin };
16
+ export { pinoPlugin, winstonPlugin, defaultLogPlugins } from '@adjedaini/clockwork-log-interceptor';
17
+ export { pgPlugin, mysql2Plugin, defaultDbPlugins } from '@adjedaini/clockwork-db-interceptor';
18
+
19
+ /** Context + console + processErrors. Context must be first. */
20
+ export const defaultCorePlugins: ClockworkPlugin[] = [
21
+ contextPlugin,
22
+ consolePlugin,
23
+ processErrorsPlugin,
24
+ ];
25
+
26
+ /** Build default plugin list from options. */
27
+ export function getDefaultPlugins(options: {
28
+ console?: boolean;
29
+ errors?: boolean;
30
+ logPlugins?: boolean;
31
+ db?: boolean;
32
+ dbPlugins?: ClockworkPlugin[];
33
+ }): ClockworkPlugin[] {
34
+ const {
35
+ console: enableConsole = true,
36
+ errors: enableErrors = true,
37
+ logPlugins: enableLogPlugins = false,
38
+ db: enableDb = false,
39
+ dbPlugins = [],
40
+ } = options;
41
+
42
+ const list: ClockworkPlugin[] = [contextPlugin];
43
+ if (enableConsole) list.push(consolePlugin);
44
+ if (enableErrors) list.push(processErrorsPlugin);
45
+ if (enableLogPlugins) list.push(...defaultLogPlugins);
46
+ if (enableDb && dbPlugins.length === 0) list.push(...defaultDbPlugins);
47
+ else if (dbPlugins.length > 0) list.push(...dbPlugins);
48
+
49
+ return list;
50
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Process errors plugin: captures uncaughtException and unhandledRejection.
3
+ */
4
+
5
+ import type { ClockworkPlugin, IPluginContext } from '@adjedaini/clockwork-core';
6
+
7
+ function patchProcessErrors(core: IPluginContext['core'], getRequestId: () => string | undefined): () => void {
8
+ const onUncaught = (err: Error) => {
9
+ const requestId = getRequestId();
10
+ core.captureError(err, requestId);
11
+ };
12
+
13
+ const onRejection = (reason: unknown) => {
14
+ const requestId = getRequestId();
15
+ const err = reason instanceof Error ? reason : new Error(String(reason));
16
+ core.captureError(err, requestId);
17
+ };
18
+
19
+ process.on('uncaughtException', onUncaught);
20
+ process.on('unhandledRejection', onRejection);
21
+
22
+ return function restore() {
23
+ process.off('uncaughtException', onUncaught);
24
+ process.off('unhandledRejection', onRejection);
25
+ };
26
+ }
27
+
28
+ export const processErrorsPlugin: ClockworkPlugin = {
29
+ name: 'processErrors',
30
+ install(ctx: IPluginContext): () => void {
31
+ return patchProcessErrors(ctx.core, ctx.getRequestId);
32
+ },
33
+ };
@@ -0,0 +1 @@
1
+ {"extends": "./tsconfig.json", "compilerOptions": {"composite": false}}
@@ -0,0 +1,16 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "composite": true
7
+ },
8
+ "include": ["src/**/*"],
9
+ "references": [
10
+ { "path": "../core" },
11
+ { "path": "../shared" },
12
+ { "path": "../transport-http" },
13
+ { "path": "../db-interceptor" },
14
+ { "path": "../log-interceptor" }
15
+ ]
16
+ }
@@ -0,0 +1,13 @@
1
+ import path from 'path';
2
+ import { fileURLToPath } from 'url';
3
+ import { defineConfig } from 'tsup';
4
+
5
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
6
+
7
+ export default defineConfig({
8
+ entry: ['src/index.ts'],
9
+ format: ['cjs'],
10
+ dts: true,
11
+ outDir: 'dist',
12
+ tsconfig: path.join(__dirname, 'tsconfig.build.json'),
13
+ });
@@ -0,0 +1,97 @@
1
+ /** Shared types for @adjedaini/clockwork-node. Framework-agnostic. */
2
+ /** Per-request context (AsyncLocalStorage). Used to correlate logs/queries to the current request. */
3
+ interface ClockworkContext {
4
+ requestId: string;
5
+ }
6
+ interface LogData {
7
+ level: 'debug' | 'info' | 'warning' | 'error';
8
+ message: string;
9
+ context?: Record<string, unknown>;
10
+ time: number;
11
+ source?: 'native' | 'clockwork';
12
+ }
13
+ interface QueryData {
14
+ query: string;
15
+ bindings?: unknown[];
16
+ duration?: number;
17
+ connection?: string;
18
+ }
19
+ interface EventData {
20
+ name: string;
21
+ description?: string;
22
+ duration?: number;
23
+ start?: number;
24
+ end?: number;
25
+ data?: Record<string, unknown>;
26
+ color?: string;
27
+ }
28
+ interface RequestSnapshot {
29
+ id: string;
30
+ type: 'http';
31
+ method: string;
32
+ uri: string;
33
+ headers: Record<string, unknown>;
34
+ getData: Record<string, unknown>;
35
+ postData?: unknown;
36
+ responseData?: unknown;
37
+ cookies?: Record<string, unknown>;
38
+ responseStatus: number;
39
+ responseTime: number;
40
+ responseDuration: number;
41
+ memoryUsage: number;
42
+ time: number;
43
+ log: LogData[];
44
+ databaseQueries: QueryData[];
45
+ timelineData: EventData[];
46
+ controller?: string;
47
+ }
48
+ interface RequestMetadata {
49
+ id: string;
50
+ method: string;
51
+ uri: string;
52
+ controller?: string;
53
+ responseStatus: number;
54
+ responseDuration: number;
55
+ time: number;
56
+ }
57
+ interface MetricsSpan {
58
+ interval: number;
59
+ retention: number;
60
+ responseTime: number[];
61
+ rps: number[];
62
+ statusCodes?: Record<string, number>[];
63
+ }
64
+ interface Snapshot {
65
+ requests: RequestMetadata[];
66
+ metrics?: {
67
+ spans: MetricsSpan[];
68
+ timestamp: number;
69
+ os?: {
70
+ cpu: number;
71
+ memory: number;
72
+ heapUsed: number;
73
+ heapTotal: number;
74
+ rss: number;
75
+ };
76
+ process?: {
77
+ uptime: number;
78
+ eventLoopDelay?: number;
79
+ };
80
+ };
81
+ }
82
+ /** Storage backend for request snapshots. Implement for Redis, SQLite, file, etc. */
83
+ interface IRequestStorage {
84
+ push(id: string, request: RequestSnapshot): void;
85
+ get(id: string): RequestSnapshot | undefined;
86
+ getAll(limit: number): RequestSnapshot[];
87
+ getLatest(): RequestSnapshot | undefined;
88
+ }
89
+ interface CoreConfig {
90
+ maxRequests?: number;
91
+ maxBodyDepth?: number;
92
+ maxBodySize?: number;
93
+ /** Custom storage backend. Default: in-memory ring buffer. */
94
+ storage?: IRequestStorage;
95
+ }
96
+
97
+ export type { ClockworkContext, CoreConfig, EventData, IRequestStorage, LogData, MetricsSpan, QueryData, RequestMetadata, RequestSnapshot, Snapshot };
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/index.ts
17
+ var index_exports = {};
18
+ module.exports = __toCommonJS(index_exports);