@logbrew/sdk 0.1.38 → 0.1.39

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 (90) hide show
  1. package/automatic-delivery.cjs +271 -0
  2. package/batch-sender.cjs +164 -0
  3. package/bounded-number.cjs +34 -0
  4. package/browser-breadcrumbs.cjs +346 -136
  5. package/capture-support.cjs +100 -0
  6. package/client-options.cjs +292 -0
  7. package/client-report.cjs +232 -0
  8. package/client.cjs +447 -0
  9. package/console-arguments.cjs +151 -0
  10. package/console-capture.cjs +194 -0
  11. package/core.cjs +30 -2810
  12. package/delivery-health.cjs +133 -0
  13. package/error-causes.cjs +130 -0
  14. package/error-details.cjs +124 -0
  15. package/error-issue.cjs +187 -0
  16. package/event-clone.cjs +55 -0
  17. package/event-metadata.cjs +40 -0
  18. package/event-pipeline.cjs +325 -0
  19. package/event-queue.cjs +306 -0
  20. package/event-store.cjs +237 -0
  21. package/event-validation.cjs +159 -0
  22. package/examples/agent-timeline.cjs +57 -46
  23. package/examples/agent-timeline.mjs +41 -35
  24. package/examples/index.mjs +122 -94
  25. package/examples/readme-example.cjs +36 -27
  26. package/examples/readme-example.mjs +21 -17
  27. package/examples/real-user-smoke.cjs +41 -32
  28. package/examples/real-user-smoke.mjs +26 -22
  29. package/exception-chain.cjs +205 -0
  30. package/index.d.ts +144 -1076
  31. package/index.js +1 -1
  32. package/issue-exception.cjs +13 -8
  33. package/metric-validation.cjs +95 -0
  34. package/network-milestone.cjs +155 -0
  35. package/null-value.cjs +4 -0
  36. package/opentelemetry-bridge.cjs +330 -0
  37. package/opentelemetry-context.cjs +245 -0
  38. package/opentelemetry-exceptions.cjs +69 -0
  39. package/opentelemetry-keys.cjs +183 -0
  40. package/opentelemetry-span.cjs +286 -0
  41. package/opentelemetry-summary.cjs +213 -0
  42. package/opentelemetry-time.cjs +131 -0
  43. package/opentelemetry.cjs +99 -1068
  44. package/package.json +55 -1
  45. package/pino-destination.cjs +108 -0
  46. package/pino-record.cjs +237 -0
  47. package/product-action.cjs +163 -0
  48. package/provided-breadcrumbs.cjs +117 -0
  49. package/random-hex.cjs +29 -0
  50. package/react-native.js +1 -1
  51. package/recording-transport.cjs +68 -0
  52. package/release-artifacts-build.cjs +263 -84
  53. package/release-artifacts-common.js +347 -66
  54. package/release-artifacts-debug-id.js +178 -0
  55. package/release-artifacts-inspect.js +213 -0
  56. package/release-artifacts-issue-event.js +99 -0
  57. package/release-artifacts-manifest-artifact.js +107 -0
  58. package/release-artifacts-manifest.js +77 -0
  59. package/release-artifacts-mappings.js +265 -0
  60. package/release-artifacts-prepare.js +297 -0
  61. package/release-artifacts-source-context.js +210 -0
  62. package/release-artifacts-symbolication.js +272 -421
  63. package/release-artifacts-upload-files.js +122 -0
  64. package/release-artifacts-upload-request.js +246 -0
  65. package/release-artifacts-upload.js +155 -300
  66. package/release-artifacts-urls.js +49 -0
  67. package/release-artifacts.js +189 -662
  68. package/retry-delay.cjs +32 -0
  69. package/span-validation.cjs +191 -0
  70. package/stored-events.cjs +243 -0
  71. package/types/client.d.ts +67 -0
  72. package/types/delivery.d.ts +125 -0
  73. package/types/issues.d.ts +249 -0
  74. package/types/logging.d.ts +175 -0
  75. package/types/opentelemetry.d.ts +205 -0
  76. package/types/product.d.ts +128 -0
  77. package/types/recording-transport.d.ts +15 -0
  78. package/types/sdk-error.d.ts +9 -0
  79. package/types/telemetry.d.ts +171 -0
  80. package/types/trace-context.d.ts +110 -0
  81. package/types/transport-error.d.ts +10 -0
  82. package/utf8.cjs +37 -0
  83. package/validation.cjs +49 -1
  84. package/vite-release-artifacts-config.cjs +120 -0
  85. package/vite-release-artifacts.cjs +199 -99
  86. package/vite-release-artifacts.d.cts +65 -40
  87. package/vite-release-artifacts.d.ts +65 -40
  88. package/vite-release-artifacts.js +2 -2
  89. package/winston-info.cjs +205 -0
  90. package/winston.cjs +189 -289
