@caracalai/core 0.1.2 → 0.1.4-rc.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 (56) hide show
  1. package/dist/async.d.ts +2 -0
  2. package/dist/async.d.ts.map +1 -0
  3. package/dist/async.js +27 -0
  4. package/dist/async.js.map +1 -0
  5. package/dist/audit.d.ts +98 -0
  6. package/dist/audit.d.ts.map +1 -0
  7. package/dist/audit.js +213 -0
  8. package/dist/audit.js.map +1 -0
  9. package/dist/config.d.ts +3 -0
  10. package/dist/config.d.ts.map +1 -1
  11. package/dist/config.js +46 -0
  12. package/dist/config.js.map +1 -1
  13. package/dist/crypto.d.ts +4 -0
  14. package/dist/crypto.d.ts.map +1 -1
  15. package/dist/crypto.js +12 -0
  16. package/dist/crypto.js.map +1 -1
  17. package/dist/env.d.ts +3 -3
  18. package/dist/env.d.ts.map +1 -1
  19. package/dist/env.js +11 -11
  20. package/dist/env.js.map +1 -1
  21. package/dist/envfile.d.ts +16 -1
  22. package/dist/envfile.d.ts.map +1 -1
  23. package/dist/envfile.js +108 -10
  24. package/dist/envfile.js.map +1 -1
  25. package/dist/errors.d.ts +4 -3
  26. package/dist/errors.d.ts.map +1 -1
  27. package/dist/errors.js.map +1 -1
  28. package/dist/index.d.ts +6 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +7 -1
  31. package/dist/index.js.map +1 -1
  32. package/dist/json.d.ts +7 -0
  33. package/dist/json.d.ts.map +1 -0
  34. package/dist/json.js +6 -0
  35. package/dist/json.js.map +1 -0
  36. package/dist/lifecycle.d.ts +17 -0
  37. package/dist/lifecycle.d.ts.map +1 -0
  38. package/dist/lifecycle.js +66 -0
  39. package/dist/lifecycle.js.map +1 -0
  40. package/dist/logging.d.ts +58 -3
  41. package/dist/logging.d.ts.map +1 -1
  42. package/dist/logging.js +292 -7
  43. package/dist/logging.js.map +1 -1
  44. package/dist/metrics.d.ts +4 -0
  45. package/dist/metrics.d.ts.map +1 -0
  46. package/dist/metrics.js +43 -0
  47. package/dist/metrics.js.map +1 -0
  48. package/dist/telemetry.d.ts +10 -0
  49. package/dist/telemetry.d.ts.map +1 -0
  50. package/dist/telemetry.js +98 -0
  51. package/dist/telemetry.js.map +1 -0
  52. package/package.json +12 -8
  53. package/dist/cliconfig.d.ts +0 -31
  54. package/dist/cliconfig.d.ts.map +0 -1
  55. package/dist/cliconfig.js +0 -56
  56. package/dist/cliconfig.js.map +0 -1
package/dist/logging.js CHANGED
@@ -2,22 +2,307 @@
2
2
  // Caracal, a product of Garudex Labs
3
3
  //
4
4
  // Structured JSON logger for TypeScript services.
