@oconde/radar 0.2.0 → 0.3.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/CHANGELOG.md +10 -0
- package/README.md +8 -0
- package/dist/{client-CZHtsQAd.d.cts → client-BB-to8cr.d.cts} +11 -0
- package/dist/{client-DbBsXgpj.d.ts → client-BS798K3S.d.ts} +11 -0
- package/dist/index.cjs +177 -14
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +186 -23
- package/dist/index.js.map +1 -1
- package/dist/nest/index.cjs +177 -14
- package/dist/nest/index.cjs.map +1 -1
- package/dist/nest/index.d.cts +1 -1
- package/dist/nest/index.d.ts +1 -1
- package/dist/nest/index.js +186 -23
- package/dist/nest/index.js.map +1 -1
- package/dist/sveltekit/index.cjs +179 -16
- package/dist/sveltekit/index.cjs.map +1 -1
- package/dist/sveltekit/index.d.cts +1 -1
- package/dist/sveltekit/index.d.ts +1 -1
- package/dist/sveltekit/index.js +190 -27
- package/dist/sveltekit/index.js.map +1 -1
- package/package.json +3 -3
package/dist/nest/index.js
CHANGED
|
@@ -78,10 +78,10 @@ function requestIdFrom(incoming) {
|
|
|
78
78
|
// src/client.ts
|
|
79
79
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
80
80
|
import { hostname } from "os";
|
|
81
|
-
import { performance as
|
|
81
|
+
import { performance as performance4 } from "perf_hooks";
|
|
82
82
|
|
|
83
83
|
// src/express.ts
|
|
84
|
-
import { performance } from "perf_hooks";
|
|
84
|
+
import { performance as performance2 } from "perf_hooks";
|
|
85
85
|
|
|
86
86
|
// src/redact.ts
|
|
87
87
|
import { createHash, createHmac, randomBytes } from "crypto";
|
|
@@ -281,7 +281,10 @@ function requestPath(req) {
|
|
|
281
281
|
}
|
|
282
282
|
function requestRoute(req, route) {
|
|
283
283
|
if (route) return route;
|
|
284
|
-
|
|
284
|
+
if (typeof req.route?.path !== "string") return void 0;
|
|
285
|
+
const base = typeof req.baseUrl === "string" ? req.baseUrl.replace(/\/+$/, "") : "";
|
|
286
|
+
if (!base) return req.route.path;
|
|
287
|
+
return req.route.path === "/" ? base : `${base}${req.route.path}`;
|
|
285
288
|
}
|
|
286
289
|
var ROUTE_PARAM = /^:([A-Za-z_$][\w$]*)/;
|
|
287
290
|
function pathSegments(value) {
|
|
@@ -401,7 +404,7 @@ function createMiddleware(logger) {
|
|
|
401
404
|
let context;
|
|
402
405
|
try {
|
|
403
406
|
const requestId = requestIdFrom(headerValue(req.headers["x-request-id"]));
|
|
404
|
-
context = { requestId, startedAt:
|
|
407
|
+
context = { requestId, startedAt: performance2.now(), req };
|
|
405
408
|
res.setHeader("x-request-id", requestId);
|
|
406
409
|
if (logger.shouldLogRequest(req)) res.once("finish", () => logger.logHttpRequest(context, res.statusCode));
|
|
407
410
|
} catch {
|
|
@@ -415,6 +418,12 @@ function createMiddleware(logger) {
|
|
|
415
418
|
// src/options.ts
|
|
416
419
|
var DEFAULT_ENDPOINT = "https://radar-ingest.oconde.dev";
|
|
417
420
|
var LEVELS = ["debug", "info", "warn", "error"];
|
|
421
|
+
function resolveTraceFetch(value) {
|
|
422
|
+
if (!value) return { enabled: false, propagateTo: [] };
|
|
423
|
+
if (value === true) return { enabled: true, propagateTo: [] };
|
|
424
|
+
const targets2 = Array.isArray(value.propagateTo) ? value.propagateTo : [];
|
|
425
|
+
return { enabled: true, propagateTo: targets2.filter((target) => typeof target === "string" ? target.trim() !== "" : target instanceof RegExp) };
|
|
426
|
+
}
|
|
418
427
|
function resolveOptions(options = {}, env = process.env) {
|
|
419
428
|
const key = options.key?.trim() || void 0;
|
|
420
429
|
return {
|
|
@@ -430,6 +439,7 @@ function resolveOptions(options = {}, env = process.env) {
|
|
|
430
439
|
logRequests: options.logRequests ?? true,
|
|
431
440
|
ignorePaths: options.ignorePaths ?? ["/healthz", "/health"],
|
|
432
441
|
captureUnhandled: options.captureUnhandled ?? true,
|
|
442
|
+
traceFetch: resolveTraceFetch(options.traceFetch),
|
|
433
443
|
debug: options.debug ?? false
|
|
434
444
|
};
|
|
435
445
|
}
|
|
@@ -497,6 +507,7 @@ var IDENTIFIER = "[A-Za-z_$][\\w$]*";
|
|
|
497
507
|
var MAX_LINES_UP = 400;
|
|
498
508
|
var MAX_HEADER_LINES = 6;
|
|
499
509
|
var MAX_NAME_LENGTH = 100;
|
|
510
|
+
var MAX_COMMENT_LINES = 40;
|
|
500
511
|
var CONTROL_BLOCK = /^\s*(?:\}\s*)?(?:if|else|for|while|do|switch|try|catch|finally|with)\b/;
|
|
501
512
|
var CLASS_BODY = new RegExp(`\\bclass\\s+${IDENTIFIER}`);
|
|
502
513
|
var MARKUP_BOUNDARY = /<\/?(?:script|style|template)\b/i;
|
|
@@ -509,8 +520,58 @@ var NAME_PATTERNS = [
|
|
|
509
520
|
];
|
|
510
521
|
var METHOD_PATTERN = new RegExp(`^\\s*(?:(?:export|default|public|private|protected|static|async|override|readonly|get|set)\\s+)*\\*?\\s*(${IDENTIFIER})\\s*(?:<[^>]*>)?\\s*\\([^]*\\)\\s*(?::\\s*[^{]+)?$`);
|
|
511
522
|
var ANONYMOUS_FUNCTION = /\bfunction\b|=>/;
|
|
512
|
-
|
|
513
|
-
|
|
523
|
+
var STRING_LITERAL = /(["'`])(?:\\.|(?!\1)[^\\])*\1/g;
|
|
524
|
+
function lineCommentAt(text, from) {
|
|
525
|
+
for (let index = text.indexOf("//", from); index >= 0; index = text.indexOf("//", index + 1)) {
|
|
526
|
+
if (index === 0 || text[index - 1] !== ":") return index;
|
|
527
|
+
}
|
|
528
|
+
return -1;
|
|
529
|
+
}
|
|
530
|
+
function blockCommentAt(text, from) {
|
|
531
|
+
for (let index = text.indexOf("/*", from); index >= 0; index = text.indexOf("/*", index + 1)) {
|
|
532
|
+
if (index === 0 || text[index - 1] !== "\\") return index;
|
|
533
|
+
}
|
|
534
|
+
return -1;
|
|
535
|
+
}
|
|
536
|
+
function stripComments(text, insideComment, closesLater) {
|
|
537
|
+
let code = "";
|
|
538
|
+
let position = 0;
|
|
539
|
+
let inside = insideComment;
|
|
540
|
+
while (position < text.length) {
|
|
541
|
+
if (inside) {
|
|
542
|
+
const end = text.indexOf("*/", position);
|
|
543
|
+
if (end < 0) return { code, insideComment: true };
|
|
544
|
+
inside = false;
|
|
545
|
+
position = end + 2;
|
|
546
|
+
continue;
|
|
547
|
+
}
|
|
548
|
+
const block = blockCommentAt(text, position);
|
|
549
|
+
const line = lineCommentAt(text, position);
|
|
550
|
+
if (line >= 0 && (block < 0 || line < block)) return { code: code + text.slice(position, line), insideComment: false };
|
|
551
|
+
if (block < 0) return { code: code + text.slice(position), insideComment: false };
|
|
552
|
+
if (text.indexOf("*/", block + 2) < 0 && !closesLater()) {
|
|
553
|
+
code += text.slice(position, block + 2);
|
|
554
|
+
position = block + 2;
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
code += text.slice(position, block);
|
|
558
|
+
inside = true;
|
|
559
|
+
position = block + 2;
|
|
560
|
+
}
|
|
561
|
+
return { code, insideComment: inside };
|
|
562
|
+
}
|
|
563
|
+
function codeLines(lines, from, start, column) {
|
|
564
|
+
const plain = lines.slice(from, start + 1).map((line) => line.replace(STRING_LITERAL, '""'));
|
|
565
|
+
const closesWithin = (index) => plain.slice(index + 1, index + 1 + MAX_COMMENT_LINES).some((line) => line.includes("*/"));
|
|
566
|
+
const result = [];
|
|
567
|
+
let insideComment = false;
|
|
568
|
+
for (let index = 0; index < plain.length; index++) {
|
|
569
|
+
const text = index === plain.length - 1 && column ? (lines[start] ?? "").slice(0, Math.max(0, column - 1)).replace(STRING_LITERAL, '""') : plain[index] ?? "";
|
|
570
|
+
const stripped = stripComments(text, insideComment, () => closesWithin(index));
|
|
571
|
+
insideComment = stripped.insideComment;
|
|
572
|
+
result.push(stripped.code);
|
|
573
|
+
}
|
|
574
|
+
return result;
|
|
514
575
|
}
|
|
515
576
|
function parenBalance(text) {
|
|
516
577
|
let balance = 0;
|
|
@@ -520,11 +581,11 @@ function parenBalance(text) {
|
|
|
520
581
|
}
|
|
521
582
|
return balance;
|
|
522
583
|
}
|
|
523
|
-
function headerOf(
|
|
584
|
+
function headerOf(code, index, prefix) {
|
|
524
585
|
let header = prefix;
|
|
525
586
|
for (let previous = index - 1; previous >= 0 && previous >= index - MAX_HEADER_LINES; previous--) {
|
|
526
587
|
if (header.trim() !== "" && parenBalance(header) >= 0) break;
|
|
527
|
-
header = `${
|
|
588
|
+
header = `${code[previous] ?? ""} ${header}`;
|
|
528
589
|
}
|
|
529
590
|
return header;
|
|
530
591
|
}
|
|
@@ -539,11 +600,12 @@ function nameIn(header) {
|
|
|
539
600
|
function enclosingFunctionName(lines, line, column) {
|
|
540
601
|
const start = line - 1;
|
|
541
602
|
if (start < 0 || start >= lines.length) return void 0;
|
|
603
|
+
const from = Math.max(0, start - MAX_LINES_UP - MAX_HEADER_LINES);
|
|
604
|
+
const cleaned = codeLines(lines, from, start, column);
|
|
542
605
|
let depth = 0;
|
|
543
606
|
for (let index = start; index >= 0 && index >= start - MAX_LINES_UP; index--) {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
const code = codeOnly(index === start && column ? raw.slice(0, Math.max(0, column - 1)) : raw);
|
|
607
|
+
if (index < start && MARKUP_BOUNDARY.test(lines[index] ?? "")) return void 0;
|
|
608
|
+
const code = cleaned[index - from] ?? "";
|
|
547
609
|
for (let position = code.length - 1; position >= 0; position--) {
|
|
548
610
|
const char = code[position];
|
|
549
611
|
if (char === "}") {
|
|
@@ -553,7 +615,7 @@ function enclosingFunctionName(lines, line, column) {
|
|
|
553
615
|
depth -= 1;
|
|
554
616
|
continue;
|
|
555
617
|
}
|
|
556
|
-
const header = headerOf(
|
|
618
|
+
const header = headerOf(cleaned, index - from, code.slice(0, position));
|
|
557
619
|
if (CLASS_BODY.test(header)) return void 0;
|
|
558
620
|
if (CONTROL_BLOCK.test(header)) continue;
|
|
559
621
|
const name = nameIn(header);
|
|
@@ -795,20 +857,110 @@ function safeStringify(value) {
|
|
|
795
857
|
}
|
|
796
858
|
}
|
|
797
859
|
|
|
798
|
-
// src/transport.ts
|
|
799
|
-
import { promisify } from "util";
|
|
800
|
-
import { gzip } from "zlib";
|
|
801
|
-
|
|
802
860
|
// src/util.ts
|
|
803
|
-
import { performance as
|
|
861
|
+
import { performance as performance3 } from "perf_hooks";
|
|
804
862
|
function describeError(error) {
|
|
805
863
|
return error instanceof Error ? error.message : String(error);
|
|
806
864
|
}
|
|
807
865
|
function elapsedSince(startedAt) {
|
|
808
|
-
return Math.round(
|
|
866
|
+
return Math.round(performance3.now() - startedAt);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
// src/trace-fetch.ts
|
|
870
|
+
var WRAPPED = /* @__PURE__ */ Symbol.for("@oconde/radar.fetch");
|
|
871
|
+
var REQUEST_ID_HEADER = "x-request-id";
|
|
872
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
873
|
+
var TELEGRAM_BOT = /^bot\d{5,}:[\w-]{20,}$/;
|
|
874
|
+
var TOKEN_LIKE = /^[\w\-.~+=]{20,}$/;
|
|
875
|
+
function secretSegment(segment) {
|
|
876
|
+
if (UUID.test(segment)) return false;
|
|
877
|
+
if (TELEGRAM_BOT.test(segment) || looksLikeCredential(segment)) return true;
|
|
878
|
+
return TOKEN_LIKE.test(segment) && /[A-Za-z]/.test(segment) && /\d/.test(segment);
|
|
879
|
+
}
|
|
880
|
+
function outboundPath(pathname, mode) {
|
|
881
|
+
if (mode === "none") return pathname;
|
|
882
|
+
return pathname.split("/").map((segment) => {
|
|
883
|
+
let decoded = segment;
|
|
884
|
+
try {
|
|
885
|
+
decoded = decodeURIComponent(segment);
|
|
886
|
+
} catch {
|
|
887
|
+
decoded = segment;
|
|
888
|
+
}
|
|
889
|
+
return secretSegment(decoded) ? maskValue(decoded, false) : segment;
|
|
890
|
+
}).join("/");
|
|
891
|
+
}
|
|
892
|
+
function failureOf(error) {
|
|
893
|
+
const message = describeError(error);
|
|
894
|
+
const cause = error instanceof Error ? error.cause : void 0;
|
|
895
|
+
const detail = typeof cause?.code === "string" ? cause.code : typeof cause?.message === "string" ? cause.message : "";
|
|
896
|
+
return detail && !message.includes(detail) ? `${message} (${detail})` : message;
|
|
897
|
+
}
|
|
898
|
+
function urlOf(input) {
|
|
899
|
+
try {
|
|
900
|
+
if (typeof input === "string") return new URL(input);
|
|
901
|
+
if (input instanceof URL) return input;
|
|
902
|
+
return new URL(input.url);
|
|
903
|
+
} catch {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
}
|
|
907
|
+
function originOf(value) {
|
|
908
|
+
try {
|
|
909
|
+
return new URL(value).origin;
|
|
910
|
+
} catch {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
function targets(url, target) {
|
|
915
|
+
if (target instanceof RegExp) return target.test(url.host);
|
|
916
|
+
const wanted = target.trim().toLowerCase();
|
|
917
|
+
if (wanted.startsWith(".")) return url.hostname.toLowerCase().endsWith(wanted);
|
|
918
|
+
return url.host.toLowerCase() === wanted || url.hostname.toLowerCase() === wanted;
|
|
919
|
+
}
|
|
920
|
+
function isPlainObject(value) {
|
|
921
|
+
if (value === null || typeof value !== "object") return false;
|
|
922
|
+
const prototype = Object.getPrototypeOf(value);
|
|
923
|
+
return prototype === Object.prototype || prototype === null;
|
|
924
|
+
}
|
|
925
|
+
function withRequestId(input, init, requestId) {
|
|
926
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
927
|
+
if (headers.has(REQUEST_ID_HEADER)) return [input, init];
|
|
928
|
+
headers.set(REQUEST_ID_HEADER, requestId);
|
|
929
|
+
if (init === void 0 || isPlainObject(init)) return [input, { ...init, headers }];
|
|
930
|
+
return [new Request(input, init), { headers }];
|
|
931
|
+
}
|
|
932
|
+
function traceFetch(config) {
|
|
933
|
+
const current = globalThis.fetch;
|
|
934
|
+
if (typeof current !== "function" || current[WRAPPED]) return () => void 0;
|
|
935
|
+
const original = current;
|
|
936
|
+
const radarOrigin = originOf(config.endpoint);
|
|
937
|
+
const traced = async (input, init) => {
|
|
938
|
+
const url = urlOf(input);
|
|
939
|
+
if (!url || url.origin === radarOrigin || url.protocol !== "http:" && url.protocol !== "https:") return original(input, init);
|
|
940
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
941
|
+
const context = currentContext();
|
|
942
|
+
const [nextInput, nextInit] = context && config.propagateTo.some((target) => targets(url, target)) ? withRequestId(input, init, context.requestId) : [input, init];
|
|
943
|
+
const attrs = { method, host: url.host, path: outboundPath(url.pathname, config.redact) };
|
|
944
|
+
const started = performance.now();
|
|
945
|
+
try {
|
|
946
|
+
const response = await original(nextInput, nextInit);
|
|
947
|
+
config.record(response.status >= 500 ? "error" : response.status >= 400 ? "warn" : "info", { ...attrs, status: response.status, durationMs: elapsedSince(started) });
|
|
948
|
+
return response;
|
|
949
|
+
} catch (error) {
|
|
950
|
+
config.record("error", { ...attrs, error: failureOf(error), durationMs: elapsedSince(started) });
|
|
951
|
+
throw error;
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
Object.defineProperty(traced, WRAPPED, { value: original });
|
|
955
|
+
globalThis.fetch = traced;
|
|
956
|
+
return () => {
|
|
957
|
+
if (globalThis.fetch === traced) globalThis.fetch = original;
|
|
958
|
+
};
|
|
809
959
|
}
|
|
810
960
|
|
|
811
961
|
// src/transport.ts
|
|
962
|
+
import { promisify } from "util";
|
|
963
|
+
import { gzip } from "zlib";
|
|
812
964
|
var gzipAsync = promisify(gzip);
|
|
813
965
|
var MAX_BATCH_BYTES = 9e5;
|
|
814
966
|
var GZIP_THRESHOLD_BYTES = 8192;
|
|
@@ -1036,7 +1188,7 @@ function withTimeout(promise, ms) {
|
|
|
1036
1188
|
|
|
1037
1189
|
// src/version.ts
|
|
1038
1190
|
var SDK_NAME = "@oconde/radar";
|
|
1039
|
-
var SDK_VERSION = true ? "0.
|
|
1191
|
+
var SDK_VERSION = true ? "0.3.0" : "0.0.0-dev";
|
|
1040
1192
|
|
|
1041
1193
|
// src/client.ts
|
|
1042
1194
|
var MAX_CHECK_IN_DURATION_MS = 7 * 864e5;
|
|
@@ -1048,6 +1200,7 @@ var RadarClient = class {
|
|
|
1048
1200
|
initialized = false;
|
|
1049
1201
|
closed = false;
|
|
1050
1202
|
captured = /* @__PURE__ */ new WeakSet();
|
|
1203
|
+
restoreFetch = null;
|
|
1051
1204
|
get isEnabled() {
|
|
1052
1205
|
return this.transport !== null && !this.closed;
|
|
1053
1206
|
}
|
|
@@ -1075,6 +1228,14 @@ var RadarClient = class {
|
|
|
1075
1228
|
});
|
|
1076
1229
|
}
|
|
1077
1230
|
if (this.options.captureUnhandled && (this.transport || this.options.console)) installProcessHandlers(this);
|
|
1231
|
+
if (this.options.traceFetch.enabled && (this.transport || this.options.console)) {
|
|
1232
|
+
this.restoreFetch = traceFetch({
|
|
1233
|
+
endpoint: this.options.endpoint,
|
|
1234
|
+
propagateTo: this.options.traceFetch.propagateTo,
|
|
1235
|
+
redact: this.options.redact,
|
|
1236
|
+
record: (level, attrs) => this.safely(() => this.emitLog(level, "http.client", attrs))
|
|
1237
|
+
});
|
|
1238
|
+
}
|
|
1078
1239
|
} catch (error) {
|
|
1079
1240
|
this.debugWarn(`radar.init falhou: ${describeError(error)}`);
|
|
1080
1241
|
}
|
|
@@ -1118,7 +1279,7 @@ var RadarClient = class {
|
|
|
1118
1279
|
}
|
|
1119
1280
|
async track(name, fn, data) {
|
|
1120
1281
|
const execute = async () => {
|
|
1121
|
-
const started =
|
|
1282
|
+
const started = performance4.now();
|
|
1122
1283
|
try {
|
|
1123
1284
|
const result = await fn();
|
|
1124
1285
|
this.info(name, { ...data, durationMs: elapsedSince(started), ok: true });
|
|
@@ -1130,10 +1291,10 @@ var RadarClient = class {
|
|
|
1130
1291
|
}
|
|
1131
1292
|
};
|
|
1132
1293
|
if (currentContext()) return execute();
|
|
1133
|
-
return runWithContext({ requestId: randomUUID2(), startedAt:
|
|
1294
|
+
return runWithContext({ requestId: randomUUID2(), startedAt: performance4.now() }, execute);
|
|
1134
1295
|
}
|
|
1135
1296
|
withContext(fn, options = {}) {
|
|
1136
|
-
return runWithContext({ requestId: requestIdFrom(options.requestId), startedAt:
|
|
1297
|
+
return runWithContext({ requestId: requestIdFrom(options.requestId), startedAt: performance4.now() }, fn);
|
|
1137
1298
|
}
|
|
1138
1299
|
async checkIn(slug, status, options = {}) {
|
|
1139
1300
|
try {
|
|
@@ -1161,7 +1322,7 @@ var RadarClient = class {
|
|
|
1161
1322
|
}
|
|
1162
1323
|
async cron(slug, fn) {
|
|
1163
1324
|
const checkInId = randomUUID2();
|
|
1164
|
-
const started =
|
|
1325
|
+
const started = performance4.now();
|
|
1165
1326
|
const execute = async () => {
|
|
1166
1327
|
await this.checkIn(slug, "in_progress", { checkInId });
|
|
1167
1328
|
try {
|
|
@@ -1211,6 +1372,8 @@ var RadarClient = class {
|
|
|
1211
1372
|
async close(timeoutMs = 2e3) {
|
|
1212
1373
|
if (this.closed) return;
|
|
1213
1374
|
await this.flush(timeoutMs);
|
|
1375
|
+
this.restoreFetch?.();
|
|
1376
|
+
this.restoreFetch = null;
|
|
1214
1377
|
this.closed = true;
|
|
1215
1378
|
this.transport?.stop();
|
|
1216
1379
|
}
|