@futurewindai/wotchi 0.1.0-beta.2 → 0.1.0-beta.6
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/README.md +178 -47
- package/SECURITY.md +2 -2
- package/dist/cjs/core/admission.js +22 -0
- package/dist/cjs/core/client.js +416 -21
- package/dist/cjs/core/config.js +193 -18
- package/dist/cjs/core/diagnostics.js +16 -1
- package/dist/cjs/core/group-store.js +22 -9
- package/dist/cjs/core/incident-builder.js +18 -0
- package/dist/cjs/core/incident-policy.js +2 -7
- package/dist/cjs/core/limits.js +17 -0
- package/dist/cjs/core/normalize.js +16 -6
- package/dist/cjs/core/notification-queue.js +92 -6
- package/dist/cjs/core/prometheus.js +129 -0
- package/dist/cjs/core/redact.js +57 -8
- package/dist/cjs/core/runtime-monitor.js +109 -0
- package/dist/cjs/index.js +8 -1
- package/dist/cjs/integrations/express/error-handler.js +21 -4
- package/dist/cjs/integrations/express/index.js +2 -1
- package/dist/cjs/integrations/express/status-observer.js +6 -0
- package/dist/cjs/integrations/nest/capture.js +21 -0
- package/dist/cjs/integrations/nest/exception-filter.js +64 -8
- package/dist/cjs/integrations/nest/filter-wrapper.js +17 -0
- package/dist/cjs/integrations/nest/index.js +7 -1
- package/dist/cjs/integrations/nest/module.js +44 -0
- package/dist/cjs/integrations/nest/register.js +15 -1
- package/dist/cjs/integrations/request-context.js +83 -1
- package/dist/cjs/notifiers/alert-payload.js +20 -0
- package/dist/cjs/notifiers/console.js +85 -15
- package/dist/cjs/notifiers/telegram-format.js +75 -5
- package/dist/cjs/notifiers/webhook-http.js +394 -0
- package/dist/cjs/notifiers/webhook.js +28 -0
- package/dist/esm/core/admission.js +19 -0
- package/dist/esm/core/client.js +416 -21
- package/dist/esm/core/config.js +193 -18
- package/dist/esm/core/diagnostics.js +16 -1
- package/dist/esm/core/group-store.js +22 -9
- package/dist/esm/core/incident-builder.js +18 -0
- package/dist/esm/core/incident-policy.js +2 -7
- package/dist/esm/core/limits.js +14 -0
- package/dist/esm/core/normalize.js +16 -6
- package/dist/esm/core/notification-queue.js +92 -6
- package/dist/esm/core/prometheus.js +125 -0
- package/dist/esm/core/redact.js +57 -8
- package/dist/esm/core/runtime-monitor.js +106 -0
- package/dist/esm/index.js +4 -1
- package/dist/esm/integrations/express/error-handler.js +21 -4
- package/dist/esm/integrations/express/index.js +1 -1
- package/dist/esm/integrations/express/status-observer.js +6 -0
- package/dist/esm/integrations/nest/capture.js +17 -0
- package/dist/esm/integrations/nest/exception-filter.js +65 -9
- package/dist/esm/integrations/nest/filter-wrapper.js +14 -0
- package/dist/esm/integrations/nest/index.js +3 -1
- package/dist/esm/integrations/nest/module.js +41 -0
- package/dist/esm/integrations/nest/register.js +15 -1
- package/dist/esm/integrations/request-context.js +83 -1
- package/dist/esm/notifiers/alert-payload.js +16 -0
- package/dist/esm/notifiers/console.js +85 -15
- package/dist/esm/notifiers/telegram-format.js +75 -5
- package/dist/esm/notifiers/webhook-http.js +387 -0
- package/dist/esm/notifiers/webhook.js +24 -0
- package/dist/types/core/admission.d.ts +10 -0
- package/dist/types/core/config.d.ts +17 -1
- package/dist/types/core/diagnostics.d.ts +7 -1
- package/dist/types/core/incident-policy.d.ts +1 -1
- package/dist/types/core/limits.d.ts +14 -0
- package/dist/types/core/notification-queue.d.ts +14 -1
- package/dist/types/core/prometheus.d.ts +7 -0
- package/dist/types/core/runtime-monitor.d.ts +15 -0
- package/dist/types/core/types.d.ts +111 -2
- package/dist/types/index.d.ts +8 -2
- package/dist/types/integrations/express/index.d.ts +2 -2
- package/dist/types/integrations/nest/capture.d.ts +4 -0
- package/dist/types/integrations/nest/exception-filter.d.ts +6 -2
- package/dist/types/integrations/nest/filter-wrapper.d.ts +7 -0
- package/dist/types/integrations/nest/index.d.ts +6 -2
- package/dist/types/integrations/nest/module.d.ts +9 -0
- package/dist/types/integrations/nest/register.d.ts +3 -0
- package/dist/types/integrations/request-context.d.ts +3 -0
- package/dist/types/notifiers/alert-payload.d.ts +5 -0
- package/dist/types/notifiers/webhook-http.d.ts +37 -0
- package/dist/types/notifiers/webhook.d.ts +4 -0
- package/dist/types-cjs/core/admission.d.cts +10 -0
- package/dist/types-cjs/core/config.d.cts +17 -1
- package/dist/types-cjs/core/diagnostics.d.cts +7 -1
- package/dist/types-cjs/core/incident-policy.d.cts +1 -1
- package/dist/types-cjs/core/limits.d.cts +14 -0
- package/dist/types-cjs/core/notification-queue.d.cts +14 -1
- package/dist/types-cjs/core/prometheus.d.cts +7 -0
- package/dist/types-cjs/core/runtime-monitor.d.cts +15 -0
- package/dist/types-cjs/core/types.d.cts +111 -2
- package/dist/types-cjs/index.d.cts +8 -2
- package/dist/types-cjs/integrations/express/index.d.cts +2 -2
- package/dist/types-cjs/integrations/nest/capture.d.cts +4 -0
- package/dist/types-cjs/integrations/nest/exception-filter.d.cts +6 -2
- package/dist/types-cjs/integrations/nest/filter-wrapper.d.cts +7 -0
- package/dist/types-cjs/integrations/nest/index.d.cts +6 -2
- package/dist/types-cjs/integrations/nest/module.d.cts +9 -0
- package/dist/types-cjs/integrations/nest/register.d.cts +3 -0
- package/dist/types-cjs/integrations/request-context.d.cts +3 -0
- package/dist/types-cjs/notifiers/alert-payload.d.cts +5 -0
- package/dist/types-cjs/notifiers/webhook-http.d.cts +37 -0
- package/dist/types-cjs/notifiers/webhook.d.cts +4 -0
- package/package.json +17 -4
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PROMETHEUS_CONTENT_TYPE = void 0;
|
|
4
|
+
exports.createWotchiPrometheusExporter = createWotchiPrometheusExporter;
|
|
5
|
+
exports.PROMETHEUS_CONTENT_TYPE = "text/plain; version=0.0.4; charset=utf-8";
|
|
6
|
+
const METRICS = [
|
|
7
|
+
{
|
|
8
|
+
name: "captured_events_total",
|
|
9
|
+
help: "Total events accepted by Wotchi.",
|
|
10
|
+
type: "counter",
|
|
11
|
+
value: (diagnostics) => diagnostics.capturedEvents,
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "capture_failures_total",
|
|
15
|
+
help: "Capture failures contained by Wotchi.",
|
|
16
|
+
type: "counter",
|
|
17
|
+
value: (diagnostics) => diagnostics.captureFailures,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "groups_evicted_total",
|
|
21
|
+
help: "Groups evicted from bounded memory.",
|
|
22
|
+
type: "counter",
|
|
23
|
+
value: (diagnostics) => diagnostics.groupsEvicted,
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "alerts_queued_total",
|
|
27
|
+
help: "Alerts admitted to the notification queue.",
|
|
28
|
+
type: "counter",
|
|
29
|
+
value: (diagnostics) => diagnostics.alertsQueued,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "alerts_dropped_total",
|
|
33
|
+
help: "Alerts dropped because the notification queue was full.",
|
|
34
|
+
type: "counter",
|
|
35
|
+
value: (diagnostics) => diagnostics.alertsDropped,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "alerts_sent_total",
|
|
39
|
+
help: "Alerts delivered successfully to notifiers.",
|
|
40
|
+
type: "counter",
|
|
41
|
+
value: (diagnostics) => diagnostics.alertsSent,
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "notifier_failures_total",
|
|
45
|
+
help: "Notifier delivery failures contained by Wotchi.",
|
|
46
|
+
type: "counter",
|
|
47
|
+
value: (diagnostics) => diagnostics.notifierFailures,
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: "fingerprint_callback_failures_total",
|
|
51
|
+
help: "Fingerprint callback failures contained by Wotchi.",
|
|
52
|
+
type: "counter",
|
|
53
|
+
value: (diagnostics) => diagnostics.fingerprintCallbackFailures,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "filter_failures_total",
|
|
57
|
+
help: "Event filter failures contained by Wotchi.",
|
|
58
|
+
type: "counter",
|
|
59
|
+
value: (diagnostics) => diagnostics.filterFailures,
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
name: "before_send_failures_total",
|
|
63
|
+
help: "Before-send callback failures contained by Wotchi.",
|
|
64
|
+
type: "counter",
|
|
65
|
+
value: (diagnostics) => diagnostics.beforeSendFailures,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: "events_suppressed_total",
|
|
69
|
+
help: "Events suppressed by filtering, thresholds, or cooldowns.",
|
|
70
|
+
type: "counter",
|
|
71
|
+
value: (diagnostics) => diagnostics.eventsSuppressed,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "events_dropped_overload_total",
|
|
75
|
+
help: "Events dropped before normalization by the optional overload admission limit.",
|
|
76
|
+
type: "counter",
|
|
77
|
+
value: (diagnostics) => diagnostics.eventsDroppedOverload,
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "captures_after_shutdown_total",
|
|
81
|
+
help: "Capture calls ignored after client shutdown.",
|
|
82
|
+
type: "counter",
|
|
83
|
+
value: (diagnostics) => diagnostics.capturesAfterShutdown,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: "notifier_timeouts_total",
|
|
87
|
+
help: "Notifier deliveries that exceeded the configured timeout.",
|
|
88
|
+
type: "counter",
|
|
89
|
+
value: (diagnostics) => diagnostics.notifierTimeouts,
|
|
90
|
+
},
|
|
91
|
+
{
|
|
92
|
+
name: "notifier_circuit_open_skips_total",
|
|
93
|
+
help: "Notifier deliveries skipped while the notifier circuit was open.",
|
|
94
|
+
type: "counter",
|
|
95
|
+
value: (diagnostics) => diagnostics.notifierCircuitOpenSkips,
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "active_groups",
|
|
99
|
+
help: "Current in-memory incident groups.",
|
|
100
|
+
type: "gauge",
|
|
101
|
+
value: (diagnostics) => diagnostics.activeGroups,
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
name: "pending_alerts",
|
|
105
|
+
help: "Current alerts waiting for notifier delivery.",
|
|
106
|
+
type: "gauge",
|
|
107
|
+
value: (diagnostics) => diagnostics.pendingAlerts,
|
|
108
|
+
},
|
|
109
|
+
];
|
|
110
|
+
const safeMetricValue = (value) => {
|
|
111
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
return Math.min(Math.floor(value), Number.MAX_SAFE_INTEGER);
|
|
115
|
+
};
|
|
116
|
+
const renderMetrics = (diagnostics) => {
|
|
117
|
+
const lines = [];
|
|
118
|
+
for (const metric of METRICS) {
|
|
119
|
+
lines.push(`# HELP wotchi_${metric.name} ${metric.help}`, `# TYPE wotchi_${metric.name} ${metric.type}`, `wotchi_${metric.name} ${safeMetricValue(metric.value(diagnostics))}`);
|
|
120
|
+
}
|
|
121
|
+
lines.push("");
|
|
122
|
+
return lines.join("\n");
|
|
123
|
+
};
|
|
124
|
+
function createWotchiPrometheusExporter(client) {
|
|
125
|
+
return Object.freeze({
|
|
126
|
+
contentType: exports.PROMETHEUS_CONTENT_TYPE,
|
|
127
|
+
render: () => renderMetrics(client.getDiagnostics()),
|
|
128
|
+
});
|
|
129
|
+
}
|
package/dist/cjs/core/redact.js
CHANGED
|
@@ -4,6 +4,7 @@ exports.REDACTED = void 0;
|
|
|
4
4
|
exports.redactValue = redactValue;
|
|
5
5
|
exports.redactError = redactError;
|
|
6
6
|
const normalize_js_1 = require("./normalize.js");
|
|
7
|
+
const limits_js_1 = require("./limits.js");
|
|
7
8
|
exports.REDACTED = "[REDACTED]";
|
|
8
9
|
const DEFAULT_KEYS = [
|
|
9
10
|
"authorization",
|
|
@@ -14,6 +15,12 @@ const DEFAULT_KEYS = [
|
|
|
14
15
|
"secret",
|
|
15
16
|
"apiKey",
|
|
16
17
|
"api_key",
|
|
18
|
+
"xApiKey",
|
|
19
|
+
"x_api_key",
|
|
20
|
+
"dbPassword",
|
|
21
|
+
"db_password",
|
|
22
|
+
"databasePassword",
|
|
23
|
+
"database_password",
|
|
17
24
|
"token",
|
|
18
25
|
"accessToken",
|
|
19
26
|
"access_token",
|
|
@@ -23,12 +30,16 @@ const DEFAULT_KEYS = [
|
|
|
23
30
|
"private_key",
|
|
24
31
|
"clientSecret",
|
|
25
32
|
"client_secret",
|
|
33
|
+
"signature",
|
|
34
|
+
"session",
|
|
35
|
+
"webhookSecret",
|
|
36
|
+
"webhook_secret",
|
|
26
37
|
"cardNumber",
|
|
27
38
|
"cvv",
|
|
28
39
|
"cvc",
|
|
29
40
|
"pin",
|
|
30
41
|
];
|
|
31
|
-
const normalizeKey = (key) => key.toLowerCase().replace(/[-
|
|
42
|
+
const normalizeKey = (key) => key.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
32
43
|
const defaultKeySet = new Set(DEFAULT_KEYS.map(normalizeKey));
|
|
33
44
|
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
34
45
|
const luhnValid = (digits) => {
|
|
@@ -54,6 +65,7 @@ const redactCardLikeValues = (value) => value.replace(/\b\d[\d -]{11,25}\d\b/g,
|
|
|
54
65
|
const CONNECTION_URL_PATTERN = /\b(?:postgres(?:ql)?|rediss?|mongodb(?:\+srv)?):\/\/[^\s"'<>]+/gi;
|
|
55
66
|
const CONNECTION_QUERY_SECRET_PATTERN = /([?&](?:password|passwd|pass|secret|token|api[-_]?key|access[-_]?token|refresh[-_]?token|sslpassword)=)[^&#\s]*/gi;
|
|
56
67
|
const URL_TRAILING_PUNCTUATION = /[),.;!?]+$/;
|
|
68
|
+
const AUTHORITY_USERINFO_PATTERN = /\b[^:\s/@]+:[^\s/@]+@(?=(?:[a-z0-9-]+(?:\.[a-z0-9-]+)*|\[[0-9a-f:.]+\])(?::\d+)?(?:[/?#\s,;.)]|$))/gi;
|
|
57
69
|
const redactConnectionUrl = (candidate) => {
|
|
58
70
|
let core = candidate;
|
|
59
71
|
let suffix = "";
|
|
@@ -77,20 +89,57 @@ const redactConnectionUrl = (candidate) => {
|
|
|
77
89
|
return `${core.slice(0, authorityStart)}${redactedAuthority}${remainder}${suffix}`;
|
|
78
90
|
};
|
|
79
91
|
const redactConnectionUrls = (value) => value.replace(CONNECTION_URL_PATTERN, redactConnectionUrl);
|
|
92
|
+
const redactAuthorityUserinfo = (value) => value.replace(AUTHORITY_USERINFO_PATTERN, `${exports.REDACTED}@`);
|
|
93
|
+
const SENSITIVE_QUERY_KEYS = new Set([
|
|
94
|
+
"authorization",
|
|
95
|
+
"cookie",
|
|
96
|
+
"password",
|
|
97
|
+
"passwd",
|
|
98
|
+
"secret",
|
|
99
|
+
"signature",
|
|
100
|
+
"token",
|
|
101
|
+
"accesstoken",
|
|
102
|
+
"refreshtoken",
|
|
103
|
+
"apikey",
|
|
104
|
+
"xapikey",
|
|
105
|
+
"session",
|
|
106
|
+
]);
|
|
107
|
+
const decodeQueryKey = (value) => {
|
|
108
|
+
try {
|
|
109
|
+
return decodeURIComponent(value.replace(/\+/g, " "));
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const redactSensitiveQueryValues = (value) => value.replace(/([?&])([^=&#\s]+)=([^&#\s]*)/g, (match, prefix, key) => {
|
|
116
|
+
if (!SENSITIVE_QUERY_KEYS.has(normalizeKey(decodeQueryKey(key)))) {
|
|
117
|
+
return match;
|
|
118
|
+
}
|
|
119
|
+
return prefix + key + "=" + exports.REDACTED;
|
|
120
|
+
});
|
|
121
|
+
const redactWebhookPathSecrets = (value) => value.replace(/(https?:\/\/[^/\s]+\/(?:services|hooks|webhooks?)\/)[^/?#\s]+/gi, (_match, prefix) => prefix + exports.REDACTED);
|
|
80
122
|
const redactString = (value, maxStringLength) => {
|
|
81
123
|
let result = redactConnectionUrls(value);
|
|
124
|
+
result = redactAuthorityUserinfo(result);
|
|
125
|
+
result = redactWebhookPathSecrets(result);
|
|
126
|
+
result = redactSensitiveQueryValues(result);
|
|
82
127
|
result = result.replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?-----END [^-]*PRIVATE KEY-----/gi, exports.REDACTED);
|
|
83
128
|
result = result.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, `Bearer ${exports.REDACTED}`);
|
|
84
|
-
result = result.replace(/\
|
|
129
|
+
result = result.replace(/\bBasic\s+[A-Za-z0-9+/=]+/gi, `Basic ${exports.REDACTED}`);
|
|
130
|
+
result = result.replace(/\b(?:Cookie|Set-Cookie)\s*:\s*[^\r\n]+/gi, "Cookie: [REDACTED]");
|
|
131
|
+
result = result.replace(/\b(?:authorization|password|passwd|secret|signature|session|token|x[-_]?api[-_]?key|db[-_]?password|database[-_]?password|api[-_]?key)\s*[:=]\s*[^\s,;]+/gi, (match) => {
|
|
85
132
|
const separatorIndex = match.search(/[:=]/);
|
|
86
133
|
return separatorIndex < 0 ? exports.REDACTED : `${match.slice(0, separatorIndex + 1)}${exports.REDACTED}`;
|
|
87
134
|
});
|
|
88
|
-
result = result.replace(/\b[A-Za-z0-9_-]{
|
|
135
|
+
result = result.replace(/\b[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g, exports.REDACTED);
|
|
89
136
|
result = result.replace(/\b(?:github_pat|ghp|xox[baprs]-|sk|pk|AKIA)[A-Za-z0-9_-]{8,}\b/gi, exports.REDACTED);
|
|
90
137
|
result = redactCardLikeValues(result);
|
|
91
138
|
return result.slice(0, maxStringLength);
|
|
92
139
|
};
|
|
93
|
-
const normalizedOption = (value, fallback) => Number.isSafeInteger(value) && value !== undefined && value > 0
|
|
140
|
+
const normalizedOption = (value, fallback, maximum) => Number.isSafeInteger(value) && value !== undefined && value > 0 && value <= maximum
|
|
141
|
+
? value
|
|
142
|
+
: fallback;
|
|
94
143
|
const redactNormalized = (value, sensitiveKeys, options, depth, keysVisited) => {
|
|
95
144
|
if (typeof value === "string") {
|
|
96
145
|
return redactString(value, options.maxStringLength);
|
|
@@ -128,10 +177,10 @@ const redactNormalized = (value, sensitiveKeys, options, depth, keysVisited) =>
|
|
|
128
177
|
return result;
|
|
129
178
|
};
|
|
130
179
|
const redactionLimits = (options) => ({
|
|
131
|
-
maxDepth: normalizedOption(options.maxDepth, 5),
|
|
132
|
-
maxKeys: normalizedOption(options.maxKeys, 100),
|
|
133
|
-
maxStringLength: normalizedOption(options.maxStringLength, 500),
|
|
134
|
-
maxStackLength: normalizedOption(options.maxStackLength, 4_000),
|
|
180
|
+
maxDepth: normalizedOption(options.maxDepth, 5, limits_js_1.MAX_NORMALIZATION_DEPTH),
|
|
181
|
+
maxKeys: normalizedOption(options.maxKeys, 100, limits_js_1.MAX_NORMALIZATION_KEYS),
|
|
182
|
+
maxStringLength: normalizedOption(options.maxStringLength, 500, limits_js_1.MAX_NORMALIZATION_STRING_LENGTH),
|
|
183
|
+
maxStackLength: normalizedOption(options.maxStackLength, 4_000, limits_js_1.MAX_NORMALIZATION_STACK_LENGTH),
|
|
135
184
|
});
|
|
136
185
|
const sensitiveKeySet = (options) => {
|
|
137
186
|
const keys = new Set(defaultKeySet);
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.registerWotchiRuntimeWatcher = registerWotchiRuntimeWatcher;
|
|
4
|
+
const DEFAULT_INTERVAL_MS = 5_000;
|
|
5
|
+
const MIN_INTERVAL_MS = 100;
|
|
6
|
+
const MAX_INTERVAL_MS = 60_000;
|
|
7
|
+
const MAX_THRESHOLD = Number.MAX_SAFE_INTEGER;
|
|
8
|
+
const positiveNumber = (value, fallback, field) => {
|
|
9
|
+
if (value === undefined) {
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
if (!Number.isFinite(value) || value <= 0 || value > MAX_THRESHOLD) {
|
|
13
|
+
throw new RangeError(`${field} must be a positive finite number`);
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
};
|
|
17
|
+
function registerWotchiRuntimeWatcher(client, options = {}) {
|
|
18
|
+
const intervalMs = positiveNumber(options.intervalMs, DEFAULT_INTERVAL_MS, "intervalMs");
|
|
19
|
+
if (!Number.isSafeInteger(intervalMs) ||
|
|
20
|
+
intervalMs < MIN_INTERVAL_MS ||
|
|
21
|
+
intervalMs > MAX_INTERVAL_MS) {
|
|
22
|
+
throw new RangeError(`intervalMs must be an integer from ${MIN_INTERVAL_MS} to ${MAX_INTERVAL_MS}`);
|
|
23
|
+
}
|
|
24
|
+
const thresholds = {
|
|
25
|
+
cpuPercent: options.cpuPercent,
|
|
26
|
+
rssBytes: options.rssBytes,
|
|
27
|
+
heapUsedBytes: options.heapUsedBytes,
|
|
28
|
+
eventLoopDelayMs: options.eventLoopDelayMs,
|
|
29
|
+
pendingAlerts: options.pendingAlerts,
|
|
30
|
+
notifierFailures: options.notifierFailures,
|
|
31
|
+
};
|
|
32
|
+
for (const [field, value] of Object.entries(thresholds)) {
|
|
33
|
+
if (value !== undefined) {
|
|
34
|
+
positiveNumber(value, 1, field);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
const alertThreshold = options.alertThreshold ?? 3;
|
|
38
|
+
if (!Number.isSafeInteger(alertThreshold) || alertThreshold <= 0 || alertThreshold > 1_000_000) {
|
|
39
|
+
throw new RangeError("alertThreshold must be a positive integer no greater than 1000000");
|
|
40
|
+
}
|
|
41
|
+
let previousCpu = process.cpuUsage();
|
|
42
|
+
let previousTime = process.hrtime.bigint();
|
|
43
|
+
let previousNotifierFailures = client.getDiagnostics().notifierFailures;
|
|
44
|
+
let expectedAt = Date.now() + intervalMs;
|
|
45
|
+
let registered = true;
|
|
46
|
+
const sample = () => {
|
|
47
|
+
if (!registered) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const timestamp = Date.now();
|
|
51
|
+
const elapsedMicros = Math.max(1, Number(process.hrtime.bigint() - previousTime) / 1_000);
|
|
52
|
+
const cpu = process.cpuUsage(previousCpu);
|
|
53
|
+
previousCpu = process.cpuUsage();
|
|
54
|
+
previousTime = process.hrtime.bigint();
|
|
55
|
+
const memory = process.memoryUsage();
|
|
56
|
+
const eventLoopDelayMs = Math.max(0, timestamp - expectedAt);
|
|
57
|
+
expectedAt = timestamp + intervalMs;
|
|
58
|
+
const cpuPercent = ((cpu.user + cpu.system) / elapsedMicros) * 100;
|
|
59
|
+
const diagnostics = client.getDiagnostics();
|
|
60
|
+
const notifierFailures = Math.max(0, diagnostics.notifierFailures - previousNotifierFailures);
|
|
61
|
+
previousNotifierFailures = diagnostics.notifierFailures;
|
|
62
|
+
const readings = [
|
|
63
|
+
{ metric: "cpu-percent", value: cpuPercent, threshold: thresholds.cpuPercent },
|
|
64
|
+
{ metric: "rss-bytes", value: memory.rss, threshold: thresholds.rssBytes },
|
|
65
|
+
{ metric: "heap-used-bytes", value: memory.heapUsed, threshold: thresholds.heapUsedBytes },
|
|
66
|
+
{
|
|
67
|
+
metric: "event-loop-delay-ms",
|
|
68
|
+
value: eventLoopDelayMs,
|
|
69
|
+
threshold: thresholds.eventLoopDelayMs,
|
|
70
|
+
},
|
|
71
|
+
{ metric: "pending-alerts", value: 0, threshold: thresholds.pendingAlerts },
|
|
72
|
+
{
|
|
73
|
+
metric: "notifier-failures",
|
|
74
|
+
value: notifierFailures,
|
|
75
|
+
threshold: thresholds.notifierFailures,
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
for (const reading of readings) {
|
|
79
|
+
const value = reading.metric === "pending-alerts" ? diagnostics.pendingAlerts : reading.value;
|
|
80
|
+
if (reading.threshold === undefined || value < reading.threshold) {
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
client.captureEvent({
|
|
84
|
+
level: "error",
|
|
85
|
+
kind: "runtime-monitor",
|
|
86
|
+
message: `Wotchi runtime pressure: ${reading.metric}`,
|
|
87
|
+
fingerprint: `wotchi.runtime.${reading.metric}`,
|
|
88
|
+
severity: "high",
|
|
89
|
+
alertThreshold,
|
|
90
|
+
context: {
|
|
91
|
+
metric: reading.metric,
|
|
92
|
+
value: Math.round(value * 100) / 100,
|
|
93
|
+
threshold: reading.threshold,
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
const timer = setInterval(sample, intervalMs);
|
|
99
|
+
timer.unref?.();
|
|
100
|
+
return {
|
|
101
|
+
unregister: () => {
|
|
102
|
+
if (!registered) {
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
registered = false;
|
|
106
|
+
clearInterval(timer);
|
|
107
|
+
},
|
|
108
|
+
};
|
|
109
|
+
}
|
package/dist/cjs/index.js
CHANGED
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.telegramNotifier = exports.registerWotchiProcessMonitor = exports.createWotchi = exports.consoleNotifier = exports.WotchiConfigurationError = void 0;
|
|
3
|
+
exports.webhookNotifier = exports.telegramNotifier = exports.registerWotchiRuntimeWatcher = exports.registerWotchiProcessMonitor = exports.PROMETHEUS_CONTENT_TYPE = exports.createWotchiPrometheusExporter = exports.createWotchi = exports.consoleNotifier = exports.WotchiConfigurationError = void 0;
|
|
4
4
|
const client_js_1 = require("./core/client.js");
|
|
5
5
|
Object.defineProperty(exports, "createWotchi", { enumerable: true, get: function () { return client_js_1.createWotchi; } });
|
|
6
6
|
const process_monitor_js_1 = require("./core/process-monitor.js");
|
|
7
7
|
Object.defineProperty(exports, "registerWotchiProcessMonitor", { enumerable: true, get: function () { return process_monitor_js_1.registerWotchiProcessMonitor; } });
|
|
8
|
+
const prometheus_js_1 = require("./core/prometheus.js");
|
|
9
|
+
Object.defineProperty(exports, "createWotchiPrometheusExporter", { enumerable: true, get: function () { return prometheus_js_1.createWotchiPrometheusExporter; } });
|
|
10
|
+
Object.defineProperty(exports, "PROMETHEUS_CONTENT_TYPE", { enumerable: true, get: function () { return prometheus_js_1.PROMETHEUS_CONTENT_TYPE; } });
|
|
11
|
+
const runtime_monitor_js_1 = require("./core/runtime-monitor.js");
|
|
12
|
+
Object.defineProperty(exports, "registerWotchiRuntimeWatcher", { enumerable: true, get: function () { return runtime_monitor_js_1.registerWotchiRuntimeWatcher; } });
|
|
8
13
|
const console_js_1 = require("./notifiers/console.js");
|
|
9
14
|
Object.defineProperty(exports, "consoleNotifier", { enumerable: true, get: function () { return console_js_1.consoleNotifier; } });
|
|
10
15
|
const telegram_js_1 = require("./notifiers/telegram.js");
|
|
11
16
|
Object.defineProperty(exports, "telegramNotifier", { enumerable: true, get: function () { return telegram_js_1.telegramNotifier; } });
|
|
17
|
+
const webhook_js_1 = require("./notifiers/webhook.js");
|
|
18
|
+
Object.defineProperty(exports, "webhookNotifier", { enumerable: true, get: function () { return webhook_js_1.webhookNotifier; } });
|
|
12
19
|
var errors_js_1 = require("./core/errors.js");
|
|
13
20
|
Object.defineProperty(exports, "WotchiConfigurationError", { enumerable: true, get: function () { return errors_js_1.WotchiConfigurationError; } });
|
|
@@ -6,11 +6,28 @@ const state_js_1 = require("./state.js");
|
|
|
6
6
|
function createExpressErrorHandler(client, options) {
|
|
7
7
|
return (error, request, response, next) => {
|
|
8
8
|
(0, state_js_1.markExpressErrorCaptured)(request);
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
let captured = false;
|
|
10
|
+
const captureAfterResponse = () => {
|
|
11
|
+
if (captured) {
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
captured = true;
|
|
15
|
+
response.off("finish", captureAfterResponse);
|
|
16
|
+
response.off("close", captureAfterResponse);
|
|
17
|
+
try {
|
|
18
|
+
const requestContext = (0, request_context_js_1.getExpressRequestContext)(request, response, options);
|
|
19
|
+
client.captureException(error, undefined, requestContext === undefined ? undefined : { request: requestContext });
|
|
20
|
+
}
|
|
21
|
+
catch {
|
|
22
|
+
// A capture failure must never change Express error handling.
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
if (response.writableEnded || response.finished) {
|
|
26
|
+
captureAfterResponse();
|
|
11
27
|
}
|
|
12
|
-
|
|
13
|
-
|
|
28
|
+
else {
|
|
29
|
+
response.once("finish", captureAfterResponse);
|
|
30
|
+
response.once("close", captureAfterResponse);
|
|
14
31
|
}
|
|
15
32
|
next(error);
|
|
16
33
|
};
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.wotchiStatusObserver = exports.telegramNotifier = exports.createWotchi = exports.consoleNotifier = void 0;
|
|
3
|
+
exports.wotchiStatusObserver = exports.webhookNotifier = exports.telegramNotifier = exports.createWotchi = exports.consoleNotifier = void 0;
|
|
4
4
|
exports.wotchiErrorHandler = wotchiErrorHandler;
|
|
5
5
|
const error_handler_js_1 = require("./error-handler.js");
|
|
6
6
|
var index_js_1 = require("../../index.js");
|
|
7
7
|
Object.defineProperty(exports, "consoleNotifier", { enumerable: true, get: function () { return index_js_1.consoleNotifier; } });
|
|
8
8
|
Object.defineProperty(exports, "createWotchi", { enumerable: true, get: function () { return index_js_1.createWotchi; } });
|
|
9
9
|
Object.defineProperty(exports, "telegramNotifier", { enumerable: true, get: function () { return index_js_1.telegramNotifier; } });
|
|
10
|
+
Object.defineProperty(exports, "webhookNotifier", { enumerable: true, get: function () { return index_js_1.webhookNotifier; } });
|
|
10
11
|
var status_observer_js_1 = require("./status-observer.js");
|
|
11
12
|
Object.defineProperty(exports, "wotchiStatusObserver", { enumerable: true, get: function () { return status_observer_js_1.wotchiStatusObserver; } });
|
|
12
13
|
function wotchiErrorHandler(client, options) {
|
|
@@ -42,6 +42,12 @@ const normalizeOptions = (options) => {
|
|
|
42
42
|
...(options?.requestIdProperty === undefined
|
|
43
43
|
? {}
|
|
44
44
|
: { requestIdProperty: options.requestIdProperty }),
|
|
45
|
+
...(options?.correlationIdProperty === undefined
|
|
46
|
+
? {}
|
|
47
|
+
: { correlationIdProperty: options.correlationIdProperty }),
|
|
48
|
+
...(options?.traceContextProperty === undefined
|
|
49
|
+
? {}
|
|
50
|
+
: { traceContextProperty: options.traceContextProperty }),
|
|
45
51
|
statusCodes: normalizeStatuses(options?.statusCodes, DEFAULT_STATUS_CODES),
|
|
46
52
|
statusClasses: normalizeStatusClasses(options?.statusClasses),
|
|
47
53
|
ignoreStatusCodes: normalizeStatuses(options?.ignoreStatusCodes, []),
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.captureWotchiNestException = void 0;
|
|
4
|
+
const state_js_1 = require("../express/state.js");
|
|
5
|
+
const request_context_js_1 = require("./request-context.js");
|
|
6
|
+
const captureWotchiNestException = (client, exception, host, options) => {
|
|
7
|
+
try {
|
|
8
|
+
(0, state_js_1.markExpressErrorCaptured)(host.switchToHttp().getRequest());
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
// Non-HTTP NestJS contexts do not expose an Express request to mark.
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const requestContext = (0, request_context_js_1.getNestRequestContext)(host, exception, options);
|
|
15
|
+
client.captureException(exception, undefined, requestContext === undefined ? undefined : { request: requestContext });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// A capture failure must never change NestJS exception handling.
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
exports.captureWotchiNestException = captureWotchiNestException;
|
|
@@ -12,25 +12,81 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
12
12
|
exports.WotchiNestExceptionFilter = void 0;
|
|
13
13
|
const common_1 = require("@nestjs/common");
|
|
14
14
|
const core_1 = require("@nestjs/core");
|
|
15
|
-
const
|
|
15
|
+
const capture_js_1 = require("./capture.js");
|
|
16
|
+
const FILTER_CATCH_EXCEPTIONS = "__filterCatchExceptions__";
|
|
17
|
+
const matchesException = (filter, exception) => {
|
|
18
|
+
const reflection = Reflect;
|
|
19
|
+
const exceptionTypes = reflection.getMetadata?.(FILTER_CATCH_EXCEPTIONS, filter.constructor);
|
|
20
|
+
if (!Array.isArray(exceptionTypes) || exceptionTypes.length === 0) {
|
|
21
|
+
return true;
|
|
22
|
+
}
|
|
23
|
+
return exceptionTypes.some((exceptionType) => typeof exceptionType === "function" &&
|
|
24
|
+
exception instanceof exceptionType);
|
|
25
|
+
};
|
|
16
26
|
let WotchiNestExceptionFilter = class WotchiNestExceptionFilter extends core_1.BaseExceptionFilter {
|
|
17
|
-
constructor(client, applicationRef, options) {
|
|
27
|
+
constructor(client, applicationRef, options, previousGlobalFilters = []) {
|
|
18
28
|
super(applicationRef);
|
|
19
29
|
this.client = client;
|
|
20
30
|
this.options = options;
|
|
31
|
+
this.previousGlobalFilters = previousGlobalFilters;
|
|
21
32
|
}
|
|
22
33
|
catch(exception, host) {
|
|
23
|
-
|
|
24
|
-
|
|
34
|
+
(0, capture_js_1.captureWotchiNestException)(this.client, exception, host, this.options);
|
|
35
|
+
const existingFilter = this.previousGlobalFilters.find((filter) => matchesException(filter, exception));
|
|
36
|
+
if (existingFilter !== undefined) {
|
|
37
|
+
existingFilter.catch(exception, host);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
this.respondWithoutLoggingRawUnknownException(exception, host);
|
|
41
|
+
}
|
|
42
|
+
respondWithoutLoggingRawUnknownException(exception, host) {
|
|
43
|
+
if (this.applicationRef === undefined) {
|
|
44
|
+
this.respondThroughExpressAdapter(exception, host);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
if (exception instanceof common_1.HttpException) {
|
|
48
|
+
super.catch(exception, host);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const response = host.getArgByIndex(1);
|
|
52
|
+
if (this.applicationRef.isHeadersSent(response)) {
|
|
53
|
+
this.applicationRef.end(response);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (this.isHttpError(exception)) {
|
|
57
|
+
this.applicationRef.reply(response, { statusCode: exception.statusCode, message: exception.message }, exception.statusCode);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.applicationRef.reply(response, { statusCode: 500, message: "Internal server error" }, 500);
|
|
61
|
+
}
|
|
62
|
+
respondThroughExpressAdapter(exception, host) {
|
|
63
|
+
const response = host.switchToHttp().getResponse();
|
|
64
|
+
if (response.headersSent) {
|
|
65
|
+
response.end();
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (exception instanceof common_1.HttpException) {
|
|
69
|
+
const statusCode = exception.getStatus();
|
|
70
|
+
const exceptionResponse = exception.getResponse();
|
|
71
|
+
response
|
|
72
|
+
.status(statusCode)
|
|
73
|
+
.json(typeof exceptionResponse === "object" && exceptionResponse !== null
|
|
74
|
+
? exceptionResponse
|
|
75
|
+
: { statusCode, message: exceptionResponse });
|
|
76
|
+
return;
|
|
25
77
|
}
|
|
26
|
-
|
|
27
|
-
|
|
78
|
+
if (this.isHttpError(exception)) {
|
|
79
|
+
response.status(exception.statusCode).json({
|
|
80
|
+
statusCode: exception.statusCode,
|
|
81
|
+
message: exception.message,
|
|
82
|
+
});
|
|
83
|
+
return;
|
|
28
84
|
}
|
|
29
|
-
|
|
85
|
+
response.status(500).json({ statusCode: 500, message: "Internal server error" });
|
|
30
86
|
}
|
|
31
87
|
};
|
|
32
88
|
exports.WotchiNestExceptionFilter = WotchiNestExceptionFilter;
|
|
33
89
|
exports.WotchiNestExceptionFilter = WotchiNestExceptionFilter = __decorate([
|
|
34
90
|
(0, common_1.Catch)(),
|
|
35
|
-
__metadata("design:paramtypes", [Object, Object, Object])
|
|
91
|
+
__metadata("design:paramtypes", [Object, Object, Object, Array])
|
|
36
92
|
], WotchiNestExceptionFilter);
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.withWotchiNestFilter = withWotchiNestFilter;
|
|
4
|
+
const capture_js_1 = require("./capture.js");
|
|
5
|
+
function withWotchiNestFilter(client, filter, options) {
|
|
6
|
+
const wrapped = Object.create(filter);
|
|
7
|
+
Object.defineProperty(wrapped, "catch", {
|
|
8
|
+
configurable: false,
|
|
9
|
+
enumerable: false,
|
|
10
|
+
value: (exception, host) => {
|
|
11
|
+
(0, capture_js_1.captureWotchiNestException)(client, exception, host, options);
|
|
12
|
+
filter.catch(exception, host);
|
|
13
|
+
},
|
|
14
|
+
writable: false,
|
|
15
|
+
});
|
|
16
|
+
return wrapped;
|
|
17
|
+
}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.registerWotchiNestStatusObserver = exports.registerWotchiNest = exports.telegramNotifier = exports.createWotchi = exports.consoleNotifier = void 0;
|
|
3
|
+
exports.registerWotchiNestStatusObserver = exports.registerWotchiNest = exports.WOTCHI_CLIENT = exports.WotchiModule = exports.withWotchiNestFilter = exports.webhookNotifier = exports.telegramNotifier = exports.createWotchi = exports.consoleNotifier = void 0;
|
|
4
4
|
var index_js_1 = require("../../index.js");
|
|
5
5
|
Object.defineProperty(exports, "consoleNotifier", { enumerable: true, get: function () { return index_js_1.consoleNotifier; } });
|
|
6
6
|
Object.defineProperty(exports, "createWotchi", { enumerable: true, get: function () { return index_js_1.createWotchi; } });
|
|
7
7
|
Object.defineProperty(exports, "telegramNotifier", { enumerable: true, get: function () { return index_js_1.telegramNotifier; } });
|
|
8
|
+
Object.defineProperty(exports, "webhookNotifier", { enumerable: true, get: function () { return index_js_1.webhookNotifier; } });
|
|
9
|
+
var filter_wrapper_js_1 = require("./filter-wrapper.js");
|
|
10
|
+
Object.defineProperty(exports, "withWotchiNestFilter", { enumerable: true, get: function () { return filter_wrapper_js_1.withWotchiNestFilter; } });
|
|
11
|
+
var module_js_1 = require("./module.js");
|
|
12
|
+
Object.defineProperty(exports, "WotchiModule", { enumerable: true, get: function () { return module_js_1.WotchiModule; } });
|
|
13
|
+
Object.defineProperty(exports, "WOTCHI_CLIENT", { enumerable: true, get: function () { return module_js_1.WOTCHI_CLIENT; } });
|
|
8
14
|
var register_js_1 = require("./register.js");
|
|
9
15
|
Object.defineProperty(exports, "registerWotchiNest", { enumerable: true, get: function () { return register_js_1.registerWotchiNest; } });
|
|
10
16
|
Object.defineProperty(exports, "registerWotchiNestStatusObserver", { enumerable: true, get: function () { return register_js_1.registerWotchiNestStatusObserver; } });
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
+
};
|
|
8
|
+
var WotchiModule_1;
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.WotchiModule = exports.WOTCHI_CLIENT = void 0;
|
|
11
|
+
const common_1 = require("@nestjs/common");
|
|
12
|
+
const core_1 = require("@nestjs/core");
|
|
13
|
+
const client_js_1 = require("../../core/client.js");
|
|
14
|
+
const exception_filter_js_1 = require("./exception-filter.js");
|
|
15
|
+
exports.WOTCHI_CLIENT = Symbol("@futurewindai/wotchi/client");
|
|
16
|
+
let WotchiModule = WotchiModule_1 = class WotchiModule {
|
|
17
|
+
static forRoot(config, options) {
|
|
18
|
+
const registerGlobalFilter = options?.registerGlobalFilter ?? true;
|
|
19
|
+
const providers = [
|
|
20
|
+
{
|
|
21
|
+
provide: exports.WOTCHI_CLIENT,
|
|
22
|
+
useFactory: () => (0, client_js_1.createWotchi)(config),
|
|
23
|
+
},
|
|
24
|
+
];
|
|
25
|
+
if (registerGlobalFilter) {
|
|
26
|
+
providers.push({
|
|
27
|
+
provide: core_1.APP_FILTER,
|
|
28
|
+
useFactory: (client) => new exception_filter_js_1.WotchiNestExceptionFilter(client),
|
|
29
|
+
inject: [exports.WOTCHI_CLIENT],
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
module: WotchiModule_1,
|
|
34
|
+
global: true,
|
|
35
|
+
providers,
|
|
36
|
+
exports: [exports.WOTCHI_CLIENT],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
exports.WotchiModule = WotchiModule;
|
|
41
|
+
exports.WotchiModule = WotchiModule = WotchiModule_1 = __decorate([
|
|
42
|
+
(0, common_1.Global)(),
|
|
43
|
+
(0, common_1.Module)({})
|
|
44
|
+
], WotchiModule);
|