5
- const ORDER = ['debug', 'info', 'warn', 'error'];
6
- function shouldLog(msgLevel, configLevel) {
7
- return ORDER.indexOf(msgLevel) >= ORDER.indexOf(configLevel);
5
+ import { AsyncLocalStorage } from 'node:async_hooks';
6
+ import { hostname } from 'node:os';
7
+ const LEVEL_VALUE = { debug: 10, info: 20, warn: 30, error: 40, fatal: 50 };
8
+ /**
9
+ * Field names whose values must never appear in dev logs. Mirror this list in
10
+ * packages/core/go/logging/redact.go and packages/core/python/caracalai_core/logging.py.
11
+ */
12
+ export const SECRET_KEYS = Object.freeze([
13
+ 'password',
14
+ 'secret',
15
+ 'token',
16
+ 'access_token',
17
+ 'refresh_token',
18
+ 'id_token',
19
+ 'api_key',
20
+ 'client_secret',
21
+ 'private_key',
22
+ 'session',
23
+ 'assertion',
24
+ 'authorization',
25
+ 'cookie',
26
+ 'set_cookie',
27
+ 'set-cookie',
28
+ 'hmac',
29
+ 'signature',
30
+ ]);
31
+ export const REDACT_VALUE = '***';
32
+ const PINO_REDACT_CONTAINERS = Object.freeze([
33
+ 'req.headers',
34
+ 'request.headers',
35
+ 'res.headers',
36
+ 'response.headers',
37
+ 'req.body',
38
+ 'request.body',
39
+ 'req.query',
40
+ 'request.query',
41
+ ]);
42
+ const BEARER_PATTERN = /bearer\s+[A-Za-z0-9._\-+/=]{8,}/gi;
43
+ const JWT_PATTERN = /eyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}/g;
44
+ const AWS_AKIA = /AKIA[0-9A-Z]{16}/g;
45
+ const AWS_ASIA = /ASIA[0-9A-Z]{16}/g;
46
+ const GCP_KEY = /AIza[0-9A-Za-z_-]{35}/g;
47
+ const GITHUB_PAT = /gh[pousr]_[A-Za-z0-9]{36,255}/g;
48
+ const SLACK_TOKEN = /xox[abprs]-[A-Za-z0-9-]{10,}/g;
49
+ const PEM_BEGIN = '-----BEGIN ';
50
+ const PEM_END = '-----END ';
51
+ const PEM_TAIL = '-----';
52
+ export const MAX_FIELD_BYTES = (() => {
53
+ const v = process.env.CARACAL_LOG_MAX_FIELD_BYTES;
54
+ if (v) {
55
+ const n = Number.parseInt(v, 10);
56
+ if (Number.isFinite(n))
57
+ return n;
58
+ }
59
+ return 8192;
60
+ })();
61
+ export function isSecretKey(name) {
62
+ const lower = name.toLowerCase();
63
+ return SECRET_KEYS.some((k) => lower.includes(k));
8
64
  }
