@logbrew/sdk 0.1.37 → 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 (103) 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 +35 -2984
  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-breadcrumbs.cjs +143 -0
  33. package/issue-diagnostics.cjs +94 -582
  34. package/issue-evidence.cjs +256 -0
  35. package/issue-exception.cjs +268 -0
  36. package/issue-stack-frames.cjs +220 -0
  37. package/issue-stack-text.cjs +101 -0
  38. package/issue-stack.cjs +188 -225
  39. package/issue-text.cjs +72 -0
  40. package/log-context.cjs +87 -67
  41. package/metric-validation.cjs +95 -0
  42. package/network-milestone.cjs +155 -0
  43. package/null-value.cjs +4 -0
  44. package/opentelemetry-bridge.cjs +330 -0
  45. package/opentelemetry-context.cjs +245 -0
  46. package/opentelemetry-exceptions.cjs +69 -0
  47. package/opentelemetry-keys.cjs +183 -0
  48. package/opentelemetry-span.cjs +286 -0
  49. package/opentelemetry-summary.cjs +213 -0
  50. package/opentelemetry-time.cjs +131 -0
  51. package/opentelemetry.cjs +99 -1068
  52. package/package.json +64 -1
  53. package/pino-destination.cjs +108 -0
  54. package/pino-record.cjs +237 -0
  55. package/product-action.cjs +163 -0
  56. package/provided-breadcrumbs.cjs +117 -0
  57. package/random-hex.cjs +29 -0
  58. package/react-native.js +1 -1
  59. package/recording-transport.cjs +68 -0
  60. package/release-artifacts-build.cjs +263 -84
  61. package/release-artifacts-common.js +347 -66
  62. package/release-artifacts-debug-id.js +178 -0
  63. package/release-artifacts-inspect.js +213 -0
  64. package/release-artifacts-issue-event.js +99 -0
  65. package/release-artifacts-manifest-artifact.js +107 -0
  66. package/release-artifacts-manifest.js +77 -0
  67. package/release-artifacts-mappings.js +265 -0
  68. package/release-artifacts-prepare.js +297 -0
  69. package/release-artifacts-source-context.js +210 -0
  70. package/release-artifacts-symbolication.js +272 -421
  71. package/release-artifacts-upload-files.js +122 -0
  72. package/release-artifacts-upload-request.js +246 -0
  73. package/release-artifacts-upload.js +155 -300
  74. package/release-artifacts-urls.js +49 -0
  75. package/release-artifacts.js +189 -662
  76. package/retry-delay.cjs +32 -0
  77. package/sdk-error.cjs +36 -0
  78. package/span-validation.cjs +191 -0
  79. package/stored-events.cjs +243 -0
  80. package/support-ticket.cjs +232 -122
  81. package/telemetry-context.cjs +343 -251
  82. package/trace-context.cjs +376 -179
  83. package/transport-error.cjs +23 -0
  84. package/types/client.d.ts +67 -0
  85. package/types/delivery.d.ts +125 -0
  86. package/types/issues.d.ts +249 -0
  87. package/types/logging.d.ts +175 -0
  88. package/types/opentelemetry.d.ts +205 -0
  89. package/types/product.d.ts +128 -0
  90. package/types/recording-transport.d.ts +15 -0
  91. package/types/sdk-error.d.ts +9 -0
  92. package/types/telemetry.d.ts +171 -0
  93. package/types/trace-context.d.ts +110 -0
  94. package/types/transport-error.d.ts +10 -0
  95. package/utf8.cjs +37 -0
  96. package/validation.cjs +327 -0
  97. package/vite-release-artifacts-config.cjs +120 -0
  98. package/vite-release-artifacts.cjs +199 -99
  99. package/vite-release-artifacts.d.cts +65 -40
  100. package/vite-release-artifacts.d.ts +65 -40
  101. package/vite-release-artifacts.js +2 -2
  102. package/winston-info.cjs +205 -0
  103. package/winston.cjs +189 -290
package/log-context.cjs CHANGED
@@ -1,95 +1,115 @@
1
- const ZERO_TRACE_ID = "00000000000000000000000000000000";
2
- const ZERO_SPAN_ID = "0000000000000000";
1
+ const { SdkError } = require("./sdk-error.cjs");
2
+ const { ZERO_SPAN_ID, ZERO_TRACE_ID, isRecord } = require("./validation.cjs");
3
3
 