@@ -0,0 +1,133 @@
1
+ /**
2
+ * @import { PauseReason } from "./automatic-delivery.cjs"
3
+ * @import { StatusClass } from "./batch-sender.cjs"
4
+ * @import { DropReason } from "./client-report.cjs"
5
+ * @import { DeliveryOutcome } from "./event-pipeline.cjs"
6
+ * @typedef {Readonly<{
7
+ * automaticDelivery: boolean,
8
+ * lifecycle: "active" | "shutting_down" | "closed",
9
+ * storage: "persistent" | "memory",
10
+ * queueEvents: number,
11
+ * queueBytes: number,
12
+ * hydratedEvents: number,
13
+ * hydratedBytes: number,
14
+ * droppedEvents: number,
15
+ * droppedByReason: Readonly<Record<DropReason, number>>,
16
+ * lastDropReason: DropReason | "none",
17
+ * scheduled: boolean,
18
+ * inFlight: boolean,
19
+ * coalesced: boolean,
20
+ * pendingOperations: number,
21
+ * lastOutcome: DeliveryOutcome,
22
+ * lastStatusClass: StatusClass,
23
+ * pausedReason: PauseReason,
24
+ * consecutiveFailures: number,
25
+ * retryDelayMs: number,
26
+ * flushes: number,
27
+ * failures: number,
28
+ * attempts: number,
29
+ * batches: number,
30
+ * acceptedEvents: number,
31
+ * lastAttemptAtUnixMs: number,
32
+ * lastAcceptedAtUnixMs: number,
33
+ * lastDroppedAtUnixMs: number
34
+ * }>} HealthState
35
+ */
36
+
37
+ const DELIVERY_HEALTH_SCHEMA_VERSION = 1;
38
+ const NONE = 0;
39
+ const HEALTH_KEYS = Object.freeze([
40
+ "schemaVersion",
41
+ "automaticDelivery",
42
+ "lifecycle",
43
+ "deliveryState",
44
+ "storage",
45
+ "queueEvents",
46
+ "queueBytes",
47
+ "hydratedEvents",
48
+ "hydratedBytes",
49
+ "droppedEvents",
50
+ "droppedByReason",
51
+ "lastDropReason",
52
+ "scheduled",
53
+ "inFlight",
54
+ "coalesced",
55
+ "pendingOperations",
56
+ "lastOutcome",
57
+ "lastStatusClass",
58
+ "pausedReason",
59
+ "consecutiveFailures",
60
+ "retryDelayMs",
61
+ "flushes",
62
+ "failures",
63
+ "attempts",
64
+ "batches",
65
+ "acceptedEvents",
66
+ "lastAttemptAtUnixMs",
67
+ "lastAcceptedAtUnixMs",
68
+ "lastDroppedAtUnixMs"
69
+ ]);
70
+
71
+ /**
72
+ * @param {boolean} closed
73
+ * @param {boolean} closing
74
+ * @returns {HealthState["lifecycle"]}
75
+ */
76
+ function lifecycleOf(closed, closing) {
77
+ if (closed) {
78
+ return "closed";
79
+ }
80
+ return closing ? "shutting_down" : "active";
81
+ }
82
+
83
+ /**
84
+ * @param {HealthState} state
85
+ * @returns {string | undefined}
86
+ */
87
+ function activeState(state) {
88
+ if (state.inFlight) {
89
+ return "in_flight";
90
+ }
91
+ if (state.retryDelayMs > NONE) {
92
+ return "retrying";
93
+ }
94
+ if (state.pausedReason !== "none") {
95
+ return "paused";
96
+ }
97
+ if (state.queueEvents > NONE) {
98
+ return state.scheduled ? "scheduled" : "queued";
99
+ }
100
+ return undefined;
101
+ }
102
+
103
+ /**
104
+ * @param {HealthState} state
105
+ * @returns {string}
106
+ */
107
+ function deliveryState(state) {
108
+ const active = activeState(state);
109
+ if (active !== undefined) {
110
+ return active;
111
+ }
112
+ if (state.lastOutcome === "accepted" || state.lastOutcome === "failed") {
113
+ return state.lastOutcome;
114
+ }
115
+ return state.droppedEvents > NONE ? "dropped" : "idle";
116
+ }
117
+
118
+ /**
119
+ * @param {HealthState} state
120
+ * @returns {Readonly<Record<string, unknown>>}
121
+ */
122
+ function deliveryHealthSnapshot(state) {
123
+ /** @type {Readonly<Record<string, unknown>>} */
124
+ const values = {
125
+ ...state,
126
+ deliveryState: deliveryState(state),
127
+ droppedByReason: Object.freeze({ ...state.droppedByReason }),
128
+ schemaVersion: DELIVERY_HEALTH_SCHEMA_VERSION
129
+ };
130
+ return Object.freeze(Object.fromEntries(HEALTH_KEYS.map((key) => [key, values[key]])));
131
+ }
132
+
133
+ module.exports = { deliveryHealthSnapshot, lifecycleOf };
@@ -0,0 +1,130 @@
1
+ const { errorCauseType, isObjectLike, safeProperty } = require("./error-details.cjs");
2
+
3
+ /**
4
+ * @typedef {{
5
+ * errorCauseCount?: number,
6
+ * errorCauseTypes?: string,
7
+ * errorCauseSources?: string,
8
+ * errorExceptionGroup?: true,
9
+ * errorCauseTruncated?: true
10
+ * }} ErrorCauseMetadata
11
+ */
12
+
13
+ const MAX_ERROR_CAUSES = 5;
14
+ const NO_CAUSES = 0;
15
+
16
+ class ErrorCauseCollector {
17
+ constructor() {
18
+ /** @type {Readonly<{ source: string, type: string }>[]} */
19
+ this.items = [];
20
+ /** @type {Set<object>} */
21
+ this.seen = new Set();
22
+ this.sawExceptionGroup = false;
23
+ this.truncated = false;
24
+ }
25
+
26
+ /**
27
+ * @param {unknown} value
28
+ * @param {string} source
29
+ * @returns {void}
30
+ */
31
+ collect(value, source) {
32
+ if (value === undefined || value === null) {
33
+ return;
34
+ }
35
+ if (this.items.length >= MAX_ERROR_CAUSES) {
36
+ this.truncated = true;
37
+ return;
38
+ }
39
+ if (!this.markSeen(value)) {
40
+ return;
41
+ }
42
+ this.items.push({ source, type: errorCauseType(value) });
43
+ this.collectNested(value);
44
+ }
45
+
46
+ /**
47
+ * @param {unknown} value
48
+ * @returns {boolean}
49
+ */
50
+ markSeen(value) {
51
+ if (!isObjectLike(value)) {
52
+ return true;
53
+ }
54
+ if (this.seen.has(value)) {
55
+ this.truncated = true;
56
+ return false;
57
+ }
58
+ this.seen.add(value);
59
+ return true;
60
+ }
61
+
62
+ /**
63
+ * @param {unknown} parent
64
+ * @returns {void}
65
+ */
66
+ collectNested(parent) {
67
+ if (!isObjectLike(parent)) {
68
+ return;
69
+ }
70
+ this.collectCause(parent);
71
+ this.collectErrors(parent);
72
+ }
73
+
74
+ /**
75
+ * @param {object} parent
76
+ * @returns {void}
77
+ */
78
+ collectCause(parent) {
79
+ const cause = safeProperty(parent, "cause");
80
+ if (!cause.available) {
81
+ this.truncated = true;
82
+ } else if (cause.value !== undefined && cause.value !== null) {
83
+ this.collect(cause.value, "cause");
84
+ }
85
+ }
86
+
87
+ /**
88
+ * @param {object} parent
89
+ * @returns {void}
90
+ */
91
+ collectErrors(parent) {
92
+ const errors = safeProperty(parent, "errors");
93
+ if (!errors.available) {
94
+ this.truncated = true;
95
+ } else if (Array.isArray(errors.value)) {
96
+ this.sawExceptionGroup = true;
97
+ /** @type {readonly unknown[]} */
98
+ const children = errors.value;
99
+ for (const [index, child] of children.entries()) {
100
+ this.collect(child, `errors[${index}]`);
101
+ }
102
+ }
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @param {unknown} error
108
+ * @returns {ErrorCauseMetadata}
109
+ */
110
+ function errorCauseMetadata(error) {
111
+ const collector = new ErrorCauseCollector();
112
+ if (isObjectLike(error)) {
113
+ collector.seen.add(error);
114
+ collector.collectNested(error);
115
+ }
116
+ if (collector.items.length === NO_CAUSES) {
117
+ return {};
118
+ }
119
+ return {
120
+ errorCauseCount: collector.items.length,
121
+
122
+ errorCauseTypes: collector.items.map((item) => item.type).join(","),
123
+
124
+ errorCauseSources: collector.items.map((item) => item.source).join(","),
125
+ ...(collector.sawExceptionGroup ? { errorExceptionGroup: true } : {}),
126
+ ...(collector.truncated ? { errorCauseTruncated: true } : {})
127
+ };
128
+ }
129
+
130
+ module.exports = { errorCauseMetadata };
@@ -0,0 +1,124 @@
1
+ const { stringOrUndefined } = require("./validation.cjs");
2
+
3
+ /**
4
+ * @typedef {{ available: true, value: unknown } | { available: false, value: undefined }} PropertyRead
5
+ * @typedef {{ name: string, message?: string | undefined, stack?: string | undefined }} ErrorDetails
6
+ */
7
+
8
+ const TYPE_NAME_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]{0,63}$/u;
9
+ const BUILTIN_ERROR_NAMES = new Set([
10
+ "AggregateError",
11
+ "Error",
12
+ "EvalError",
13
+ "RangeError",
14
+ "ReferenceError",
15
+ "SyntaxError",
16
+ "TypeError",
17
+ "URIError"
18
+ ]);
19
+
20
+ /**
21
+ * @param {unknown} value
22
+ * @returns {value is object}
23
+ */
24
+ function isObjectLike(value) {
25
+ return value !== null && (typeof value === "object" || typeof value === "function");
26
+ }
27
+
28
+ /**
29
+ * @param {unknown} value
30
+ * @param {string} key
31
+ * @returns {unknown}
32
+ */
33
+ function propertyOf(value, key) {
34
+ return isObjectLike(value) ? Reflect.get(value, key) : undefined;
35
+ }
36
+
37
+ /**
38
+ * @param {object} value
39
+ * @param {string} name
40
+ * @returns {PropertyRead}
41
+ */
42
+ function safeProperty(value, name) {
43
+ try {
44
+ /** @type {unknown} */
45
+ const property = Reflect.get(value, name);
46
+ return { available: true, value: property };
47
+ } catch {
48
+ return { available: false, value: undefined };
49
+ }
50
+ }
51
+
52
+ /**
53
+ * @param {Readonly<PropertyRead>} property
54
+ * @returns {string | undefined}
55
+ */
56
+ function nonBlankText(property) {
57
+ return property.available ? stringOrUndefined(property.value) : undefined;
58
+ }
59
+
60
+ /**
61
+ * @param {unknown} error
62
+ * @returns {ErrorDetails}
63
+ */
64
+ function errorDetails(error) {
65
+ if (error instanceof Error || (typeof error === "object" && error !== null)) {
66
+ const name = safeProperty(error, "name");
67
+ const message = safeProperty(error, "message");
68
+ const stack = safeProperty(error, "stack");
69
+ return {
70
+ name: nonBlankText(name) ?? "Error",
71
+
72
+ message: nonBlankText(message),
73
+
74
+ stack: nonBlankText(stack)
75
+ };
76
+ }
77
+ if (typeof error === "string" && error.trim() !== "") {
78
+ return { message: error, name: "Error" };
79
+ }
80
+ return { name: "Error" };
81
+ }
82
+
83
+ /**
84
+ * @param {unknown} value
85
+ * @returns {string | undefined}
86
+ */
87
+ function safeCauseTypeName(value) {
88
+ return typeof value === "string" && TYPE_NAME_PATTERN.test(value) ? value : undefined;
89
+ }
90
+
91
+ /**
92
+ * @param {object} value
93
+ * @returns {string | undefined}
94
+ */
95
+ function constructorTypeName(value) {
96
+ const constructor = safeProperty(value, "constructor");
97
+ if (!constructor.available || !isObjectLike(constructor.value)) {
98
+ return undefined;
99
+ }
100
+ const name = safeProperty(constructor.value, "name");
101
+ return name.available ? safeCauseTypeName(name.value) : undefined;
102
+ }
103
+
104
+ /**
105
+ * @param {unknown} value
106
+ * @returns {string}
107
+ */
108
+ function errorCauseType(value) {
109
+ if (!isObjectLike(value)) {
110
+ return "NonError";
111
+ }
112
+ const constructorName = constructorTypeName(value);
113
+ if (!(value instanceof Error)) {
114
+ return constructorName ?? "Object";
115
+ }
116
+ if (constructorName !== undefined && constructorName !== "Error") {
117
+ return constructorName;
118
+ }
119
+ const name = safeProperty(value, "name");
120
+ const builtinName = name.available && typeof name.value === "string" && BUILTIN_ERROR_NAMES.has(name.value) ? name.value : undefined;
121
+ return builtinName ?? constructorName ?? "Error";
122
+ }
123
+
124
+ module.exports = { errorCauseType, errorDetails, isObjectLike, propertyOf, safeProperty };
@@ -0,0 +1,187 @@
1
+ const { errorCauseMetadata } = require("./error-causes.cjs");
2
+ const { errorDetails } = require("./error-details.cjs");
3
+ const { normalizeSeverity } = require("./event-validation.cjs");
4
+ const { createJavaScriptExceptionChain } = require("./exception-chain.cjs");
5
+ const { createIssueException, validateIssueEvidence } = require("./issue-diagnostics.cjs");
6
+ const { javascriptStackEvidence } = require("./issue-stack.cjs");
7
+ const { compactMetadata, traceMetadataFromLogContext } = require("./log-context.cjs");
8
+ const { SdkError } = require("./sdk-error.cjs");
9
+ const { hasUnicodeControlCharacter, isRecord, optionalEntry, stringOrUndefined } = require("./validation.cjs");
10
+
11
+ /**
12
+ * @import { IssueAttributes, IssueStackFrame } from "./index.cjs"
13
+ * @import { ErrorDetails } from "./error-details.cjs"
14
+ * @import { DeepReadonly } from "./validation.cjs"
15
+ * @typedef {Readonly<{ details: Readonly<ErrorDetails>, frame: Readonly<IssueStackFrame> | undefined }>} ParsedError
16
+ */
17
+
18
+ const MAX_EXCEPTION_TYPE_LENGTH = 256;
19
+ const NO_FRAMES = 0;
20
+ const LOCATION_TEXT_PATTERN = /[?#]/u;
21
+
22
+ /**
23
+ * @param {string} value
24
+ * @returns {string}
25
+ */
26
+ function boundedIssueExceptionType(value) {
27
+ const normalized = value.trim();
28
+ if (
29
+ normalized === ""
30
+ || [...normalized].length > MAX_EXCEPTION_TYPE_LENGTH
31
+ || LOCATION_TEXT_PATTERN.test(normalized)
32
+ || hasUnicodeControlCharacter(normalized)
33
+ ) {
34
+ return "Error";
35
+ }
36
+ return normalized;
37
+ }
38
+
39
+ /**
40
+ * @param {unknown} value
41
+ * @returns {string | undefined}
42
+ */
43
+ function issueFingerprintOrUndefined(value) {
44
+ if (value === undefined || value === null) {
45
+ return undefined;
46
+ }
47
+ if (typeof value !== "string" || value.trim() === "") {
48
+ throw new SdkError("validation_error", "issue fingerprint must be a non-empty string");
49
+ }
50
+ return value.trim();
51
+ }
52
+
53
+ /**
54
+ * @param {string} groupingPrefix
55
+ * @param {Readonly<IssueStackFrame> | undefined} frame
56
+ * @param {string | undefined} issueFingerprint
57
+ * @returns {Record<string, string>}
58
+ */
59
+ function issueGroupingMetadata(groupingPrefix, frame, issueFingerprint) {
60
+ /** @type {string} */
61
+ let issueGroupingSource = "error_type";
62
+ if (issueFingerprint !== undefined) {
63
+ issueGroupingSource = "explicit_fingerprint";
64
+ } else if (frame !== undefined) {
65
+ issueGroupingSource = "error_type_and_frame";
66
+ }
67
+ return {
68
+ issueGroupingKey: frame === undefined ? groupingPrefix : `${groupingPrefix}:${frame.filename}`,
69
+
70
+ issueGroupingSource,
71
+ ...optionalEntry("issueFingerprint", issueFingerprint)
72
+ };
73
+ }
74
+
75
+ /**
76
+ * @param {Readonly<IssueStackFrame> | undefined} frame
77
+ * @returns {Record<string, string>}
78
+ */
79
+ function releaseArtifactMetadata(frame) {
80
+ if (frame?.debugId === undefined || frame.debugId === "") {
81
+ return {};
82
+ }
83
+ return {
84
+ releaseArtifactType: "sourcemap",
85
+
86
+ releaseArtifactCodeFile: frame.filename,
87
+
88
+ releaseArtifactDebugId: frame.debugId
89
+ };
90
+ }
91
+
92
+ /**
93
+ * @param {Readonly<Record<string, unknown>>} options
94
+ * @returns {Record<string, unknown>}
95
+ */
96
+ function labelMetadata(options) {
97
+ /** @type {Record<string, unknown>} */
98
+ const labels = {};
99
+ for (const key of ["release", "environment", "service", "runtime", "platform"]) {
100
+ if (stringOrUndefined(options[key]) !== undefined) {
101
+ labels[key] = options[key];
102
+ }
103
+ }
104
+ return labels;
105
+ }
106
+
107
+ /**
108
+ * @param {Readonly<IssueStackFrame> | undefined} frame
109
+ * @returns {Record<string, unknown>}
110
+ */
111
+ function errorFrameMetadata(frame) {
112
+ if (frame === undefined) {
113
+ return {};
114
+ }
115
+ return {
116
+ errorFrameFile: frame.filename,
117
+
118
+ errorFrameLine: frame.line,
119
+
120
+ errorFrameColumn: frame.column
121
+ };
122
+ }
123
+
124
+ /**
125
+ * @param {unknown} error
126
+ * @param {Readonly<Record<string, unknown>>} options
127
+ * @param {ParsedError} parsed
128
+ * @returns {Record<string, unknown>}
129
+ */
130
+ function errorIssueMetadata(error, options, parsed) {
131
+ const { details, frame } = parsed;
132
+ const source = stringOrUndefined(options["source"]) ?? "javascript.error";
133
+ return {
134
+ ...compactMetadata(options["metadata"]),
135
+
136
+ source,
137
+
138
+ errorName: details.name,
139
+ ...optionalEntry("errorMessage", details.message),
140
+ ...errorFrameMetadata(frame),
141
+ ...issueGroupingMetadata(`${source}:${details.name}`, frame, issueFingerprintOrUndefined(options["fingerprint"])),
142
+ ...errorCauseMetadata(error),
143
+ ...labelMetadata(options),
144
+ ...traceMetadataFromLogContext(options["trace"]),
145
+ ...releaseArtifactMetadata(frame),
146
+ ...optionalEntry("errorStack", options["includeErrorStack"] === true ? details.stack : undefined)
147
+ };
148
+ }
149
+
150
+ /**
151
+ * @param {unknown} error
152
+ * @param {unknown} [options]
153
+ * @returns {DeepReadonly<IssueAttributes>}
154
+ */
155
+ function createIssueAttributesFromError(error, options = {}) {
156
+ if (!isRecord(options)) {
157
+ throw new SdkError("validation_error", "error issue options must be an object");
158
+ }
159
+ const details = errorDetails(error);
160
+ const stackEvidence = javascriptStackEvidence(details.stack, options["debugIdMap"]);
161
+ const [frame] = stackEvidence.frames;
162
+ const metadata = errorIssueMetadata(error, options, { details, frame });
163
+ const exception = createIssueException(
164
+ boundedIssueExceptionType(details.name),
165
+ stringOrUndefined(options["mechanism"]) ?? "javascript.error",
166
+ options["handled"] === undefined ? true : options["handled"]
167
+ );
168
+ const exceptionChain = createJavaScriptExceptionChain(error, {
169
+ debugIdMap: options["debugIdMap"],
170
+ details,
171
+ exception,
172
+ stackEvidence
173
+ });
174
+ return {
175
+ title: stringOrUndefined(options["title"]) ?? details.name,
176
+
177
+ level: normalizeSeverity("issue level", options["level"] ?? "error"),
178
+ ...optionalEntry("message", stringOrUndefined(options["message"]) ?? details.message),
179
+ exception,
180
+ exceptionChain,
181
+ ...optionalEntry("stackFrames", stackEvidence.frames.length > NO_FRAMES ? stackEvidence.frames : undefined),
182
+ ...optionalEntry("evidence", validateIssueEvidence(options["evidence"])),
183
+ metadata: compactMetadata(metadata)
184
+ };
185
+ }
186
+
187
+ module.exports = { createIssueAttributesFromError };
@@ -0,0 +1,55 @@
1
+ const { cloneIssueDiagnostics } = require("./issue-diagnostics.cjs");
2
+ const { cloneTelemetryContext } = require("./telemetry-context.cjs");
3
+ const { optionalEntry } = require("./validation.cjs");
4
+
5
+ /**
6
+ * @import { NativeStackFrame } from "./index.cjs"
7
+ * @import { EventAttributes, SdkEvent } from "./event-validation.cjs"
8
+ * @import { DeepReadonly } from "./validation.cjs"
9
+ */
10
+
11
+ /**
12
+ * @template {Readonly<{ metadata?: Readonly<Record<string, unknown>> }>} Entry
13
+ * @param {Entry} entry
14
+ * @returns {Entry}
15
+ */
16
+ function cloneWithMetadata(entry) {
17
+ return entry.metadata === undefined ? { ...entry } : { ...entry, metadata: { ...entry.metadata } };
18
+ }
19
+
20
+ /**
21
+ * @param {Readonly<NativeStackFrame>} frame
22
+ * @returns {NativeStackFrame}
23
+ */
24
+ function cloneNativeStackFrame(frame) {
25
+ return { ...frame };
26
+ }
27
+
28
+ /**
29
+ * @param {DeepReadonly<EventAttributes>} source
30
+ * @returns {Partial<DeepReadonly<EventAttributes>>}
31
+ */
32
+ function clonedCollections(source) {
33
+ const { context, events, links, metadata, nativeStackFrames } = source;
34
+ return {
35
+ ...optionalEntry("nativeStackFrames", nativeStackFrames?.map((frame) => cloneNativeStackFrame(frame))),
36
+ ...optionalEntry("metadata", metadata === undefined ? undefined : { ...metadata }),
37
+ ...optionalEntry("events", events?.map((entry) => cloneWithMetadata(entry))),
38
+ ...optionalEntry("links", links?.map((entry) => cloneWithMetadata(entry))),
39
+ ...optionalEntry("context", context === undefined ? undefined : cloneTelemetryContext(context))
40
+ };
41
+ }
42
+
43
+ /**
44
+ * @param {DeepReadonly<SdkEvent>} event
45
+ * @returns {DeepReadonly<SdkEvent>}
46
+ */
47
+ function cloneEvent(event) {
48
+ const source = event.attributes;
49
+ return {
50
+ ...event,
51
+ attributes: { ...source, ...cloneIssueDiagnostics(source), ...clonedCollections(source) }
52
+ };
53
+ }
54
+
55
+ module.exports = { cloneEvent };
@@ -0,0 +1,40 @@
1
+ const { SdkError } = require("./sdk-error.cjs");
2
+ const { validateTelemetryContext } = require("./telemetry-context.cjs");
3
+ const { isRecord, optionalEntry } = require("./validation.cjs");
4
+
5
+ /**
6
+ * @import { TelemetryContext } from "./index.cjs"
7
+ */
8
+
9
+ /**
10
+ * @param {unknown} metadata
11
+ * @returns {Record<string, unknown> | undefined}
12
+ */
13
+ function cloneMetadata(metadata) {
14
+ if (metadata === undefined) {
15
+ return undefined;
16
+ }
17
+ if (!isRecord(metadata)) {
18
+ throw new SdkError("validation_error", "metadata must be an object");
19
+ }
20
+ return { ...metadata };
21
+ }
22
+
23
+ /**
24
+ * @template {object} Attributes
25
+ * @param {Attributes} attributes
26
+ * @param {unknown} metadata
27
+ * @param {unknown} context
28
+ * @returns {Attributes & { metadata?: Record<string, unknown>, context?: TelemetryContext }}
29
+ */
30
+ function withMetadata(attributes, metadata, context) {
31
+ const safeMetadata = cloneMetadata(metadata);
32
+ const safeContext = validateTelemetryContext(context);
33
+ return {
34
+ ...attributes,
35
+ ...optionalEntry("metadata", safeMetadata),
36
+ ...optionalEntry("context", safeContext)
37
+ };
38
+ }
39
+
40
+ module.exports = { withMetadata };