9
- export function createLogger(service, level = 'info') {
65
+ export function buildPinoRedactPaths() {
66
+ const paths = new Set();
67
+ for (const k of SECRET_KEYS) {
68
+ for (const c of PINO_REDACT_CONTAINERS) {
69
+ paths.add(`${c}["${k}"]`);
70
+ paths.add(`${c}["${k.toUpperCase()}"]`);
71
+ }
72
+ }
73
+ return Array.from(paths);
74
+ }
75
+ /**
76
+ * Scrub Bearer tokens, JWT-shaped substrings, and common cloud secret patterns
77
+ * (AWS, GCP, GitHub, Slack, PEM keys) from a string. Cheap on the common path.
78
+ */
79
+ export function redactString(s) {
80
+ if (s.length < 16)
81
+ return s;
82
+ let out = redactPemBlocks(s);
83
+ out = out.replace(BEARER_PATTERN, `Bearer ${REDACT_VALUE}`);
84
+ out = out.replace(JWT_PATTERN, REDACT_VALUE);
85
+ out = out.replace(AWS_AKIA, REDACT_VALUE);
86
+ out = out.replace(AWS_ASIA, REDACT_VALUE);
87
+ out = out.replace(GCP_KEY, REDACT_VALUE);
88
+ out = out.replace(GITHUB_PAT, REDACT_VALUE);
89
+ out = out.replace(SLACK_TOKEN, REDACT_VALUE);
90
+ return out;
91
+ }
92
+ function redactPemBlocks(s) {
93
+ let copyStart = 0;
94
+ let pendingBegin = -1;
95
+ let begin = s.indexOf(PEM_BEGIN);
96
+ let end = s.indexOf(PEM_END);
97
+ const chunks = [];
98
+ while (begin !== -1 || end !== -1) {
99
+ if (begin !== -1 && (end === -1 || begin < end)) {
100
+ const label = readPemLabel(s, begin + PEM_BEGIN.length);
101
+ if (label && isPrivateKeyPemLabel(label.value) && pendingBegin === -1)
102
+ pendingBegin = begin;
103
+ begin = s.indexOf(PEM_BEGIN, label?.end ?? begin + PEM_BEGIN.length);
104
+ continue;
105
+ }
106
+ const label = readPemLabel(s, end + PEM_END.length);
107
+ if (label && isPrivateKeyPemLabel(label.value) && pendingBegin !== -1) {
108
+ chunks.push(s.slice(copyStart, pendingBegin), REDACT_VALUE);
109
+ copyStart = label.end;
110
+ pendingBegin = -1;
111
+ }
112
+ end = s.indexOf(PEM_END, label?.end ?? end + PEM_END.length);
113
+ }
114
+ if (chunks.length === 0)
115
+ return s;
116
+ chunks.push(s.slice(copyStart));
117
+ return chunks.join('');
118
+ }
119
+ function readPemLabel(s, start) {
120
+ const end = s.indexOf(PEM_TAIL, start);
121
+ if (end === -1)
122
+ return null;
123
+ return { value: s.slice(start, end), end: end + PEM_TAIL.length };
124
+ }
125
+ function isPrivateKeyPemLabel(label) {
126
+ if (!label.endsWith('PRIVATE KEY'))
127
+ return false;
128
+ for (let i = 0; i < label.length; i++) {
129
+ const code = label.charCodeAt(i);
130
+ if (code !== 32 && (code < 65 || code > 90))
131
+ return false;
132
+ }
133
+ return true;
134
+ }
135
+ export function truncateString(s) {
136
+ if (MAX_FIELD_BYTES <= 0 || s.length <= MAX_FIELD_BYTES)
137
+ return s;
138
+ return s.slice(0, MAX_FIELD_BYTES) + '…[truncated]';
139
+ }
140
+ function serializeError(err) {
141
+ const out = { name: err.name, message: err.message };
142
+ if (err.stack)
143
+ out.stack = err.stack;
144
+ const code = err.code;
145
+ if (code !== undefined)
146
+ out.code = code;
147
+ const cause = err.cause;
148
+ if (cause !== undefined)
149
+ out.cause = cause instanceof Error ? serializeError(cause) : cause;
150
+ return out;
151
+ }
152
+ /**
153
+ * Returns a deep copy of `value` with any field whose key matches SECRET_KEYS
154
+ * replaced with REDACT_VALUE, string values scrubbed of token-like patterns
155
+ * and truncated to MAX_FIELD_BYTES, and Error instances flattened to plain
156
+ * JSON-friendly objects.
157
+ */
158
+ export function redact(value) {
159
+ if (value === null || value === undefined)
160
+ return value;
161
+ if (typeof value === 'string')
162
+ return truncateString(redactString(value));
163
+ if (value instanceof Error)
164
+ return serializeError(value);
165
+ if (Array.isArray(value))
166
+ return value.map(redact);
167
+ if (typeof value !== 'object')
168
+ return value;
169
+ const out = {};
170
+ for (const [k, v] of Object.entries(value)) {
171
+ out[k] = isSecretKey(k) ? REDACT_VALUE : redact(v);
172
+ }
173
+ return out;
174
+ }
175
+ const traceStore = new AsyncLocalStorage();
176
+ /** Run `fn` with the provided trace context bound to the async chain. */
177
+ export function runWithTrace(tc, fn) {
178
+ return traceStore.run(tc, fn);
179
+ }
180
+ /** Enter a trace context for the remainder of the current async chain. */
181
+ export function bindTrace(tc) {
182
+ traceStore.enterWith(tc);
183
+ }
184
+ /** Returns the trace context bound to the current async chain, or undefined. */
185
+ export function getTraceContext() {
186
+ return traceStore.getStore();
187
+ }
188
+ /** Parse a W3C traceparent header (`version-traceid-spanid-flags`). */
189
+ export function parseTraceparent(h) {
190
+ if (!h)
191
+ return {};
192
+ const parts = h.split('-');
193
+ if (parts.length < 4)
194
+ return {};
195
+ if (parts[1].length !== 32 || parts[2].length !== 16)
196
+ return {};
197
+ return { traceId: parts[1], spanId: parts[2] };
198
+ }
199
+ /** Returns a pino-compatible mixin function that injects trace fields. */
200
+ export function traceMixin() {
201
+ return () => {
202
+ const tc = getTraceContext();
203
+ const out = {};
204
+ if (tc?.traceId)
205
+ out.trace_id = tc.traceId;
206
+ if (tc?.spanId)
207
+ out.span_id = tc.spanId;
208
+ return out;
209
+ };
210
+ }
211
+ const metricsState = { emitted: 0, dropped: 0, sampled: 0 };
212
+ export function devLogMetrics() {
213
+ return { ...metricsState };
214
+ }
215
+ const DEBUG_SAMPLE_N = (() => {
216
+ const v = process.env.CARACAL_LOG_SAMPLE_DEBUG;
217
+ if (v) {
218
+ const n = Number.parseInt(v, 10);
219
+ if (Number.isFinite(n) && n > 0)
220
+ return n;
221
+ }
222
+ return 1;
223
+ })();
224
+ let debugCounter = 0;
225
+ let cachedHostname = null;
226
+ function host() {
227
+ if (cachedHostname === null) {
228
+ try {
229
+ cachedHostname = hostname();
230
+ }
231
+ catch {
232
+ cachedHostname = 'unknown';
233
+ }
234
+ }
235
+ return cachedHostname;
236
+ }
237
+ function processBaseFields() {
238
+ return {
239
+ hostname: host(),
240
+ pid: process.pid,
241
+ version: process.env.CARACAL_VERSION || process.env.npm_package_version || 'dev',
242
+ env: process.env.CARACAL_ENV || process.env.NODE_ENV || 'development',
243
+ };
244
+ }
245
+ function envLevel() {
246
+ const raw = (process.env.CARACAL_LOG_LEVEL || process.env.LOG_LEVEL || '').toLowerCase();
247
+ if (raw === 'debug' || raw === 'info' || raw === 'warn' || raw === 'error' || raw === 'fatal')
248
+ return raw;
249
+ return 'info';
250
+ }
251
+ export function createLogger(service, levelOrOpts) {
252
+ const opts = typeof levelOrOpts === 'string' ? { level: levelOrOpts } : (levelOrOpts ?? {});
253
+ const level = opts.level ?? envLevel();
254
+ const baseFields = {
255
+ service,
256
+ ...processBaseFields(),
257
+ ...(opts.hostname !== undefined ? { hostname: opts.hostname } : {}),
258
+ ...(opts.pid !== undefined ? { pid: opts.pid } : {}),
259
+ ...(opts.version !== undefined ? { version: opts.version } : {}),
260
+ ...(opts.env !== undefined ? { env: opts.env } : {}),
261
+ };
262
+ return makeLogger(baseFields, level, opts.stream ?? process.stderr);
263
+ }
264
+ function makeLogger(bound, level, stream) {
265
+ const threshold = LEVEL_VALUE[level];
10
266
  const emit = (msgLevel, msg, fields) => {
11
- if (!shouldLog(msgLevel, level))
267
+ if (LEVEL_VALUE[msgLevel] < threshold)
12
268
  return;
13
- process.stderr.write(JSON.stringify({ level: msgLevel, service, msg, time: new Date().toISOString(), ...fields }) +
14
- '\n');
269
+ if (msgLevel === 'debug' && DEBUG_SAMPLE_N > 1) {
270
+ debugCounter = (debugCounter + 1) >>> 0;
271
+ if (debugCounter % DEBUG_SAMPLE_N !== 0) {
272
+ metricsState.sampled++;
273
+ return;
274
+ }
275
+ }
276
+ const tc = getTraceContext();
277
+ const traceFields = {};
278
+ if (tc?.traceId)
279
+ traceFields.trace_id = tc.traceId;
280
+ if (tc?.spanId)
281
+ traceFields.span_id = tc.spanId;
282
+ const safe = fields ? redact(fields) : undefined;
283
+ const line = JSON.stringify({
284
+ level: msgLevel,
285
+ time: new Date().toISOString(),
286
+ ...bound,
287
+ ...traceFields,
288
+ msg,
289
+ ...safe,
290
+ }) + '\n';
291
+ const ok = stream.write(line);
292
+ if (ok)
293
+ metricsState.emitted++;
294
+ else
295
+ metricsState.dropped++;
15
296
  };
16
297
  return {
298
+ level,
17
299
  debug: (msg, fields) => emit('debug', msg, fields),
18
300
  info: (msg, fields) => emit('info', msg, fields),
19
301
  warn: (msg, fields) => emit('warn', msg, fields),
20
302
  error: (msg, fields) => emit('error', msg, fields),
303
+ fatal: (msg, fields) => emit('fatal', msg, fields),
304
+ with: (fields) => makeLogger({ ...bound, ...redact(fields) }, level, stream),
305
+ metrics: () => devLogMetrics(),
21
306
  };
22
307
  }
23
308
  //# sourceMappingURL=logging.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,qCAAqC;AACrC,EAAE;AACF,kDAAkD;AAIlD,MAAM,KAAK,GAAY,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1D,SAAS,SAAS,CAAC,QAAe,EAAE,WAAkB;IACpD,OAAO,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAC/D,CAAC;AAID,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,QAAe,MAAM;IACjE,MAAM,IAAI,GAAG,CAAC,QAAe,EAAE,GAAW,EAAE,MAAgC,EAAE,EAAE;QAC9E,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC;YAAE,OAAO;QACxC,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,GAAG,MAAM,EAAE,CAAC;YAC1F,IAAI,CACP,CAAC;IACJ,CAAC,CAAC;IACF,OAAO;QACL,KAAK,EAAE,CAAC,GAAW,EAAE,MAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC;QACpF,IAAI,EAAE,CAAC,GAAW,EAAE,MAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC;QAClF,IAAI,EAAE,CAAC,GAAW,EAAE,MAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC;QAClF,KAAK,EAAE,CAAC,GAAW,EAAE,MAAgC,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,MAAM,CAAC;KACrF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"logging.js","sourceRoot":"","sources":["../src/logging.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { AuditClient } from './audit.js';
2
+ /** Render dev-log + (optional) audit counters in Prometheus text format. */
3
+ export declare function renderObservabilityMetrics(audit?: AuditClient): string;
4
+ //# sourceMappingURL=metrics.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAwB9C,4EAA4E;AAC5E,wBAAgB,0BAA0B,CAAC,KAAK,CAAC,EAAE,WAAW,GAAG,MAAM,CAuBtE"}
@@ -0,0 +1,43 @@
1
+ // Copyright (C) 2026 Garudex Labs. All Rights Reserved.
2
+ // Caracal, a product of Garudex Labs
3
+ //
4
+ // Prometheus text-format renderer for Caracal counter snapshots.
5
+ import { devLogMetrics } from './logging.js';
6
+ function renderCounters(counters) {
7
+ const lines = [];
8
+ for (const c of counters) {
9
+ lines.push(`# HELP ${c.name} ${c.help}`);
10
+ lines.push(`# TYPE ${c.name} counter`);
11
+ lines.push(`${c.name} ${c.value}`);
12
+ }
13
+ return lines.join('\n') + '\n';
14
+ }
15
+ function renderGauges(gauges) {
16
+ const lines = [];
17
+ for (const g of gauges) {
18
+ lines.push(`# HELP ${g.name} ${g.help}`);
19
+ lines.push(`# TYPE ${g.name} gauge`);
20
+ lines.push(`${g.name} ${g.value}`);
21
+ }
22
+ return lines.join('\n') + '\n';
23
+ }
24
+ /** Render dev-log + (optional) audit counters in Prometheus text format. */
25
+ export function renderObservabilityMetrics(audit) {
26
+ const log = devLogMetrics();
27
+ const counters = [
28
+ { name: 'caracal_log_emitted_total', help: 'Dev log records emitted', value: log.emitted },
29
+ { name: 'caracal_log_dropped_total', help: 'Dev log records dropped due to backpressure', value: log.dropped },
30
+ { name: 'caracal_log_sampled_total', help: 'Debug log records dropped by sampler', value: log.sampled },
31
+ ];
32
+ if (audit) {
33
+ const a = audit.snapshot();
34
+ counters.push({ name: 'caracal_audit_emitted_total', help: 'Audit events accepted into buffer', value: a.emitted }, { name: 'caracal_audit_dropped_total', help: 'Audit events dropped due to full buffer', value: a.dropped }, { name: 'caracal_audit_persisted_total', help: 'Audit events spilled to disk for later replay', value: a.persisted }, { name: 'caracal_audit_drained_total', help: 'Audit events replayed from disk', value: a.drained }, { name: 'caracal_audit_sink_errors_total', help: 'Audit sink (XADD) errors', value: a.sink_errors });
35
+ const gauges = [
36
+ { name: 'caracal_audit_queue_depth', help: 'Audit buffer depth', value: a.queue_depth },
37
+ { name: 'caracal_audit_queue_cap', help: 'Audit buffer capacity', value: a.queue_cap },
38
+ ];
39
+ return renderCounters(counters) + renderGauges(gauges);
40
+ }
41
+ return renderCounters(counters);
42
+ }
43
+ //# sourceMappingURL=metrics.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ type Log = {
2
+ error?: (msg: string, meta?: Record<string, unknown>) => void;
3
+ };
4
+ type FastifyLike = {
5
+ addHook: (name: string, handler: (...args: unknown[]) => unknown) => void;
6
+ };
7
+ export declare function initNodeTelemetry(serviceName: string, log?: Log): () => Promise<void>;
8
+ export declare function instrumentFastifyApp(app: FastifyLike, serviceName: string): void;
9
+ export {};
10
+ //# sourceMappingURL=telemetry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.d.ts","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"AAWA,KAAK,GAAG,GAAG;IAAE,KAAK,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAA;CAAE,CAAA;AAC5E,KAAK,WAAW,GAAG;IACjB,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,KAAK,IAAI,CAAA;CAC1E,CAAA;AAID,wBAAgB,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAmBrF;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,GAAG,IAAI,CAyChF"}
@@ -0,0 +1,98 @@
1
+ // Copyright (C) 2026 Garudex Labs. All Rights Reserved.
2
+ // Caracal, a product of Garudex Labs
3
+ //
4
+ // OpenTelemetry bootstrap helpers for Node.js services.
5
+ import { context, propagation, SpanKind, SpanStatusCode, trace } from '@opentelemetry/api';
6
+ import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
7
+ import { resourceFromAttributes } from '@opentelemetry/resources';
8
+ import { BatchSpanProcessor } from '@opentelemetry/sdk-trace-base';
9
+ import { NodeTracerProvider } from '@opentelemetry/sdk-trace-node';
10
+ const spanKey = Symbol('caracal.otel.span');
11
+ export function initNodeTelemetry(serviceName, log) {
12
+ const endpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT?.trim();
13
+ if (!endpoint)
14
+ return async () => { };
15
+ const protocol = process.env.OTEL_EXPORTER_OTLP_PROTOCOL?.trim();
16
+ if (protocol && protocol !== 'http/protobuf') {
17
+ throw new Error(`unsupported OTEL_EXPORTER_OTLP_PROTOCOL ${protocol}`);
18
+ }
19
+ const provider = new NodeTracerProvider({
20
+ resource: resourceFromAttributes(resourceAttributes(serviceName)),
21
+ spanProcessors: [new BatchSpanProcessor(new OTLPTraceExporter({ url: traceUrl(endpoint) }))],
22
+ });
23
+ provider.register();
24
+ return async () => {
25
+ try {
26
+ await provider.shutdown();
27
+ }
28
+ catch (err) {
29
+ log?.error?.('telemetry shutdown failed', { err });
30
+ }
31
+ };
32
+ }
33
+ export function instrumentFastifyApp(app, serviceName) {
34
+ const tracer = trace.getTracer(serviceName);
35
+ app.addHook('onRequest', async (req) => {
36
+ const request = req;
37
+ const method = request.method ?? 'GET';
38
+ const path = String(request.url ?? '/').split('?')[0] || '/';
39
+ const parent = propagation.extract(context.active(), normalizeHeaders(request.headers ?? {}));
40
+ request[spanKey] = tracer.startSpan(`${method} ${path}`, {
41
+ kind: SpanKind.SERVER,
42
+ attributes: {
43
+ 'http.request.method': method,
44
+ 'url.path': path,
45
+ },
46
+ }, parent);
47
+ });
48
+ app.addHook('onResponse', async (req, reply) => {
49
+ const request = req;
50
+ const response = reply;
51
+ const span = request[spanKey];
52
+ if (!span)
53
+ return;
54
+ const statusCode = response.statusCode ?? 200;
55
+ span.setAttribute('http.response.status_code', statusCode);
56
+ if (statusCode >= 500) {
57
+ span.setStatus({ code: SpanStatusCode.ERROR });
58
+ }
59
+ span.end();
60
+ });
61
+ app.addHook('onError', async (req, _reply, err) => {
62
+ const request = req;
63
+ const span = request[spanKey];
64
+ if (!span)
65
+ return;
66
+ if (err instanceof Error) {
67
+ span.recordException(err);
68
+ }
69
+ span.setStatus({ code: SpanStatusCode.ERROR });
70
+ });
71
+ }
72
+ function traceUrl(endpoint) {
73
+ const trimmed = endpoint.replace(/\/+$/, '');
74
+ return trimmed.endsWith('/v1/traces') ? trimmed : `${trimmed}/v1/traces`;
75
+ }
76
+ function normalizeHeaders(headers) {
77
+ const out = {};
78
+ for (const [key, value] of Object.entries(headers)) {
79
+ if (Array.isArray(value)) {
80
+ out[key] = value.join(',');
81
+ }
82
+ else if (typeof value === 'string') {
83
+ out[key] = value;
84
+ }
85
+ }
86
+ return out;
87
+ }
88
+ function resourceAttributes(serviceName) {
89
+ const attrs = { 'service.name': serviceName };
90
+ for (const raw of (process.env.OTEL_RESOURCE_ATTRIBUTES ?? '').split(',')) {
91
+ const [key, value] = raw.split('=', 2);
92
+ if (key?.trim() && value?.trim()) {
93
+ attrs[key.trim()] = value.trim();
94
+ }
95
+ }
96
+ return attrs;
97
+ }
98
+ //# sourceMappingURL=telemetry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"telemetry.js","sourceRoot":"","sources":["../src/telemetry.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@caracalai/core",
3
- "version": "0.1.2",
3
+ "version": "0.1.4-rc.1",
4
4
  "description": "Caracal SDK foundation: logging, config, errors.",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://github.com/Garudex-Labs/caracal",