4
- function buildLogContextHelpers({ SdkError }) {
5
- function compactMetadata(metadata) {
6
- if (metadata === undefined) {
7
- return {};
8
- }
9
- if (!metadata || Array.isArray(metadata) || typeof metadata !== "object") {
10
- throw new SdkError("validation_error", "metadata must be an object");
11
- }
12
- const safeMetadata = {};
13
- for (const [key, value] of Object.entries(metadata)) {
14
- if (isMetadataValue(value)) {
15
- safeMetadata[key] = value;
16
- }
17
- }
18
- return safeMetadata;
19
- }
4
+ /**
5
+ * @import { LogCorrelationTraceContext, Metadata, MetadataValue } from "./index.cjs"
6
+ */
20
7
 
21
- function traceFromProvider(provider, onError) {
22
- if (!provider) {
23
- return undefined;
24
- }
25
- try {
26
- return provider();
27
- } catch (error) {
28
- onError(error);
29
- return undefined;
30
- }
31
- }
32
-
33
- return {
34
- compactMetadata,
35
- isMetadataValue,
36
- normalizeLogTraceContext,
37
- traceFromProvider,
38
- traceMetadataFromLogContext
39
- };
40
- }
8
+ const TRACE_ID_PATTERN = /^[0-9a-fA-F]{32}$/u;
9
+ const SPAN_ID_PATTERN = /^[0-9a-fA-F]{16}$/u;
41
10
 
11
+ /**
12
+ * @param {unknown} value
13
+ * @returns {value is MetadataValue}
14
+ */
42
15
  function isMetadataValue(value) {
43
16
  return (
44
17
  value === null
45
18
  || typeof value === "string"
46
- || typeof value === "number" && Number.isFinite(value)
19
+ || (typeof value === "number" && Number.isFinite(value))
47
20
  || typeof value === "boolean"
48
21
  );
49
22
  }
50
23
 
