@logbrew/sdk 0.1.3 → 0.1.4
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 +336 -2
- package/examples/real-user-smoke.cjs +15 -1
- package/examples/real-user-smoke.mjs +15 -1
- package/index.cjs +1358 -28
- package/index.d.cts +461 -6
- package/index.d.ts +461 -6
- package/index.js +13 -0
- package/issue-stack.cjs +149 -0
- package/opentelemetry.cjs +1080 -0
- package/package.json +28 -1
- package/release-artifacts-build.cjs +227 -0
- package/release-artifacts-common.js +82 -0
- package/release-artifacts-symbolication.js +550 -0
- package/release-artifacts-upload.js +380 -0
- package/release-artifacts.js +766 -0
- package/support-ticket.cjs +175 -0
- package/trace-context.cjs +217 -0
- package/vite-release-artifacts.cjs +152 -0
- package/vite-release-artifacts.d.cts +44 -0
- package/vite-release-artifacts.d.ts +44 -0
- package/vite-release-artifacts.js +6 -0
package/issue-stack.cjs
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const MAX_ISSUE_STACK_FRAMES = 32;
|
|
4
|
+
const SAFE_DEBUG_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
|
|
5
|
+
const LOCAL_ABSOLUTE_PATH_PATTERN = /^(?:\/(?:Users|home|private|tmp|var|Volumes)\/|[A-Za-z]:[\\/])/u;
|
|
6
|
+
|
|
7
|
+
function buildIssueStackHelpers({ SdkError }) {
|
|
8
|
+
function javascriptStackFrames(stack, debugIdMap) {
|
|
9
|
+
if (typeof stack !== "string" || stack.trim() === "") {
|
|
10
|
+
return [];
|
|
11
|
+
}
|
|
12
|
+
const frames = [];
|
|
13
|
+
for (const rawLine of stack.split(/\r?\n/u)) {
|
|
14
|
+
const parsed = parseJavaScriptStackFrame(rawLine);
|
|
15
|
+
if (parsed) {
|
|
16
|
+
const debugId = debugIdForFrame(parsed.filename, debugIdMap, SdkError);
|
|
17
|
+
frames.push({ ...parsed, ...(debugId ? { debugId } : {}) });
|
|
18
|
+
if (frames.length === MAX_ISSUE_STACK_FRAMES) {
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return frames;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function validateIssueStackFrames(stackFrames) {
|
|
27
|
+
if (stackFrames === undefined) {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
if (!Array.isArray(stackFrames) || stackFrames.length === 0 || stackFrames.length > MAX_ISSUE_STACK_FRAMES) {
|
|
31
|
+
throw new SdkError("validation_error", `issue stackFrames must contain 1-${MAX_ISSUE_STACK_FRAMES} frames`);
|
|
32
|
+
}
|
|
33
|
+
return stackFrames.map((frame) => {
|
|
34
|
+
if (!frame || Array.isArray(frame) || typeof frame !== "object") {
|
|
35
|
+
throw new SdkError("validation_error", "issue stack frame must be an object");
|
|
36
|
+
}
|
|
37
|
+
if (typeof frame.filename !== "string") {
|
|
38
|
+
throw new SdkError("validation_error", "issue stack frame filename is invalid");
|
|
39
|
+
}
|
|
40
|
+
const filename = sanitizeFrameFilename(frame.filename);
|
|
41
|
+
if (!filename || filename.length > 2048 || hasControlCharacter(filename)) {
|
|
42
|
+
throw new SdkError("validation_error", "issue stack frame filename is invalid");
|
|
43
|
+
}
|
|
44
|
+
const line = positiveIntegerFromText(frame.line);
|
|
45
|
+
const column = positiveIntegerFromText(frame.column);
|
|
46
|
+
if (line === null || column === null || line > 2147483647 || column > 2147483647) {
|
|
47
|
+
throw new SdkError("validation_error", "issue stack frame coordinates must be positive integers");
|
|
48
|
+
}
|
|
49
|
+
const debugId = frame.debugId === undefined
|
|
50
|
+
? undefined
|
|
51
|
+
: typeof frame.debugId === "string" && SAFE_DEBUG_ID_PATTERN.test(frame.debugId.trim())
|
|
52
|
+
? frame.debugId.trim().toLowerCase()
|
|
53
|
+
: null;
|
|
54
|
+
if (debugId === null) {
|
|
55
|
+
throw new SdkError("validation_error", "issue stack frame debugId is invalid");
|
|
56
|
+
}
|
|
57
|
+
return { filename, line, column, ...(debugId ? { debugId } : {}) };
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return { javascriptStackFrames, validateIssueStackFrames };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function parseJavaScriptStackFrame(rawLine) {
|
|
65
|
+
const line = typeof rawLine === "string" ? rawLine.trim() : "";
|
|
66
|
+
if (!line) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
let location = line;
|
|
70
|
+
if (location.startsWith("at ")) {
|
|
71
|
+
location = location.slice(3).trim();
|
|
72
|
+
if (location.endsWith(")") && location.includes("(")) {
|
|
73
|
+
location = location.slice(location.lastIndexOf("(") + 1, -1);
|
|
74
|
+
}
|
|
75
|
+
} else if (location.includes("@")) {
|
|
76
|
+
location = location.slice(location.lastIndexOf("@") + 1);
|
|
77
|
+
}
|
|
78
|
+
const parts = location.split(":");
|
|
79
|
+
if (parts.length < 3) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
const column = positiveIntegerFromText(parts.pop());
|
|
83
|
+
const lineNumber = positiveIntegerFromText(parts.pop());
|
|
84
|
+
const filename = sanitizeFrameFilename(parts.join(":"));
|
|
85
|
+
if (!filename || lineNumber === null || column === null) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
return { filename, line: lineNumber, column };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function positiveIntegerFromText(value) {
|
|
92
|
+
const text = String(value);
|
|
93
|
+
if (!/^[1-9][0-9]*$/u.test(text)) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const parsed = Number(text);
|
|
97
|
+
return Number.isSafeInteger(parsed) ? parsed : null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function sanitizeFrameFilename(value) {
|
|
101
|
+
let filename = String(value ?? "").trim();
|
|
102
|
+
if (!filename) {
|
|
103
|
+
return "";
|
|
104
|
+
}
|
|
105
|
+
filename = filename.split("?", 1)[0].split("#", 1)[0];
|
|
106
|
+
if (filename.startsWith("file://")) {
|
|
107
|
+
filename = filename.slice("file://".length);
|
|
108
|
+
}
|
|
109
|
+
if (LOCAL_ABSOLUTE_PATH_PATTERN.test(filename)) {
|
|
110
|
+
return basename(filename);
|
|
111
|
+
}
|
|
112
|
+
return filename;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function debugIdForFrame(filename, debugIdMap, SdkError) {
|
|
116
|
+
if (debugIdMap === undefined || debugIdMap === null) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
if (!debugIdMap || Array.isArray(debugIdMap) || typeof debugIdMap !== "object") {
|
|
120
|
+
throw new SdkError("validation_error", "debugIdMap must be an object");
|
|
121
|
+
}
|
|
122
|
+
const normalizedFilename = sanitizeFrameFilename(filename);
|
|
123
|
+
const aliases = new Set([normalizedFilename, basename(normalizedFilename)].filter(Boolean));
|
|
124
|
+
for (const [candidate, debugId] of Object.entries(debugIdMap)) {
|
|
125
|
+
if (typeof debugId !== "string" || !SAFE_DEBUG_ID_PATTERN.test(debugId.trim())) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
const normalizedCandidate = sanitizeFrameFilename(candidate);
|
|
129
|
+
if (aliases.has(normalizedCandidate) || aliases.has(basename(normalizedCandidate))) {
|
|
130
|
+
return debugId.trim().toLowerCase();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function basename(value) {
|
|
137
|
+
const normalized = String(value).replace(/\\/gu, "/").replace(/\/+$/u, "");
|
|
138
|
+
const marker = normalized.lastIndexOf("/");
|
|
139
|
+
return marker === -1 ? normalized : normalized.slice(marker + 1);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function hasControlCharacter(value) {
|
|
143
|
+
return Array.from(value).some((character) => {
|
|
144
|
+
const code = character.codePointAt(0);
|
|
145
|
+
return code !== undefined && (code <= 31 || code === 127);
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
module.exports = { buildIssueStackHelpers };
|