@@ -22,30 +22,34 @@
22
22
  ".": {
23
23
  "import": "./dist/index.js",
24
24
  "types": "./dist/index.d.ts"
25
- },
26
- "./cli": {
27
- "import": "./dist/cliconfig.js",
28
- "types": "./dist/cliconfig.d.ts"
29
25
  }
30
26
  },
31
27
  "files": [
32
28
  "dist",
33
- "README.md",
34
29
  "LICENSE"
35
30
  ],
36
31
  "publishConfig": {
37
32
  "access": "public"
38
33
  },
39
34
  "scripts": {
35
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
36
+ "prebuild": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
40
37
  "build": "tsc",
41
38
  "dev": "tsc --watch",
42
39
  "typecheck": "tsc --noEmit",
43
- "test": "vitest run --root ../../.. tests/typescript/unit/shared",
44
- "prepublishOnly": "tsc"
40
+ "test": "vitest run --root ../../.. tests/typescript/unit/shared tests/typescript/contract/interoperability",
41
+ "prepublishOnly": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\" && tsc"
45
42
  },
46
43
  "devDependencies": {
47
44
  "@types/node": "^24.12.2",
48
45
  "typescript": "^6.0.3",
49
46
  "vitest": "^4.1.6"
47
+ },
48
+ "dependencies": {
49
+ "@opentelemetry/api": "^1.9.1",
50
+ "@opentelemetry/exporter-trace-otlp-http": "^0.218.0",
51
+ "@opentelemetry/resources": "^2.7.1",
52
+ "@opentelemetry/sdk-trace-base": "^2.7.1",
53
+ "@opentelemetry/sdk-trace-node": "^2.7.1"
50
54
  }