51
- function traceMetadataFromLogContext(trace) {
52
- const normalized = normalizeLogTraceContext(trace);
53
- if (!normalized) {
24
+ /**
25
+ * @param {unknown} metadata
26
+ * @returns {Metadata}
27
+ */
28
+ function compactMetadata(metadata) {
29
+ if (metadata === undefined) {
54
30
  return {};
55
31
  }
56
- return {
57
- traceId: normalized.traceId,
58
- spanId: normalized.spanId,
59
- ...(normalized.parentSpanId !== undefined ? { parentSpanId: normalized.parentSpanId } : {}),
60
- ...(normalized.sampled !== undefined ? { sampled: normalized.sampled } : {})
61
- };
32
+ if (!isRecord(metadata)) {
33
+ throw new SdkError("validation_error", "metadata must be an object");
34
+ }
35
+ /** @type {Metadata} */
36
+ const safeMetadata = {};
37
+ for (const [key, value] of Object.entries(metadata)) {
38
+ if (isMetadataValue(value)) {
39
+ safeMetadata[key] = value;
40
+ }
41
+ }
42
+ return safeMetadata;
62
43
  }
63
44
 
45
+ /**
46
+ * @template Trace
47
+ * @param {(() => Trace) | null | undefined} provider
48
+ * @param {(error: unknown) => void} onError
49
+ * @returns {Trace | undefined}
50
+ */
51
+ function traceFromProvider(provider, onError) {
52
+ if (!provider) {
53
+ return undefined;
54
+ }
55
+ try {
56
+ return provider();
57
+ } catch (error) {
58
+ onError(error);
59
+ return undefined;
60
+ }
61
+ }
62
+
63
+ /**
64
+ * @param {unknown} value
65
+ * @param {Readonly<RegExp>} pattern
66
+ * @param {string} zeroValue
67
+ * @returns {string | undefined}
68
+ */
69
+ function normalizeHexId(value, pattern, zeroValue) {
70
+ if (typeof value !== "string" || !pattern.test(value) || value.toLowerCase() === zeroValue) {
71
+ return undefined;
72
+ }
73
+ return value.toLowerCase();
74
+ }
75
+
76
+ /**
77
+ * @param {unknown} trace
78
+ * @returns {LogCorrelationTraceContext | undefined}
79
+ */
64
80
  function normalizeLogTraceContext(trace) {
65
- if (!trace || Array.isArray(trace) || typeof trace !== "object") {
81
+ if (!isRecord(trace)) {
66
82
  return undefined;
67
83
  }
68
- const traceId = normalizeHexId(trace.traceId, 32, ZERO_TRACE_ID);
69
- const spanId = normalizeHexId(trace.spanId, 16, ZERO_SPAN_ID);
70
- if (!traceId || !spanId) {
84
+ const traceId = normalizeHexId(trace["traceId"], TRACE_ID_PATTERN, ZERO_TRACE_ID);
85
+ const spanId = normalizeHexId(trace["spanId"], SPAN_ID_PATTERN, ZERO_SPAN_ID);
86
+ if (traceId === undefined || spanId === undefined) {
71
87
  return undefined;
72
88
  }
73
- const parentSpanId = normalizeHexId(trace.parentSpanId, 16, ZERO_SPAN_ID);
89
+ const parentSpanId = normalizeHexId(trace["parentSpanId"], SPAN_ID_PATTERN, ZERO_SPAN_ID);
90
+ const { sampled } = trace;
74
91
  return {
75
92
  traceId,
93
+
76
94
  spanId,
77
- ...(parentSpanId !== undefined ? { parentSpanId } : {}),
78
- ...(typeof trace.sampled === "boolean" ? { sampled: trace.sampled } : {})
95
+ ...(parentSpanId === undefined ? {} : { parentSpanId }),
96
+ ...(typeof sampled === "boolean" ? { sampled } : {})
79
97
  };
80
98
  }
81
99
 
82
- function normalizeHexId(value, length, zeroValue) {
83
- if (typeof value !== "string") {
84
- return undefined;
85
- }
86
- const pattern = length === 32
87
- ? /^[0-9a-fA-F]{32}$/u
88
- : /^[0-9a-fA-F]{16}$/u;
89
- if (!pattern.test(value) || value.toLowerCase() === zeroValue) {
90
- return undefined;
91
- }
92
- return value.toLowerCase();
100
+ /**
101
+ * @param {unknown} trace
102
+ * @returns {Metadata}
103
+ */
104
+ function traceMetadataFromLogContext(trace) {
105
+ const normalized = normalizeLogTraceContext(trace);
106
+ return normalized === undefined ? {} : { ...normalized };
93
107
  }
94
108
 
95
- module.exports = { buildLogContextHelpers };
109
+ module.exports = {
110
+ compactMetadata,
111
+ isMetadataValue,
112
+ normalizeLogTraceContext,
113
+ traceFromProvider,
114
+ traceMetadataFromLogContext
115
+ };
@@ -0,0 +1,95 @@
1
+ const { withMetadata } = require("./event-metadata.cjs");
2
+ const { SdkError } = require("./sdk-error.cjs");
3
+ const { hasUnicodeControlCharacter, optionalEntry, requireAllowedValue, requireFiniteNumber, requireNonEmpty } = require("./validation.cjs");
4
+
5
+ /**
6
+ * @import { EventAttributes } from "./event-validation.cjs"
7
+ * @typedef {"counter" | "gauge" | "histogram"} MetricKind
8
+ */
9
+
10
+ const MAX_METRIC_DESCRIPTION_LENGTH = 1024;
11
+ const MIN_METRIC_VALUE = 0;
12
+ const FIRST_CODE_POINT = 0;
13
+ const FIRST_SURROGATE = 0xD8_00;
14
+ const LAST_SURROGATE = 0xDF_FF;
15
+ const LINE_SEPARATOR = 0x20_28;
16
+ const PARAGRAPH_SEPARATOR = 0x20_29;
17
+ /** @type {ReadonlySet<MetricKind>} */
18
+ const METRIC_KINDS = new Set(["counter", "gauge", "histogram"]);
19
+ /** @type {ReadonlySet<MetricKind>} */
20
+ const NON_NEGATIVE_METRIC_KINDS = new Set(["counter", "histogram"]);
21
+ /** @type {ReadonlySet<string>} */
22
+ const CUMULATIVE_TEMPORALITIES = new Set(["delta", "cumulative"]);
23
+ /** @type {ReadonlyMap<MetricKind, ReadonlySet<string>>} */
24
+ const METRIC_TEMPORALITIES_BY_KIND = new Map([
25
+ ["counter", CUMULATIVE_TEMPORALITIES],
26
+ ["gauge", new Set(["instant"])],
27
+ ["histogram", CUMULATIVE_TEMPORALITIES]
28
+ ]);
29
+
30
+ /**
31
+ * @param {string} character
32
+ * @returns {boolean}
33
+ */
34
+ function isSeparatorOrSurrogate(character) {
35
+ const code = character.codePointAt(FIRST_CODE_POINT);
36
+ return code !== undefined && (
37
+ (code >= FIRST_SURROGATE && code <= LAST_SURROGATE)
38
+ || code === LINE_SEPARATOR
39
+ || code === PARAGRAPH_SEPARATOR
40
+ );
41
+ }
42
+
43
+ /**
44
+ * @param {unknown} value
45
+ * @returns {string | undefined}
46
+ */
47
+ function metricDescriptionOrUndefined(value) {
48
+ if (value === undefined) {
49
+ return undefined;
50
+ }
51
+ const characters = typeof value === "string" ? [...value] : [];
52
+ if (
53
+ typeof value !== "string"
54
+ || value.trim() === ""
55
+ || characters.length > MAX_METRIC_DESCRIPTION_LENGTH
56
+ || hasUnicodeControlCharacter(value)
57
+ || characters.some((character) => isSeparatorOrSurrogate(character))
58
+ ) {
59
+ throw new SdkError(
60
+ "validation_error",
61
+ `metric description must be a non-blank string of at most ${MAX_METRIC_DESCRIPTION_LENGTH} non-control characters`
62
+ );
63
+ }
64
+ return value.trim();
65
+ }
66
+
67
+ /**
68
+ * @param {Readonly<Record<string, unknown>>} attributes
69
+ * @returns {EventAttributes}
70
+ */
71
+ function validateMetric(attributes) {
72
+ const name = requireNonEmpty("metric name", attributes["name"]);
73
+ const kind = requireAllowedValue("metric kind", attributes["kind"], METRIC_KINDS);
74
+ const value = requireFiniteNumber("metric value", attributes["value"]);
75
+ const unit = requireNonEmpty("metric unit", attributes["unit"]);
76
+ const allowedTemporalities = METRIC_TEMPORALITIES_BY_KIND.get(kind) ?? CUMULATIVE_TEMPORALITIES;
77
+ const temporality = requireAllowedValue(`metric temporality for ${kind}`, attributes["temporality"], allowedTemporalities);
78
+ if (NON_NEGATIVE_METRIC_KINDS.has(kind) && value < MIN_METRIC_VALUE) {
79
+ throw new SdkError("validation_error", `metric ${kind} value must be non-negative`);
80
+ }
81
+ const description = metricDescriptionOrUndefined(attributes["description"]);
82
+ return withMetadata({
83
+ name,
84
+ ...optionalEntry("description", description),
85
+ kind,
86
+
87
+ value,
88
+
89
+ unit,
90
+
91
+ temporality
92
+ }, attributes["metadata"], attributes["context"]);
93
+ }
94
+
95
+ module.exports = { validateMetric };
@@ -0,0 +1,155 @@
1
+ const { ACTION_STATUSES } = require("./event-validation.cjs");
2
+ const { compactMetadata } = require("./log-context.cjs");
3
+ const { sanitizeRouteTemplate } = require("./product-action.cjs");
4
+ const { SdkError } = require("./sdk-error.cjs");
5
+ const { isRecord, requireAllowedValue, requireNonEmpty, stringOrUndefined } = require("./validation.cjs");
6
+
7
+ /**
8
+ * @import { ActionStatus, TimelineAttributes, TimelineOptions } from "./product-action.cjs"
9
+ * @typedef {{
10
+ * durationMs: number | undefined,
11
+ * metadata: unknown,
12
+ * method: string,
13
+ * name: string,
14
+ * routeTemplate: string,
15
+ * sessionId: unknown,
16
+ * status: ActionStatus,
17
+ * statusCode: number | undefined,
18
+ * traceId: unknown
19
+ * }} NetworkMilestoneDetails
20
+ */
21
+
22
+ const MIN_STATUS_CODE = 100;
23
+ const MAX_STATUS_CODE = 599;
24
+ const FAILURE_STATUS_CODE = 400;
25
+ const MIN_DURATION_MS = 0;
26
+ const HTTP_METHOD_PATTERN = /^[A-Z][A-Z0-9_-]*$/u;
27
+
28
+ /**
29
+ * @param {unknown} method
30
+ * @returns {string}
31
+ */
32
+ function normalizeHttpMethod(method) {
33
+ const value = method === undefined ? "GET" : method;
34
+ if (typeof value !== "string" || value.trim() === "") {
35
+ throw new SdkError("validation_error", "network milestone method must be a non-empty string");
36
+ }
37
+ const normalized = value.trim().toUpperCase();
38
+ if (!HTTP_METHOD_PATTERN.test(normalized)) {
39
+ throw new SdkError("validation_error", "network milestone method must be a valid HTTP method");
40
+ }
41
+ return normalized;
42
+ }
43
+
44
+ /**
45
+ * @param {unknown} value
46
+ * @returns {number | undefined}
47
+ */
48
+ function statusCodeOrUndefined(value) {
49
+ if (value === undefined) {
50
+ return undefined;
51
+ }
52
+ if (typeof value !== "number" || !Number.isInteger(value) || value < MIN_STATUS_CODE || value > MAX_STATUS_CODE) {
53
+ throw new SdkError("validation_error", "network milestone statusCode must be an integer from 100 to 599");
54
+ }
55
+ return value;
56
+ }
57
+
58
+ /**
59
+ * @param {string} label
60
+ * @param {unknown} value
61
+ * @returns {number | undefined}
62
+ */
63
+ function nonNegativeNumberOrUndefined(label, value) {
64
+ if (value === undefined) {
65
+ return undefined;
66
+ }
67
+ if (typeof value !== "number" || !Number.isFinite(value) || value < MIN_DURATION_MS) {
68
+ throw new SdkError("validation_error", `${label} must be a non-negative number`);
69
+ }
70
+ return value;
71
+ }
72
+
73
+ /**
74
+ * @param {number | undefined} statusCode
75
+ * @returns {"failure" | "success"}
76
+ */
77
+ function statusFromStatusCode(statusCode) {
78
+ return statusCode !== undefined && statusCode >= FAILURE_STATUS_CODE ? "failure" : "success";
79
+ }
80
+
81
+ /**
82
+ * @param {Readonly<Record<string, unknown>>} request
83
+ * @returns {NetworkMilestoneDetails}
84
+ */
85
+ function networkMilestoneFields(request) {
86
+ const routeTemplate = requireNonEmpty("network milestone routeTemplate", sanitizeRouteTemplate(request["routeTemplate"]));
87
+ const method = normalizeHttpMethod(request["method"]);
88
+ const statusCode = statusCodeOrUndefined(request["statusCode"]);
89
+ const requestedStatus = request["status"];
90
+ const status = requireAllowedValue(
91
+ "network milestone status",
92
+ requestedStatus === undefined ? statusFromStatusCode(statusCode) : requestedStatus,
93
+ ACTION_STATUSES
94
+ );
95
+ const durationMs = nonNegativeNumberOrUndefined("network milestone durationMs", request["durationMs"]);
96
+ const name = stringOrUndefined(request["name"]) ?? `network.${method.toLowerCase()} ${routeTemplate}`;
97
+ return {
98
+ durationMs,
99
+ metadata: request["metadata"],
100
+ method,
101
+ name,
102
+ routeTemplate,
103
+ sessionId: request["sessionId"],
104
+ status,
105
+ statusCode,
106
+ traceId: request["traceId"]
107
+ };
108
+ }
109
+
110
+ /**
111
+ * @param {unknown} request
112
+ * @returns {NetworkMilestoneDetails}
113
+ */
114
+ function networkMilestoneDetails(request) {
115
+ if (typeof request === "string") {
116
+ return networkMilestoneFields({ routeTemplate: request });
117
+ }
118
+ if (!isRecord(request)) {
119
+ throw new SdkError("validation_error", "network milestone must be a string or object");
120
+ }
121
+ return networkMilestoneFields(request);
122
+ }
123
+
124
+ /**
125
+ * @param {unknown} request
126
+ * @param {TimelineOptions} [options]
127
+ * @returns {TimelineAttributes}
128
+ */
129
+ function createNetworkMilestoneAttributes(request, options = {}) {
130
+ const details = networkMilestoneDetails(request);
131
+ return {
132
+ name: details.name,
133
+
134
+ status: details.status,
135
+
136
+ metadata: compactMetadata({
137
+ source: "network.milestone",
138
+ ...compactMetadata(options.metadata),
139
+ ...compactMetadata(details.metadata),
140
+ routeTemplate: details.routeTemplate,
141
+
142
+ method: details.method,
143
+
144
+ statusCode: details.statusCode,
145
+
146
+ durationMs: details.durationMs,
147
+
148
+ sessionId: stringOrUndefined(details.sessionId),
149
+
150
+ traceId: stringOrUndefined(details.traceId)
151
+ })
152
+ };
153
+ }
154
+
155
+ module.exports = { createNetworkMilestoneAttributes };
package/null-value.cjs ADDED
@@ -0,0 +1,4 @@
1
+ /** @type {null} */
2
+ const NULL_VALUE = null;
3
+
4
+ module.exports = { NULL_VALUE };