@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.cjs
CHANGED
|
@@ -305,7 +305,10 @@ function requestPath(req) {
|
|
|
305
305
|
}
|
|
306
306
|
function requestRoute(req, route) {
|
|
307
307
|
if (route) return route;
|
|
308
|
-
|
|
308
|
+
if (typeof req.route?.path !== "string") return void 0;
|
|
309
|
+
const base = typeof req.baseUrl === "string" ? req.baseUrl.replace(/\/+$/, "") : "";
|
|
310
|
+
if (!base) return req.route.path;
|
|
311
|
+
return req.route.path === "/" ? base : `${base}${req.route.path}`;
|
|
309
312
|
}
|
|
310
313
|
var ROUTE_PARAM = /^:([A-Za-z_$][\w$]*)/;
|
|
311
314
|
function pathSegments(value) {
|
|
@@ -439,6 +442,12 @@ function createMiddleware(logger) {
|
|
|
439
442
|
// src/options.ts
|
|
440
443
|
var DEFAULT_ENDPOINT = "https://radar-ingest.oconde.dev";
|
|
441
444
|
var LEVELS = ["debug", "info", "warn", "error"];
|
|
445
|
+
function resolveTraceFetch(value) {
|
|
446
|
+
if (!value) return { enabled: false, propagateTo: [] };
|
|
447
|
+
if (value === true) return { enabled: true, propagateTo: [] };
|
|
448
|
+
const targets2 = Array.isArray(value.propagateTo) ? value.propagateTo : [];
|
|
449
|
+
return { enabled: true, propagateTo: targets2.filter((target) => typeof target === "string" ? target.trim() !== "" : target instanceof RegExp) };
|
|
450
|
+
}
|
|
442
451
|
function resolveOptions(options = {}, env = process.env) {
|
|
443
452
|
const key = options.key?.trim() || void 0;
|
|
444
453
|
return {
|
|
@@ -454,6 +463,7 @@ function resolveOptions(options = {}, env = process.env) {
|
|
|
454
463
|
logRequests: options.logRequests ?? true,
|
|
455
464
|
ignorePaths: options.ignorePaths ?? ["/healthz", "/health"],
|
|
456
465
|
captureUnhandled: options.captureUnhandled ?? true,
|
|
466
|
+
traceFetch: resolveTraceFetch(options.traceFetch),
|
|
457
467
|
debug: options.debug ?? false
|
|
458
468
|
};
|
|
459
469
|
}
|
|
@@ -521,6 +531,7 @@ var IDENTIFIER = "[A-Za-z_$][\\w$]*";
|
|
|
521
531
|
var MAX_LINES_UP = 400;
|
|
522
532
|
var MAX_HEADER_LINES = 6;
|
|
523
533
|
var MAX_NAME_LENGTH = 100;
|
|
534
|
+
var MAX_COMMENT_LINES = 40;
|
|
524
535
|
var CONTROL_BLOCK = /^\s*(?:\}\s*)?(?:if|else|for|while|do|switch|try|catch|finally|with)\b/;
|
|
525
536
|
var CLASS_BODY = new RegExp(`\\bclass\\s+${IDENTIFIER}`);
|
|
526
537
|
var MARKUP_BOUNDARY = /<\/?(?:script|style|template)\b/i;
|
|
@@ -533,8 +544,58 @@ var NAME_PATTERNS = [
|
|
|
533
544
|
];
|
|
534
545
|
var METHOD_PATTERN = new RegExp(`^\\s*(?:(?:export|default|public|private|protected|static|async|override|readonly|get|set)\\s+)*\\*?\\s*(${IDENTIFIER})\\s*(?:<[^>]*>)?\\s*\\([^]*\\)\\s*(?::\\s*[^{]+)?$`);
|
|
535
546
|
var ANONYMOUS_FUNCTION = /\bfunction\b|=>/;
|
|
536
|
-
|
|
537
|
-
|
|
547
|
+
var STRING_LITERAL = /(["'`])(?:\\.|(?!\1)[^\\])*\1/g;
|
|
548
|
+
function lineCommentAt(text, from) {
|
|
549
|
+
for (let index = text.indexOf("//", from); index >= 0; index = text.indexOf("//", index + 1)) {
|
|
550
|
+
if (index === 0 || text[index - 1] !== ":") return index;
|
|
551
|
+
}
|
|
552
|
+
return -1;
|
|
553
|
+
}
|
|
554
|
+
function blockCommentAt(text, from) {
|
|
555
|
+
for (let index = text.indexOf("/*", from); index >= 0; index = text.indexOf("/*", index + 1)) {
|
|
556
|
+
if (index === 0 || text[index - 1] !== "\\") return index;
|
|
557
|
+
}
|
|
558
|
+
return -1;
|
|
559
|
+
}
|
|
560
|
+
function stripComments(text, insideComment, closesLater) {
|
|
561
|
+
let code = "";
|
|
562
|
+
let position = 0;
|
|
563
|
+
let inside = insideComment;
|
|
564
|
+
while (position < text.length) {
|
|
565
|
+
if (inside) {
|
|
566
|
+
const end = text.indexOf("*/", position);
|
|
567
|
+
if (end < 0) return { code, insideComment: true };
|
|
568
|
+
inside = false;
|
|
569
|
+
position = end + 2;
|
|
570
|
+
continue;
|
|
571
|
+
}
|
|
572
|
+
const block = blockCommentAt(text, position);
|
|
573
|
+
const line = lineCommentAt(text, position);
|
|
574
|
+
if (line >= 0 && (block < 0 || line < block)) return { code: code + text.slice(position, line), insideComment: false };
|
|
575
|
+
if (block < 0) return { code: code + text.slice(position), insideComment: false };
|
|
576
|
+
if (text.indexOf("*/", block + 2) < 0 && !closesLater()) {
|
|
577
|
+
code += text.slice(position, block + 2);
|
|
578
|
+
position = block + 2;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
code += text.slice(position, block);
|
|
582
|
+
inside = true;
|
|
583
|
+
position = block + 2;
|
|
584
|
+
}
|
|
585
|
+
return { code, insideComment: inside };
|
|
586
|
+
}
|
|
587
|
+
function codeLines(lines, from, start, column) {
|
|
588
|
+
const plain = lines.slice(from, start + 1).map((line) => line.replace(STRING_LITERAL, '""'));
|
|
589
|
+
const closesWithin = (index) => plain.slice(index + 1, index + 1 + MAX_COMMENT_LINES).some((line) => line.includes("*/"));
|
|
590
|
+
const result = [];
|
|
591
|
+
let insideComment = false;
|
|
592
|
+
for (let index = 0; index < plain.length; index++) {
|
|
593
|
+
const text = index === plain.length - 1 && column ? (lines[start] ?? "").slice(0, Math.max(0, column - 1)).replace(STRING_LITERAL, '""') : plain[index] ?? "";
|
|
594
|
+
const stripped = stripComments(text, insideComment, () => closesWithin(index));
|
|
595
|
+
insideComment = stripped.insideComment;
|
|
596
|
+
result.push(stripped.code);
|
|
597
|
+
}
|
|
598
|
+
return result;
|
|
538
599
|
}
|
|
539
600
|
function parenBalance(text) {
|
|
540
601
|
let balance = 0;
|
|
@@ -544,11 +605,11 @@ function parenBalance(text) {
|
|
|
544
605
|
}
|
|
545
606
|
return balance;
|
|
546
607
|
}
|
|
547
|
-
function headerOf(
|
|
608
|
+
function headerOf(code, index, prefix) {
|
|
548
609
|
let header = prefix;
|
|
549
610
|
for (let previous = index - 1; previous >= 0 && previous >= index - MAX_HEADER_LINES; previous--) {
|
|
550
611
|
if (header.trim() !== "" && parenBalance(header) >= 0) break;
|
|
551
|
-
header = `${
|
|
612
|
+
header = `${code[previous] ?? ""} ${header}`;
|
|
552
613
|
}
|
|
553
614
|
return header;
|
|
554
615
|
}
|
|
@@ -563,11 +624,12 @@ function nameIn(header) {
|
|
|
563
624
|
function enclosingFunctionName(lines, line, column) {
|
|
564
625
|
const start = line - 1;
|
|
565
626
|
if (start < 0 || start >= lines.length) return void 0;
|
|
627
|
+
const from = Math.max(0, start - MAX_LINES_UP - MAX_HEADER_LINES);
|
|
628
|
+
const cleaned = codeLines(lines, from, start, column);
|
|
566
629
|
let depth = 0;
|
|
567
630
|
for (let index = start; index >= 0 && index >= start - MAX_LINES_UP; index--) {
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
const code = codeOnly(index === start && column ? raw.slice(0, Math.max(0, column - 1)) : raw);
|
|
631
|
+
if (index < start && MARKUP_BOUNDARY.test(lines[index] ?? "")) return void 0;
|
|
632
|
+
const code = cleaned[index - from] ?? "";
|
|
571
633
|
for (let position = code.length - 1; position >= 0; position--) {
|
|
572
634
|
const char = code[position];
|
|
573
635
|
if (char === "}") {
|
|
@@ -577,7 +639,7 @@ function enclosingFunctionName(lines, line, column) {
|
|
|
577
639
|
depth -= 1;
|
|
578
640
|
continue;
|
|
579
641
|
}
|
|
580
|
-
const header = headerOf(
|
|
642
|
+
const header = headerOf(cleaned, index - from, code.slice(0, position));
|
|
581
643
|
if (CLASS_BODY.test(header)) return void 0;
|
|
582
644
|
if (CONTROL_BLOCK.test(header)) continue;
|
|
583
645
|
const name = nameIn(header);
|
|
@@ -819,10 +881,6 @@ function safeStringify(value) {
|
|
|
819
881
|
}
|
|
820
882
|
}
|
|
821
883
|
|
|
822
|
-
// src/transport.ts
|
|
823
|
-
var import_node_util2 = require("util");
|
|
824
|
-
var import_node_zlib = require("zlib");
|
|
825
|
-
|
|
826
884
|
// src/util.ts
|
|
827
885
|
var import_node_perf_hooks2 = require("perf_hooks");
|
|
828
886
|
function describeError(error) {
|
|
@@ -832,7 +890,101 @@ function elapsedSince(startedAt) {
|
|
|
832
890
|
return Math.round(import_node_perf_hooks2.performance.now() - startedAt);
|
|
833
891
|
}
|
|
834
892
|
|
|
893
|
+
// src/trace-fetch.ts
|
|
894
|
+
var WRAPPED = /* @__PURE__ */ Symbol.for("@oconde/radar.fetch");
|
|
895
|
+
var REQUEST_ID_HEADER = "x-request-id";
|
|
896
|
+
var UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
897
|
+
var TELEGRAM_BOT = /^bot\d{5,}:[\w-]{20,}$/;
|
|
898
|
+
var TOKEN_LIKE = /^[\w\-.~+=]{20,}$/;
|
|
899
|
+
function secretSegment(segment) {
|
|
900
|
+
if (UUID.test(segment)) return false;
|
|
901
|
+
if (TELEGRAM_BOT.test(segment) || looksLikeCredential(segment)) return true;
|
|
902
|
+
return TOKEN_LIKE.test(segment) && /[A-Za-z]/.test(segment) && /\d/.test(segment);
|
|
903
|
+
}
|
|
904
|
+
function outboundPath(pathname, mode) {
|
|
905
|
+
if (mode === "none") return pathname;
|
|
906
|
+
return pathname.split("/").map((segment) => {
|
|
907
|
+
let decoded = segment;
|
|
908
|
+
try {
|
|
909
|
+
decoded = decodeURIComponent(segment);
|
|
910
|
+
} catch {
|
|
911
|
+
decoded = segment;
|
|
912
|
+
}
|
|
913
|
+
return secretSegment(decoded) ? maskValue(decoded, false) : segment;
|
|
914
|
+
}).join("/");
|
|
915
|
+
}
|
|
916
|
+
function failureOf(error) {
|
|
917
|
+
const message = describeError(error);
|
|
918
|
+
const cause = error instanceof Error ? error.cause : void 0;
|
|
919
|
+
const detail = typeof cause?.code === "string" ? cause.code : typeof cause?.message === "string" ? cause.message : "";
|
|
920
|
+
return detail && !message.includes(detail) ? `${message} (${detail})` : message;
|
|
921
|
+
}
|
|
922
|
+
function urlOf(input) {
|
|
923
|
+
try {
|
|
924
|
+
if (typeof input === "string") return new URL(input);
|
|
925
|
+
if (input instanceof URL) return input;
|
|
926
|
+
return new URL(input.url);
|
|
927
|
+
} catch {
|
|
928
|
+
return null;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function originOf(value) {
|
|
932
|
+
try {
|
|
933
|
+
return new URL(value).origin;
|
|
934
|
+
} catch {
|
|
935
|
+
return null;
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
function targets(url, target) {
|
|
939
|
+
if (target instanceof RegExp) return target.test(url.host);
|
|
940
|
+
const wanted = target.trim().toLowerCase();
|
|
941
|
+
if (wanted.startsWith(".")) return url.hostname.toLowerCase().endsWith(wanted);
|
|
942
|
+
return url.host.toLowerCase() === wanted || url.hostname.toLowerCase() === wanted;
|
|
943
|
+
}
|
|
944
|
+
function isPlainObject(value) {
|
|
945
|
+
if (value === null || typeof value !== "object") return false;
|
|
946
|
+
const prototype = Object.getPrototypeOf(value);
|
|
947
|
+
return prototype === Object.prototype || prototype === null;
|
|
948
|
+
}
|
|
949
|
+
function withRequestId(input, init, requestId) {
|
|
950
|
+
const headers = new Headers(init?.headers ?? (input instanceof Request ? input.headers : void 0));
|
|
951
|
+
if (headers.has(REQUEST_ID_HEADER)) return [input, init];
|
|
952
|
+
headers.set(REQUEST_ID_HEADER, requestId);
|
|
953
|
+
if (init === void 0 || isPlainObject(init)) return [input, { ...init, headers }];
|
|
954
|
+
return [new Request(input, init), { headers }];
|
|
955
|
+
}
|
|
956
|
+
function traceFetch(config) {
|
|
957
|
+
const current = globalThis.fetch;
|
|
958
|
+
if (typeof current !== "function" || current[WRAPPED]) return () => void 0;
|
|
959
|
+
const original = current;
|
|
960
|
+
const radarOrigin = originOf(config.endpoint);
|
|
961
|
+
const traced = async (input, init) => {
|
|
962
|
+
const url = urlOf(input);
|
|
963
|
+
if (!url || url.origin === radarOrigin || url.protocol !== "http:" && url.protocol !== "https:") return original(input, init);
|
|
964
|
+
const method = (init?.method ?? (input instanceof Request ? input.method : "GET")).toUpperCase();
|
|
965
|
+
const context = currentContext();
|
|
966
|
+
const [nextInput, nextInit] = context && config.propagateTo.some((target) => targets(url, target)) ? withRequestId(input, init, context.requestId) : [input, init];
|
|
967
|
+
const attrs = { method, host: url.host, path: outboundPath(url.pathname, config.redact) };
|
|
968
|
+
const started = performance.now();
|
|
969
|
+
try {
|
|
970
|
+
const response = await original(nextInput, nextInit);
|
|
971
|
+
config.record(response.status >= 500 ? "error" : response.status >= 400 ? "warn" : "info", { ...attrs, status: response.status, durationMs: elapsedSince(started) });
|
|
972
|
+
return response;
|
|
973
|
+
} catch (error) {
|
|
974
|
+
config.record("error", { ...attrs, error: failureOf(error), durationMs: elapsedSince(started) });
|
|
975
|
+
throw error;
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
Object.defineProperty(traced, WRAPPED, { value: original });
|
|
979
|
+
globalThis.fetch = traced;
|
|
980
|
+
return () => {
|
|
981
|
+
if (globalThis.fetch === traced) globalThis.fetch = original;
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
|
|
835
985
|
// src/transport.ts
|
|
986
|
+
var import_node_util2 = require("util");
|
|
987
|
+
var import_node_zlib = require("zlib");
|
|
836
988
|
var gzipAsync = (0, import_node_util2.promisify)(import_node_zlib.gzip);
|
|
837
989
|
var MAX_BATCH_BYTES = 9e5;
|
|
838
990
|
var GZIP_THRESHOLD_BYTES = 8192;
|
|
@@ -1060,7 +1212,7 @@ function withTimeout(promise, ms) {
|
|
|
1060
1212
|
|
|
1061
1213
|
// src/version.ts
|
|
1062
1214
|
var SDK_NAME = "@oconde/radar";
|
|
1063
|
-
var SDK_VERSION = true ? "0.
|
|
1215
|
+
var SDK_VERSION = true ? "0.3.0" : "0.0.0-dev";
|
|
1064
1216
|
|
|
1065
1217
|
// src/client.ts
|
|
1066
1218
|
var MAX_CHECK_IN_DURATION_MS = 7 * 864e5;
|
|
@@ -1072,6 +1224,7 @@ var RadarClient = class {
|
|
|
1072
1224
|
initialized = false;
|
|
1073
1225
|
closed = false;
|
|
1074
1226
|
captured = /* @__PURE__ */ new WeakSet();
|
|
1227
|
+
restoreFetch = null;
|
|
1075
1228
|
get isEnabled() {
|
|
1076
1229
|
return this.transport !== null && !this.closed;
|
|
1077
1230
|
}
|
|
@@ -1099,6 +1252,14 @@ var RadarClient = class {
|
|
|
1099
1252
|
});
|
|
1100
1253
|
}
|
|
1101
1254
|
if (this.options.captureUnhandled && (this.transport || this.options.console)) installProcessHandlers(this);
|
|
1255
|
+
if (this.options.traceFetch.enabled && (this.transport || this.options.console)) {
|
|
1256
|
+
this.restoreFetch = traceFetch({
|
|
1257
|
+
endpoint: this.options.endpoint,
|
|
1258
|
+
propagateTo: this.options.traceFetch.propagateTo,
|
|
1259
|
+
redact: this.options.redact,
|
|
1260
|
+
record: (level, attrs) => this.safely(() => this.emitLog(level, "http.client", attrs))
|
|
1261
|
+
});
|
|
1262
|
+
}
|
|
1102
1263
|
} catch (error) {
|
|
1103
1264
|
this.debugWarn(`radar.init falhou: ${describeError(error)}`);
|
|
1104
1265
|
}
|
|
@@ -1235,6 +1396,8 @@ var RadarClient = class {
|
|
|
1235
1396
|
async close(timeoutMs = 2e3) {
|
|
1236
1397
|
if (this.closed) return;
|
|
1237
1398
|
await this.flush(timeoutMs);
|
|
1399
|
+
this.restoreFetch?.();
|
|
1400
|
+
this.restoreFetch = null;
|
|
1238
1401
|
this.closed = true;
|
|
1239
1402
|
this.transport?.stop();
|
|
1240
1403
|
}
|