monten 0.1.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.
- package/dist/config/observability.config.d.ts +3 -0
- package/dist/config/observability.config.js +29 -0
- package/dist/context/requestContext.d.ts +5 -0
- package/dist/context/requestContext.js +26 -0
- package/dist/db/dbTimer.d.ts +1 -0
- package/dist/db/dbTimer.js +18 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +17 -0
- package/dist/logger/format.d.ts +2 -0
- package/dist/logger/format.js +6 -0
- package/dist/logger/logger.d.ts +8 -0
- package/dist/logger/logger.js +50 -0
- package/dist/metrics/metricsBuffer.d.ts +3 -0
- package/dist/metrics/metricsBuffer.js +15 -0
- package/dist/metrics/metricsFlusher.d.ts +6 -0
- package/dist/metrics/metricsFlusher.js +59 -0
- package/dist/metrics/metricsTypes.d.ts +19 -0
- package/dist/metrics/metricsTypes.js +2 -0
- package/dist/middleware/httpMiddleware.d.ts +1 -0
- package/dist/middleware/httpMiddleware.js +85 -0
- package/dist/types/index.d.ts +27 -0
- package/dist/types/index.js +2 -0
- package/dist/utils/time.d.ts +2 -0
- package/dist/utils/time.js +11 -0
- package/dist/utils/uuid.d.ts +1 -0
- package/dist/utils/uuid.js +19 -0
- package/package.json +27 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initObservabilityInternal = initObservabilityInternal;
|
|
4
|
+
exports.getObservabilityConfig = getObservabilityConfig;
|
|
5
|
+
const metricsFlusher_1 = require("../metrics/metricsFlusher");
|
|
6
|
+
let currentConfig = {
|
|
7
|
+
serviceName: 'unknown-service',
|
|
8
|
+
enableLogging: true,
|
|
9
|
+
enableMetrics: false,
|
|
10
|
+
metricsFlushIntervalMs: 10000,
|
|
11
|
+
};
|
|
12
|
+
function initObservabilityInternal(config) {
|
|
13
|
+
var _a;
|
|
14
|
+
currentConfig = {
|
|
15
|
+
serviceName: config.serviceName,
|
|
16
|
+
enableLogging: config.enableLogging,
|
|
17
|
+
enableMetrics: config.enableMetrics,
|
|
18
|
+
metricsFlushIntervalMs: (_a = config.metricsFlushIntervalMs) !== null && _a !== void 0 ? _a : currentConfig.metricsFlushIntervalMs,
|
|
19
|
+
};
|
|
20
|
+
if (currentConfig.enableMetrics) {
|
|
21
|
+
(0, metricsFlusher_1.startMetricsFlusher)();
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
(0, metricsFlusher_1.stopMetricsFlusher)();
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function getObservabilityConfig() {
|
|
28
|
+
return currentConfig;
|
|
29
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RequestContext } from '../types';
|
|
2
|
+
export declare function runWithRequestContext<T>(ctx: RequestContext, fn: () => T): T;
|
|
3
|
+
export declare function getRequestContext(): RequestContext | undefined;
|
|
4
|
+
export declare function addDbTimeMs(deltaMs: number): void;
|
|
5
|
+
export declare function setRequestError(error: unknown): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runWithRequestContext = runWithRequestContext;
|
|
4
|
+
exports.getRequestContext = getRequestContext;
|
|
5
|
+
exports.addDbTimeMs = addDbTimeMs;
|
|
6
|
+
exports.setRequestError = setRequestError;
|
|
7
|
+
const async_hooks_1 = require("async_hooks");
|
|
8
|
+
const storage = new async_hooks_1.AsyncLocalStorage();
|
|
9
|
+
function runWithRequestContext(ctx, fn) {
|
|
10
|
+
return storage.run(ctx, fn);
|
|
11
|
+
}
|
|
12
|
+
function getRequestContext() {
|
|
13
|
+
return storage.getStore();
|
|
14
|
+
}
|
|
15
|
+
function addDbTimeMs(deltaMs) {
|
|
16
|
+
const ctx = storage.getStore();
|
|
17
|
+
if (!ctx)
|
|
18
|
+
return;
|
|
19
|
+
ctx.dbTimeMs += deltaMs;
|
|
20
|
+
}
|
|
21
|
+
function setRequestError(error) {
|
|
22
|
+
const ctx = storage.getStore();
|
|
23
|
+
if (!ctx)
|
|
24
|
+
return;
|
|
25
|
+
ctx.error = error;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function withDbTiming<T>(fn: () => Promise<T>): Promise<T>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withDbTiming = withDbTiming;
|
|
4
|
+
const requestContext_1 = require("../context/requestContext");
|
|
5
|
+
const time_1 = require("../utils/time");
|
|
6
|
+
async function withDbTiming(fn) {
|
|
7
|
+
const start = (0, time_1.monotonicNowMs)();
|
|
8
|
+
try {
|
|
9
|
+
const result = await fn();
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
finally {
|
|
13
|
+
const durationMs = (0, time_1.monotonicNowMs)() - start;
|
|
14
|
+
if (durationMs >= 0) {
|
|
15
|
+
(0, requestContext_1.addDbTimeMs)(durationMs);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ObservabilityInitConfig } from './types';
|
|
2
|
+
export declare function initObservability(config: ObservabilityInitConfig): void;
|
|
3
|
+
export declare function httpObservabilityMiddleware(): (req: any, res: any, next: (err?: any) => void) => void;
|
|
4
|
+
export declare function withDbTiming<T>(fn: () => Promise<T>): Promise<T>;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.initObservability = initObservability;
|
|
4
|
+
exports.httpObservabilityMiddleware = httpObservabilityMiddleware;
|
|
5
|
+
exports.withDbTiming = withDbTiming;
|
|
6
|
+
const observability_config_1 = require("./config/observability.config");
|
|
7
|
+
const httpMiddleware_1 = require("./middleware/httpMiddleware");
|
|
8
|
+
const dbTimer_1 = require("./db/dbTimer");
|
|
9
|
+
function initObservability(config) {
|
|
10
|
+
(0, observability_config_1.initObservabilityInternal)(config);
|
|
11
|
+
}
|
|
12
|
+
function httpObservabilityMiddleware() {
|
|
13
|
+
return (0, httpMiddleware_1.httpObservabilityMiddleware)();
|
|
14
|
+
}
|
|
15
|
+
function withDbTiming(fn) {
|
|
16
|
+
return (0, dbTimer_1.withDbTiming)(fn);
|
|
17
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { LogLevel } from '../types';
|
|
2
|
+
export declare function log(level: LogLevel, message: string, fields?: Record<string, unknown>): void;
|
|
3
|
+
export declare const logger: {
|
|
4
|
+
debug(message: string, fields?: Record<string, unknown>): void;
|
|
5
|
+
info(message: string, fields?: Record<string, unknown>): void;
|
|
6
|
+
warn(message: string, fields?: Record<string, unknown>): void;
|
|
7
|
+
error(message: string, fields?: Record<string, unknown>): void;
|
|
8
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.logger = void 0;
|
|
4
|
+
exports.log = log;
|
|
5
|
+
const observability_config_1 = require("../config/observability.config");
|
|
6
|
+
const requestContext_1 = require("../context/requestContext");
|
|
7
|
+
const format_1 = require("./format");
|
|
8
|
+
const time_1 = require("../utils/time");
|
|
9
|
+
function write(line) {
|
|
10
|
+
// Structured logging only, no console.log
|
|
11
|
+
process.stdout.write(line + '\n');
|
|
12
|
+
}
|
|
13
|
+
function createLogEntry(level, message, fields) {
|
|
14
|
+
const cfg = (0, observability_config_1.getObservabilityConfig)();
|
|
15
|
+
const ctx = (0, requestContext_1.getRequestContext)();
|
|
16
|
+
const base = {
|
|
17
|
+
level,
|
|
18
|
+
message,
|
|
19
|
+
timestamp: (0, time_1.nowMs)(),
|
|
20
|
+
serviceName: cfg.serviceName,
|
|
21
|
+
};
|
|
22
|
+
if (ctx === null || ctx === void 0 ? void 0 : ctx.requestId) {
|
|
23
|
+
base.requestId = ctx.requestId;
|
|
24
|
+
}
|
|
25
|
+
if (fields && Object.keys(fields).length > 0) {
|
|
26
|
+
base.fields = fields;
|
|
27
|
+
}
|
|
28
|
+
return base;
|
|
29
|
+
}
|
|
30
|
+
function log(level, message, fields) {
|
|
31
|
+
const cfg = (0, observability_config_1.getObservabilityConfig)();
|
|
32
|
+
if (!cfg.enableLogging)
|
|
33
|
+
return;
|
|
34
|
+
const entry = createLogEntry(level, message, fields);
|
|
35
|
+
write((0, format_1.formatLog)(entry));
|
|
36
|
+
}
|
|
37
|
+
exports.logger = {
|
|
38
|
+
debug(message, fields) {
|
|
39
|
+
log('debug', message, fields);
|
|
40
|
+
},
|
|
41
|
+
info(message, fields) {
|
|
42
|
+
log('info', message, fields);
|
|
43
|
+
},
|
|
44
|
+
warn(message, fields) {
|
|
45
|
+
log('warn', message, fields);
|
|
46
|
+
},
|
|
47
|
+
error(message, fields) {
|
|
48
|
+
log('error', message, fields);
|
|
49
|
+
},
|
|
50
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.pushMetric = pushMetric;
|
|
4
|
+
exports.drainMetrics = drainMetrics;
|
|
5
|
+
const buffer = [];
|
|
6
|
+
function pushMetric(metric) {
|
|
7
|
+
buffer.push(metric);
|
|
8
|
+
}
|
|
9
|
+
function drainMetrics() {
|
|
10
|
+
if (buffer.length === 0)
|
|
11
|
+
return [];
|
|
12
|
+
const copy = buffer.slice();
|
|
13
|
+
buffer.length = 0;
|
|
14
|
+
return copy;
|
|
15
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MetricsSink } from './metricsTypes';
|
|
2
|
+
export declare function setMetricsSink(sink: MetricsSink | undefined): void;
|
|
3
|
+
declare function flushOnce(): Promise<void>;
|
|
4
|
+
export declare function startMetricsFlusher(): void;
|
|
5
|
+
export declare function stopMetricsFlusher(): void;
|
|
6
|
+
export { flushOnce as flushMetricsOnce };
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setMetricsSink = setMetricsSink;
|
|
4
|
+
exports.startMetricsFlusher = startMetricsFlusher;
|
|
5
|
+
exports.stopMetricsFlusher = stopMetricsFlusher;
|
|
6
|
+
exports.flushMetricsOnce = flushOnce;
|
|
7
|
+
const observability_config_1 = require("../config/observability.config");
|
|
8
|
+
const logger_1 = require("../logger/logger");
|
|
9
|
+
const time_1 = require("../utils/time");
|
|
10
|
+
const metricsBuffer_1 = require("./metricsBuffer");
|
|
11
|
+
let flushTimer = null;
|
|
12
|
+
let customSink;
|
|
13
|
+
function defaultSink(batch) {
|
|
14
|
+
if (batch.length === 0)
|
|
15
|
+
return;
|
|
16
|
+
logger_1.logger.info('metrics_flush', {
|
|
17
|
+
count: batch.length,
|
|
18
|
+
flushedAt: (0, time_1.nowMs)(),
|
|
19
|
+
metrics: batch,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function setMetricsSink(sink) {
|
|
23
|
+
customSink = sink;
|
|
24
|
+
}
|
|
25
|
+
async function flushOnce() {
|
|
26
|
+
const cfg = (0, observability_config_1.getObservabilityConfig)();
|
|
27
|
+
if (!cfg.enableMetrics)
|
|
28
|
+
return;
|
|
29
|
+
const batch = (0, metricsBuffer_1.drainMetrics)();
|
|
30
|
+
if (batch.length === 0)
|
|
31
|
+
return;
|
|
32
|
+
const sink = customSink !== null && customSink !== void 0 ? customSink : defaultSink;
|
|
33
|
+
try {
|
|
34
|
+
await sink(batch);
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
logger_1.logger.error('metrics_flush_failed', {
|
|
38
|
+
error: err instanceof Error ? err.message : String(err),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function startMetricsFlusher() {
|
|
43
|
+
const cfg = (0, observability_config_1.getObservabilityConfig)();
|
|
44
|
+
if (flushTimer) {
|
|
45
|
+
clearInterval(flushTimer);
|
|
46
|
+
flushTimer = null;
|
|
47
|
+
}
|
|
48
|
+
if (!cfg.enableMetrics)
|
|
49
|
+
return;
|
|
50
|
+
flushTimer = setInterval(() => {
|
|
51
|
+
void flushOnce();
|
|
52
|
+
}, cfg.metricsFlushIntervalMs);
|
|
53
|
+
}
|
|
54
|
+
function stopMetricsFlusher() {
|
|
55
|
+
if (flushTimer) {
|
|
56
|
+
clearInterval(flushTimer);
|
|
57
|
+
flushTimer = null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export type MetricType = 'http_request';
|
|
2
|
+
export interface MetricBase {
|
|
3
|
+
type: MetricType;
|
|
4
|
+
timestamp: number;
|
|
5
|
+
serviceName: string;
|
|
6
|
+
}
|
|
7
|
+
export interface HttpRequestMetric extends MetricBase {
|
|
8
|
+
type: 'http_request';
|
|
9
|
+
method: string;
|
|
10
|
+
path: string;
|
|
11
|
+
statusCode: number;
|
|
12
|
+
latencyMs: number;
|
|
13
|
+
dbTimeMs: number;
|
|
14
|
+
success: boolean;
|
|
15
|
+
errorName?: string;
|
|
16
|
+
errorMessage?: string;
|
|
17
|
+
}
|
|
18
|
+
export type MetricRecord = HttpRequestMetric;
|
|
19
|
+
export type MetricsSink = (batch: MetricRecord[]) => void | Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function httpObservabilityMiddleware(): (req: any, res: any, next: (err?: any) => void) => void;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.httpObservabilityMiddleware = httpObservabilityMiddleware;
|
|
4
|
+
const observability_config_1 = require("../config/observability.config");
|
|
5
|
+
const requestContext_1 = require("../context/requestContext");
|
|
6
|
+
const logger_1 = require("../logger/logger");
|
|
7
|
+
const metricsBuffer_1 = require("../metrics/metricsBuffer");
|
|
8
|
+
const time_1 = require("../utils/time");
|
|
9
|
+
const uuid_1 = require("../utils/uuid");
|
|
10
|
+
function httpObservabilityMiddleware() {
|
|
11
|
+
return function httpMiddleware(req, res, next) {
|
|
12
|
+
const cfg = (0, observability_config_1.getObservabilityConfig)();
|
|
13
|
+
const requestId = (0, uuid_1.generateRequestId)();
|
|
14
|
+
const startTimeMs = (0, time_1.monotonicNowMs)();
|
|
15
|
+
const ctx = {
|
|
16
|
+
requestId,
|
|
17
|
+
startTimeMs,
|
|
18
|
+
dbTimeMs: 0,
|
|
19
|
+
error: undefined,
|
|
20
|
+
};
|
|
21
|
+
const wrappedNext = (err) => {
|
|
22
|
+
if (err) {
|
|
23
|
+
(0, requestContext_1.setRequestError)(err);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
next(err);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
(0, requestContext_1.setRequestError)(error);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
(0, requestContext_1.runWithRequestContext)(ctx, () => {
|
|
34
|
+
const method = req.method || 'UNKNOWN';
|
|
35
|
+
const path = req.path || req.url || 'UNKNOWN';
|
|
36
|
+
const onFinish = () => {
|
|
37
|
+
var _a;
|
|
38
|
+
res.removeListener('finish', onFinish);
|
|
39
|
+
res.removeListener('close', onFinish);
|
|
40
|
+
const endTimeMs = (0, time_1.monotonicNowMs)();
|
|
41
|
+
const latencyMs = endTimeMs - startTimeMs;
|
|
42
|
+
const statusCode = res.statusCode || 0;
|
|
43
|
+
const currentCtx = (_a = (0, requestContext_1.getRequestContext)()) !== null && _a !== void 0 ? _a : ctx;
|
|
44
|
+
const dbTimeMs = currentCtx.dbTimeMs;
|
|
45
|
+
const error = currentCtx.error;
|
|
46
|
+
const success = statusCode < 500;
|
|
47
|
+
if (cfg.enableLogging) {
|
|
48
|
+
const logFields = {
|
|
49
|
+
method,
|
|
50
|
+
path,
|
|
51
|
+
statusCode,
|
|
52
|
+
latencyMs,
|
|
53
|
+
dbTimeMs,
|
|
54
|
+
};
|
|
55
|
+
if (error) {
|
|
56
|
+
logFields.errorName = error.name;
|
|
57
|
+
logFields.errorMessage = error.message;
|
|
58
|
+
logFields.errorStack = error.stack;
|
|
59
|
+
}
|
|
60
|
+
const level = success && !error ? 'info' : 'error';
|
|
61
|
+
logger_1.logger[level]('http_request', logFields);
|
|
62
|
+
}
|
|
63
|
+
if (cfg.enableMetrics) {
|
|
64
|
+
const metric = {
|
|
65
|
+
type: 'http_request',
|
|
66
|
+
timestamp: (0, time_1.nowMs)(),
|
|
67
|
+
serviceName: cfg.serviceName,
|
|
68
|
+
method,
|
|
69
|
+
path,
|
|
70
|
+
statusCode,
|
|
71
|
+
latencyMs,
|
|
72
|
+
dbTimeMs,
|
|
73
|
+
success,
|
|
74
|
+
errorName: error === null || error === void 0 ? void 0 : error.name,
|
|
75
|
+
errorMessage: error === null || error === void 0 ? void 0 : error.message,
|
|
76
|
+
};
|
|
77
|
+
(0, metricsBuffer_1.pushMetric)(metric);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
res.on('finish', onFinish);
|
|
81
|
+
res.on('close', onFinish);
|
|
82
|
+
wrappedNext();
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface ObservabilityInitConfig {
|
|
2
|
+
serviceName: string;
|
|
3
|
+
enableLogging: boolean;
|
|
4
|
+
enableMetrics: boolean;
|
|
5
|
+
metricsFlushIntervalMs?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface ObservabilityConfig {
|
|
8
|
+
serviceName: string;
|
|
9
|
+
enableLogging: boolean;
|
|
10
|
+
enableMetrics: boolean;
|
|
11
|
+
metricsFlushIntervalMs: number;
|
|
12
|
+
}
|
|
13
|
+
export interface RequestContext {
|
|
14
|
+
requestId: string;
|
|
15
|
+
startTimeMs: number;
|
|
16
|
+
dbTimeMs: number;
|
|
17
|
+
error?: unknown;
|
|
18
|
+
}
|
|
19
|
+
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
20
|
+
export interface LogEntry {
|
|
21
|
+
level: LogLevel;
|
|
22
|
+
message: string;
|
|
23
|
+
timestamp: number;
|
|
24
|
+
serviceName: string;
|
|
25
|
+
requestId?: string;
|
|
26
|
+
fields?: Record<string, unknown>;
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.nowMs = nowMs;
|
|
4
|
+
exports.monotonicNowMs = monotonicNowMs;
|
|
5
|
+
function nowMs() {
|
|
6
|
+
return Date.now();
|
|
7
|
+
}
|
|
8
|
+
function monotonicNowMs() {
|
|
9
|
+
// Uses high-resolution monotonic clock for durations
|
|
10
|
+
return Number(process.hrtime.bigint() / BigInt(1000000));
|
|
11
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function generateRequestId(): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRequestId = generateRequestId;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
5
|
+
function generateRequestId() {
|
|
6
|
+
var _a;
|
|
7
|
+
if (typeof ((_a = global.crypto) === null || _a === void 0 ? void 0 : _a.randomUUID) === 'function') {
|
|
8
|
+
return global.crypto.randomUUID();
|
|
9
|
+
}
|
|
10
|
+
const buf = (0, crypto_1.randomBytes)(16);
|
|
11
|
+
const hex = buf.toString('hex');
|
|
12
|
+
return [
|
|
13
|
+
hex.substring(0, 8),
|
|
14
|
+
hex.substring(8, 12),
|
|
15
|
+
hex.substring(12, 16),
|
|
16
|
+
hex.substring(16, 20),
|
|
17
|
+
hex.substring(20),
|
|
18
|
+
].join('-');
|
|
19
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "monten",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Lightweight observability utilities for Express-based Node.js backends (experimental).",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"private": false,
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc -p tsconfig.json"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"observability",
|
|
16
|
+
"logging",
|
|
17
|
+
"metrics",
|
|
18
|
+
"express",
|
|
19
|
+
"nodejs"
|
|
20
|
+
],
|
|
21
|
+
"author": "",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"devDependencies": {
|
|
24
|
+
"@types/node": "^22.0.0",
|
|
25
|
+
"typescript": "^5.6.0"
|
|
26
|
+
}
|
|
27
|
+
}
|