@logbrew/sdk 0.1.19 → 0.1.21
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/core.cjs +23 -8
- package/index.d.ts +10 -0
- package/issue-stack.cjs +28 -1
- package/package.json +1 -1
package/core.cjs
CHANGED
|
@@ -133,7 +133,8 @@ const {
|
|
|
133
133
|
|
|
134
134
|
const {
|
|
135
135
|
javascriptStackEvidence,
|
|
136
|
-
validateIssueStackFrames
|
|
136
|
+
validateIssueStackFrames,
|
|
137
|
+
validateNativeStackFrames
|
|
137
138
|
} = buildIssueStackHelpers({ SdkError });
|
|
138
139
|
const {
|
|
139
140
|
MAX_ISSUE_BREADCRUMBS,
|
|
@@ -1211,19 +1212,28 @@ function normalizeStoredRecord(record) {
|
|
|
1211
1212
|
if (!event.attributes || Array.isArray(event.attributes) || typeof event.attributes !== "object") {
|
|
1212
1213
|
throw invalidStoredRecord();
|
|
1213
1214
|
}
|
|
1215
|
+
if (JSON.stringify(event) !== serializedEvent || utf8ByteLength(serializedEvent) !== eventBytes) {
|
|
1216
|
+
throw invalidStoredRecord();
|
|
1217
|
+
}
|
|
1218
|
+
const context = event.attributes.context;
|
|
1219
|
+
const recoveredEvent = context && !Array.isArray(context) && typeof context === "object"
|
|
1220
|
+
&& context.schemaVersion === undefined
|
|
1221
|
+
? { ...event, attributes: { ...event.attributes, context: { schemaVersion: 1, ...context } } }
|
|
1222
|
+
: event;
|
|
1214
1223
|
const normalizedEvent = {
|
|
1215
|
-
type:
|
|
1216
|
-
id:
|
|
1217
|
-
timestamp:
|
|
1218
|
-
attributes: validator(
|
|
1224
|
+
type: recoveredEvent.type,
|
|
1225
|
+
id: recoveredEvent.id,
|
|
1226
|
+
timestamp: recoveredEvent.timestamp,
|
|
1227
|
+
attributes: validator(recoveredEvent.attributes)
|
|
1219
1228
|
};
|
|
1220
|
-
|
|
1229
|
+
const normalizedSerializedEvent = JSON.stringify(normalizedEvent);
|
|
1230
|
+
if (normalizedSerializedEvent !== JSON.stringify(recoveredEvent)) {
|
|
1221
1231
|
throw invalidStoredRecord();
|
|
1222
1232
|
}
|
|
1223
1233
|
return {
|
|
1224
1234
|
event: cloneEvent(normalizedEvent),
|
|
1225
|
-
eventBytes,
|
|
1226
|
-
serializedEvent
|
|
1235
|
+
eventBytes: utf8ByteLength(normalizedSerializedEvent),
|
|
1236
|
+
serializedEvent: normalizedSerializedEvent
|
|
1227
1237
|
};
|
|
1228
1238
|
} catch (error) {
|
|
1229
1239
|
if (error instanceof SdkError && error.code === "persistence_error") {
|
|
@@ -2256,6 +2266,9 @@ function cloneSpanLinks(links) {
|
|
|
2256
2266
|
|
|
2257
2267
|
function cloneEvent(event) {
|
|
2258
2268
|
const attributes = { ...event.attributes, ...cloneIssueDiagnostics(event.attributes) };
|
|
2269
|
+
if (Array.isArray(event.attributes.nativeStackFrames)) {
|
|
2270
|
+
attributes.nativeStackFrames = event.attributes.nativeStackFrames.map((frame) => ({ ...frame }));
|
|
2271
|
+
}
|
|
2259
2272
|
if (event.attributes.metadata !== undefined) {
|
|
2260
2273
|
attributes.metadata = { ...event.attributes.metadata };
|
|
2261
2274
|
}
|
|
@@ -2295,11 +2308,13 @@ function validateIssue(attributes) {
|
|
|
2295
2308
|
requireNonEmpty("issue title", attributes.title);
|
|
2296
2309
|
const level = normalizeSeverity("issue level", attributes.level);
|
|
2297
2310
|
const stackFrames = validateIssueStackFrames(attributes.stackFrames);
|
|
2311
|
+
const nativeStackFrames = validateNativeStackFrames(attributes.nativeStackFrames);
|
|
2298
2312
|
return withMetadata({
|
|
2299
2313
|
title: attributes.title,
|
|
2300
2314
|
level,
|
|
2301
2315
|
...(attributes.message !== undefined ? { message: attributes.message } : {}),
|
|
2302
2316
|
...(stackFrames !== undefined ? { stackFrames } : {}),
|
|
2317
|
+
...(nativeStackFrames !== undefined ? { nativeStackFrames } : {}),
|
|
2303
2318
|
...validateIssueDiagnostics(attributes)
|
|
2304
2319
|
}, attributes.metadata, attributes.context);
|
|
2305
2320
|
}
|
package/index.d.ts
CHANGED
|
@@ -389,6 +389,14 @@ export type IssueDiagnosticEvidence = {
|
|
|
389
389
|
truncatedFields?: string[];
|
|
390
390
|
};
|
|
391
391
|
|
|
392
|
+
export type NativeStackArchitecture = "arm" | "arm64" | "arm64e" | "x86" | "x86_64";
|
|
393
|
+
|
|
394
|
+
export type NativeStackFrame = {
|
|
395
|
+
imageUuid: string;
|
|
396
|
+
architecture: NativeStackArchitecture;
|
|
397
|
+
instructionOffset: string;
|
|
398
|
+
};
|
|
399
|
+
|
|
392
400
|
/** Public issue event attributes. */
|
|
393
401
|
export type IssueAttributes = {
|
|
394
402
|
title: string;
|
|
@@ -399,6 +407,8 @@ export type IssueAttributes = {
|
|
|
399
407
|
exceptionChain?: IssueExceptionChain;
|
|
400
408
|
/** Ordered privacy-bounded generated frames, capped at 32. */
|
|
401
409
|
stackFrames?: IssueStackFrame[];
|
|
410
|
+
/** Ordered native image-relative frames for exact release symbolication, capped at 32. */
|
|
411
|
+
nativeStackFrames?: NativeStackFrame[];
|
|
402
412
|
/** Oldest-to-newest issue history, capped at the most recent 64 entries. */
|
|
403
413
|
breadcrumbs?: IssueBreadcrumb[];
|
|
404
414
|
/** True when older or invalid history was omitted before capture. */
|
package/issue-stack.cjs
CHANGED
|
@@ -4,6 +4,9 @@ const MAX_ISSUE_STACK_FRAMES = 32;
|
|
|
4
4
|
const MAX_ISSUE_STACK_FUNCTION_LENGTH = 256;
|
|
5
5
|
const MAX_ISSUE_STACK_MODULE_LENGTH = 512;
|
|
6
6
|
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;
|
|
7
|
+
const NATIVE_IMAGE_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/u;
|
|
8
|
+
const NATIVE_OFFSET_PATTERN = /^[0-9a-f]{16}$/u;
|
|
9
|
+
const NATIVE_ARCHITECTURES = new Set(["arm", "arm64", "arm64e", "x86", "x86_64"]);
|
|
7
10
|
const LOCAL_ABSOLUTE_PATH_PATTERN = /(?:^|\s)(?:\/(?:Users|home|private|tmp|var|Volumes)\/|[A-Za-z]:[\\/])/u;
|
|
8
11
|
const DEBUG_ID_REGISTRY = Symbol.for("logbrew.release-artifact.debug-ids");
|
|
9
12
|
|
|
@@ -87,7 +90,31 @@ function buildIssueStackHelpers({ SdkError }) {
|
|
|
87
90
|
});
|
|
88
91
|
}
|
|
89
92
|
|
|
90
|
-
|
|
93
|
+
function validateNativeStackFrames(frames) {
|
|
94
|
+
if (frames === undefined) {
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
if (!Array.isArray(frames) || frames.length === 0 || frames.length > MAX_ISSUE_STACK_FRAMES) {
|
|
98
|
+
throw new SdkError("validation_error", `issue nativeStackFrames must contain 1-${MAX_ISSUE_STACK_FRAMES} frames`);
|
|
99
|
+
}
|
|
100
|
+
return frames.map((frame) => {
|
|
101
|
+
const keys = frame && !Array.isArray(frame) && typeof frame === "object" ? Object.keys(frame) : [];
|
|
102
|
+
if (keys.length !== 3
|
|
103
|
+
|| !keys.every((key) => ["imageUuid", "architecture", "instructionOffset"].includes(key))
|
|
104
|
+
|| typeof frame.imageUuid !== "string" || !NATIVE_IMAGE_UUID_PATTERN.test(frame.imageUuid)
|
|
105
|
+
|| !NATIVE_ARCHITECTURES.has(frame.architecture)
|
|
106
|
+
|| typeof frame.instructionOffset !== "string" || !NATIVE_OFFSET_PATTERN.test(frame.instructionOffset)) {
|
|
107
|
+
throw new SdkError("validation_error", "issue native stack frame is invalid");
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
imageUuid: frame.imageUuid,
|
|
111
|
+
architecture: frame.architecture,
|
|
112
|
+
instructionOffset: frame.instructionOffset
|
|
113
|
+
};
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return { javascriptStackEvidence, validateIssueStackFrames, validateNativeStackFrames };
|
|
91
118
|
}
|
|
92
119
|
|
|
93
120
|
function parseJavaScriptStackFrame(rawLine) {
|