51
55
  }
@@ -1,31 +0,0 @@
1
- import { CaracalError } from './errors.js';
2
- export declare const DEFAULT_API_URL = "http://localhost:3000";
3
- export declare const DEFAULT_COORDINATOR_URL = "http://localhost:4000";
4
- export interface Credential {
5
- env: string;
6
- resource: string;
7
- }
8
- export interface OptionalCredential extends Credential {
9
- on_failure: 'warn' | 'error';
10
- }
11
- export interface McpGovernance {
12
- mode: 'block' | 'log';
13
- }
14
- export interface CliConfig {
15
- zone_url: string;
16
- zone_id: string;
17
- application_id: string;
18
- app_client_secret: string;
19
- continue_on_failure?: boolean;
20
- credentials?: Credential[];
21
- optional_credentials?: OptionalCredential[];
22
- mcp_governance?: McpGovernance;
23
- }
24
- export declare function resolveCliConfigPath(env?: NodeJS.ProcessEnv): string | undefined;
25
- export declare class ServiceUrlMissingError extends CaracalError {
26
- readonly envKey: string;
27
- readonly nodeEnv: string;
28
- constructor(envKey: string, nodeEnv: string);
29
- }
30
- export declare function resolveServiceUrl(envKey: string, devDefault: string): string;
31
- //# sourceMappingURL=cliconfig.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cliconfig.d.ts","sourceRoot":"","sources":["../src/cliconfig.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,eAAO,MAAM,eAAe,0BAA0B,CAAC;AACvD,eAAO,MAAM,uBAAuB,0BAA0B,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAmB,SAAQ,UAAU;IACpD,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,OAAO,GAAG,KAAK,CAAC;CACvB;AAED,MAAM,WAAW,SAAS;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,oBAAoB,CAAC,EAAE,kBAAkB,EAAE,CAAC;IAC5C,cAAc,CAAC,EAAE,aAAa,CAAC;CAChC;AAKD,wBAAgB,oBAAoB,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,MAAM,GAAG,SAAS,CAc7F;AAED,qBAAa,sBAAuB,SAAQ,YAAY;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;gBACb,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAQ5C;AAID,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ5E"}