@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
@@ -1,41 +1,145 @@
1
- import crypto from "node:crypto";
2
- import fs from "node:fs";
1
+ import { access, readFile, stat } from "node:fs/promises";
2
+ import { createHash } from "node:crypto";
3
3
  import path from "node:path";
4
+ import { promisify } from "node:util";
5
+ import { realpath } from "node:fs";
6
+
7
+ /**
8
+ * @typedef {"boolean" | "repeat" | "string"} OptionKind
9
+ * @typedef {string | true | readonly string[]} OptionValue
10
+ * @typedef {Readonly<Record<string, OptionValue>>} CliOptions
11
+ * @typedef {Readonly<Record<string, OptionKind>>} OptionSpec
12
+ * @typedef {Readonly<Record<string, unknown>>} JsonObject
13
+ * @typedef {{ readonly positional: string, readonly width: number }} PositionalToken
14
+ * @typedef {{ readonly kind: OptionKind, readonly name: string, readonly value: string | true, readonly width: number }} OptionToken
15
+ */
4
16
 
5
17
  const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/iu;
6
- export const SOURCE_MAP_DEBUG_ID_KEYS = ["debug_id", "debugId", "debugID", "x_debug_id"];
18
+ const SOURCE_MAP_DEBUG_ID_KEYS = ["debug_id", "debugId", "debugID", "x_debug_id"];
19
+ const OPTION_PREFIX = "--";
20
+ const FLAG_WIDTH = 1;
21
+ const VALUE_OPTION_WIDTH = 2;
22
+ const NO_POSITIONALS = 0;
23
+ const FIRST_PART_ONLY = 1;
24
+ const JSON_INDENT = 2;
25
+ const realPathOf = promisify(realpath);
26
+
27
+ /**
28
+ * @param {unknown} value
29
+ * @returns {value is JsonObject}
30
+ */
31
+ function isJsonObject(value) {
32
+ return typeof value === "object" && value !== null && !Array.isArray(value);
33
+ }
34
+
35
+ /**
36
+ * @param {unknown} value
37
+ * @returns {value is readonly unknown[]}
38
+ */
39
+ function isJsonList(value) {
40
+ return Array.isArray(value);
41
+ }
42
+
43
+ /**
44
+ * @param {unknown} error
45
+ * @returns {string}
46
+ */
47
+ function errorMessage(error) {
48
+ return error instanceof Error ? error.message : String(error);
49
+ }
7
50
 
8
- export function parseOptions(args, spec) {
51
+ /**
52
+ * @param {OptionSpec} spec
53
+ * @param {string} name
54
+ * @returns {OptionKind}
55
+ */
56
+ function optionKind(spec, name) {
57
+ const kind = spec[name];
58
+ if (kind === undefined) {
59
+ throw new Error(`unknown option: --${name}`);
60
+ }
61
+ return kind;
62
+ }
63
+
64
+ /**
65
+ * @param {readonly string[]} window
66
+ * @param {OptionSpec} spec
67
+ * @returns {OptionToken | PositionalToken}
68
+ */
69
+ function readToken(window, spec) {
70
+ const [arg = "", value] = window;
71
+ if (!arg.startsWith(OPTION_PREFIX)) {
72
+ return { positional: arg, width: FLAG_WIDTH };
73
+ }
74
+ const name = arg.slice(OPTION_PREFIX.length);
75
+ const kind = optionKind(spec, name);
76
+ if (kind === "boolean") {
77
+ return { kind, name, value: true, width: FLAG_WIDTH };
78
+ }
79
+ if (value === undefined || value.startsWith(OPTION_PREFIX)) {
80
+ throw new Error(`missing value for --${name}`);
81
+ }
82
+ return { kind, name, value, width: VALUE_OPTION_WIDTH };
83
+ }
84
+
85
+ /**
86
+ * @param {readonly string[]} args
87
+ * @param {OptionSpec} spec
88
+ * @returns {readonly (OptionToken | PositionalToken)[]}
89
+ */
90
+ function readTokens(args, spec) {
91
+ /** @type {(OptionToken | PositionalToken)[]} */
92
+ const tokens = [];
93
+ let index = 0;
94
+ while (index < args.length) {
95
+ const token = readToken(args.slice(index, index + VALUE_OPTION_WIDTH), spec);
96
+ tokens.push(token);
97
+ index += token.width;
98
+ }
99
+ return tokens;
100
+ }
101
+
102
+ /**
103
+ * @param {OptionValue | undefined} previous
104
+ * @param {OptionToken} token
105
+ * @returns {OptionValue}
106
+ */
107
+ function optionValue(previous, token) {
108
+ if (token.kind !== "repeat" || token.value === true) {
109
+ return token.value;
110
+ }
111
+ /** @type {readonly string[]} */
112
+ const earlier = typeof previous === "object" ? previous : [];
113
+ return [...earlier, token.value];
114
+ }
115
+
116
+ /**
117
+ * @param {readonly string[]} args
118
+ * @param {OptionSpec} spec
119
+ * @returns {CliOptions}
120
+ */
121
+ function parseOptions(args, spec) {
122
+ const tokens = readTokens(args, spec);
123
+ const positionals = tokens.filter((token) => "positional" in token);
124
+ if (positionals.length > NO_POSITIONALS) {
125
+ throw new Error(`unexpected positional argument: ${String(positionals[NO_POSITIONALS]?.positional)}`);
126
+ }
127
+ /** @type {Record<string, OptionValue>} */
9
128
  const options = {};
10
- const positionals = [];
11
- for (let index = 0; index < args.length; index += 1) {
12
- const arg = args[index];
13
- if (!arg.startsWith("--")) {
14
- positionals.push(arg);
15
- continue;
16
- }
17
- const name = arg.slice(2);
18
- const kind = spec[name];
19
- if (!kind) {
20
- throw new Error(`unknown option: --${name}`);
21
- }
22
- if (kind === "boolean") {
23
- options[name] = true;
24
- continue;
25
- }
26
- const value = args[++index];
27
- if (value === undefined || value.startsWith("--")) {
28
- throw new Error(`missing value for --${name}`);
129
+ for (const token of tokens) {
130
+ if ("name" in token) {
131
+ options[token.name] = optionValue(options[token.name], token);
29
132
  }
30
- options[name] = kind === "repeat" ? [...(options[name] ?? []), value] : value;
31
- }
32
- if (positionals.length > 0) {
33
- throw new Error(`unexpected positional argument: ${positionals[0]}`);
34
133
  }
35
134
  return options;
36
135
  }
37
136
 
38
- export function requireOption(options, name) {
137
+ /**
138
+ * @param {CliOptions} options
139
+ * @param {string} name
140
+ * @returns {string}
141
+ */
142
+ function requireOption(options, name) {
39
143
  const value = options[name];
40
144
  if (typeof value !== "string" || value.trim() === "") {
41
145
  throw new Error(`--${name} is required`);
@@ -43,97 +147,274 @@ export function requireOption(options, name) {
43
147
  return value.trim();
44
148
  }
45
149
 
46
- export function sortJson(value) {
47
- if (Array.isArray(value)) {
48
- return value.map(sortJson);
150
+ /**
151
+ * @param {unknown} value
152
+ * @returns {unknown}
153
+ */
154
+ function sortJson(value) {
155
+ if (isJsonList(value)) {
156
+ return value.map((item) => sortJson(item));
49
157
  }
50
- if (value && typeof value === "object") {
51
- return Object.fromEntries(
52
- Object.keys(value)
53
- .sort()
54
- .map((key) => [key, sortJson(value[key])])
55
- );
158
+ if (isJsonObject(value)) {
159
+ const keys = Object.keys(value);
160
+ keys.sort();
161
+ return Object.fromEntries(keys.map((key) => [key, sortJson(value[key])]));
56
162
  }
57
163
  return value;
58
164
  }
59
165
 
60
- export function stableJson(value) {
166
+ /**
167
+ * @param {unknown} value
168
+ * @returns {string}
169
+ */
170
+ function stableJson(value) {
61
171
  return JSON.stringify(sortJson(value));
62
172
  }
63
173
 
64
- export function fileReference(value) {
65
- return value.split("?", 1)[0].split("#", 1)[0];
174
+ /**
175
+ * @param {string} value
176
+ * @returns {string}
177
+ */
178
+ function fileReference(value) {
179
+ const [withoutQuery = ""] = value.split("?", FIRST_PART_ONLY);
180
+ const [withoutFragment = ""] = withoutQuery.split("#", FIRST_PART_ONLY);
181
+ return withoutFragment;
66
182
  }
67
183
 
68
- export function relativeTo(root, filePath) {
184
+ /**
185
+ * @param {string} root
186
+ * @param {string} filePath
187
+ * @returns {string}
188
+ */
189
+ function relativeTo(root, filePath) {
69
190
  return path.relative(root, filePath).split(path.sep).join("/");
70
191
  }
71
192
 
72
- export function sourceMapDebugId(payload) {
193
+ /**
194
+ * @param {JsonObject} payload
195
+ * @returns {string | undefined}
196
+ */
197
+ function sourceMapDebugId(payload) {
73
198
  for (const key of SOURCE_MAP_DEBUG_ID_KEYS) {
74
199
  const value = payload[key];
75
200
  if (typeof value === "string" && value.trim() !== "") {
76
201
  return value.trim();
77
202
  }
78
203
  }
79
- return null;
204
+ return undefined;
205
+ }
206
+
207
+ /**
208
+ * @param {unknown} payload
209
+ * @returns {void}
210
+ */
211
+ function printJson(payload) {
212
+ process.stdout.write(`${JSON.stringify(sortJson(payload), undefined, JSON_INDENT)}\n`);
213
+ }
214
+
215
+ /**
216
+ * @param {string} filePath
217
+ * @returns {Promise<boolean>}
218
+ */
219
+ async function pathExists(filePath) {
220
+ try {
221
+ await access(filePath);
222
+ return true;
223
+ } catch {
224
+ return false;
225
+ }
226
+ }
227
+
228
+ /**
229
+ * @param {string} filePath
230
+ * @returns {Promise<string>}
231
+ */
232
+ async function realPath(filePath) {
233
+ return realPathOf(filePath);
80
234
  }
81
235
 
82
- export function printJson(payload) {
83
- process.stdout.write(`${JSON.stringify(sortJson(payload), null, 2)}\n`);
236
+ /**
237
+ * @param {string} filePath
238
+ * @returns {Promise<string>}
239
+ */
240
+ async function readText(filePath) {
241
+ return readFile(filePath, "utf8");
84
242
  }
85
243
 
86
- export function safeResolve(candidate, root) {
87
- const resolvedRoot = fs.realpathSync(root);
244
+ /**
245
+ * @param {string} candidate
246
+ * @param {string} root
247
+ * @returns {Promise<string | undefined>}
248
+ */
249
+ async function safeResolve(candidate, root) {
250
+ const resolvedRoot = await realPath(root);
88
251
  const resolved = path.resolve(candidate);
89
- const comparable = fs.existsSync(resolved) ? fs.realpathSync(resolved) : resolved;
252
+ const comparable = (await pathExists(resolved)) ? await realPath(resolved) : resolved;
90
253
  const relative = path.relative(resolvedRoot, comparable);
91
254
  if (relative === "" || (!relative.startsWith("..") && !path.isAbsolute(relative))) {
92
255
  return comparable;
93
256
  }
94
- return null;
257
+ return undefined;
258
+ }
259
+
260
+ /**
261
+ * @param {string} filePath
262
+ * @returns {Promise<number>}
263
+ */
264
+ async function byteSize(filePath) {
265
+ const stats = await stat(filePath);
266
+ return stats.size;
267
+ }
268
+
269
+ /**
270
+ * @param {string} filePath
271
+ * @returns {Promise<boolean>}
272
+ */
273
+ async function isFile(filePath) {
274
+ const stats = await stat(filePath);
275
+ return stats.isFile();
95
276
  }
96
277
 
97
- export function byteSize(filePath) {
98
- return fs.statSync(filePath).size;
278
+ /**
279
+ * @param {string} filePath
280
+ * @returns {Promise<boolean>}
281
+ */
282
+ async function isDirectory(filePath) {
283
+ const stats = await stat(filePath);
284
+ return stats.isDirectory();
99
285
  }
100
286
 
101
- export function sha256File(filePath) {
102
- const digest = crypto.createHash("sha256");
103
- digest.update(fs.readFileSync(filePath));
287
+ /**
288
+ * @param {string} filePath
289
+ * @returns {Promise<string>}
290
+ */
291
+ async function sha256File(filePath) {
292
+ const digest = createHash("sha256");
293
+ digest.update(await readFile(filePath));
104
294
  return digest.digest("hex");
105
295
  }
106
296
 
107
- export function requireBuildDir(value) {
297
+ /**
298
+ * @param {string} value
299
+ * @returns {Promise<string>}
300
+ */
301
+ async function requireBuildDir(value) {
108
302
  const buildDir = path.resolve(value);
109
- if (!fs.existsSync(buildDir) || !fs.statSync(buildDir).isDirectory()) {
303
+ if (!(await pathExists(buildDir)) || !(await isDirectory(buildDir))) {
110
304
  throw new Error(`build directory does not exist: ${value}`);
111
305
  }
112
- return fs.realpathSync(buildDir);
306
+ return realPath(buildDir);
113
307
  }
114
308
 
115
- export function readJsonObject(filePath, label) {
116
- let payload;
309
+ /**
310
+ * @param {string} filePath
311
+ * @param {string} label
312
+ * @returns {Promise<unknown>}
313
+ */
314
+ async function readJson(filePath, label) {
117
315
  try {
118
- payload = JSON.parse(fs.readFileSync(filePath, "utf8"));
316
+ /** @type {unknown} */
317
+ const payload = JSON.parse(await readText(filePath));
318
+ return payload;
119
319
  } catch (error) {
120
- throw new Error(`${label} is not valid JSON: ${error.message}`, { cause: error });
320
+ throw new Error(`${label} is not valid JSON: ${errorMessage(error)}`, { cause: error });
121
321
  }
122
- if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
322
+ }
323
+
324
+ /**
325
+ * @param {string} filePath
326
+ * @param {string} label
327
+ * @returns {Promise<JsonObject>}
328
+ */
329
+ async function readJsonObject(filePath, label) {
330
+ const payload = await readJson(filePath, label);
331
+ if (!isJsonObject(payload)) {
123
332
  throw new Error(`${label} must be a JSON object`);
124
333
  }
125
334
  return payload;
126
335
  }
127
336
 
128
- export function normalizeProjectId(value, errorMessage, required = false) {
337
+ /**
338
+ * @template Item, Result
339
+ * @param {readonly Item[]} items
340
+ * @param {(item: Item) => Promise<Result>} mapper
341
+ * @returns {Promise<Result[]>}
342
+ */
343
+ async function mapInOrder(items, mapper) {
344
+ /** @type {Result[]} */
345
+ const results = [];
346
+ /**
347
+ * @param {readonly Item[]} remaining
348
+ * @returns {Promise<Result[]>}
349
+ */
350
+ async function mapRemaining(remaining) {
351
+ const [first, ...rest] = remaining;
352
+ if (remaining.length === NO_POSITIONALS || first === undefined) {
353
+ return results;
354
+ }
355
+ results.push(await mapper(first));
356
+ return mapRemaining(rest);
357
+ }
358
+ return mapRemaining(items);
359
+ }
360
+
361
+ /**
362
+ * @template Item
363
+ * @param {readonly Item[]} items
364
+ * @param {(item: Item) => Promise<boolean>} predicate
365
+ * @returns {Promise<Item | undefined>}
366
+ */
367
+ async function findInOrder(items, predicate) {
368
+ const [first, ...rest] = items;
369
+ if (items.length === NO_POSITIONALS || first === undefined) {
370
+ return undefined;
371
+ }
372
+ return (await predicate(first)) ? first : findInOrder(rest, predicate);
373
+ }
374
+
375
+ /**
376
+ * @param {unknown} value
377
+ * @param {string} message
378
+ * @param {boolean} required
379
+ * @returns {string | undefined}
380
+ */
381
+ function normalizeProjectId(value, message, required = false) {
129
382
  if (value === undefined || value === null) {
130
383
  if (required) {
131
- throw new Error(errorMessage);
384
+ throw new Error(message);
132
385
  }
133
386
  return undefined;
134
387
  }
135
- if (typeof value !== "string" || UUID_RE.test(value.trim()) === false) {
136
- throw new Error(errorMessage);
388
+ if (typeof value !== "string" || !UUID_RE.test(value.trim())) {
389
+ throw new Error(message);
137
390
  }
138
391
  return value.trim().toLowerCase();
139
392
  }
393
+
394
+ export {
395
+ SOURCE_MAP_DEBUG_ID_KEYS,
396
+ byteSize,
397
+ errorMessage,
398
+ fileReference,
399
+ findInOrder,
400
+ isDirectory,
401
+ isFile,
402
+ isJsonList,
403
+ isJsonObject,
404
+ mapInOrder,
405
+ normalizeProjectId,
406
+ parseOptions,
407
+ pathExists,
408
+ printJson,
409
+ readJsonObject,
410
+ readText,
411
+ realPath,
412
+ relativeTo,
413
+ requireBuildDir,
414
+ requireOption,
415
+ safeResolve,
416
+ sha256File,
417
+ sortJson,
418
+ sourceMapDebugId,
419
+ stableJson
420
+ };
@@ -0,0 +1,178 @@
1
+ import { SOURCE_MAP_DEBUG_ID_KEYS, stableJson } from "./release-artifacts-common.js";
2
+ import { Buffer } from "node:buffer";
3
+ import { createHash } from "node:crypto";
4
+
5
+ /** @import { JsonObject } from "./release-artifacts-common.js" */
6
+
7
+ const DEBUG_ID_NAMESPACE = "16f4a837-7e0b-4d7c-97d9-8a7af1fd2768";
8
+ const DEBUG_ID_RE = /(?:\/\/#|\/\*#)\s*debugId=(?<debugId>[A-Za-z0-9._:-]+)/giu;
9
+ const DEBUG_ID_REGISTRY_NAME = "logbrew.release-artifact.debug-ids";
10
+ const DEBUG_ID_REGISTRY_EXPRESSION = `Symbol.for(${JSON.stringify(DEBUG_ID_REGISTRY_NAME)})`;
11
+ const HERMES_RUNTIME_DEBUG_ID_RE =
12
+ /\/\*logbrew-runtime-debug-id\*\/\/\/# debugId=(?<debugId>[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[89ab][0-9a-f]{3}-[0-9a-f]{12})/iu;
13
+ const RUNTIME_DEBUG_ID_MARKER = "/*logbrew-runtime-debug-id*/";
14
+ const SOURCE_MAPPING_COMMENT_RE = /(?:\/\/#|\/\*#)\s*sourceMappingURL=[^\r\n]*/giu;
15
+ const SOURCE_MAPPING_RE = /(?:\/\/#|\/\*#)\s*sourceMappingURL=(?<url>[^\s*]+)/iu;
16
+ const SHEBANG_LINE_RE = /^#![^\r\n]*(?:\r?\n|$)/u;
17
+ const LEADING_TRIVIA_RE = /^(?:\s|\/\/[^\r\n]*(?:\r?\n|$)|\/\*[\s\S]*?\*\/)+/u;
18
+ const UUID_BYTE_LENGTH = 16;
19
+ const UUID_TIME_LOW_LENGTH = 8;
20
+ const UUID_SHORT_GROUP_LENGTH = 4;
21
+ const UUID_NODE_LENGTH = 12;
22
+ const UUID_GROUP_LENGTHS = [
23
+ UUID_TIME_LOW_LENGTH,
24
+ UUID_SHORT_GROUP_LENGTH,
25
+ UUID_SHORT_GROUP_LENGTH,
26
+ UUID_SHORT_GROUP_LENGTH,
27
+ UUID_NODE_LENGTH
28
+ ];
29
+ const UUID_VERSION_BYTE = 6;
30
+ const UUID_VARIANT_BYTE = 8;
31
+ const UUID_VERSION_MODULUS = 16;
32
+ const UUID_VERSION_5_BITS = 80;
33
+ const UUID_VARIANT_MODULUS = 64;
34
+ const UUID_RFC_4122_VARIANT_BITS = 128;
35
+ const UUID_START = 0;
36
+ const LAST_INDEX = -1;
37
+
38
+ /**
39
+ * @param {string} source
40
+ * @returns {string | undefined}
41
+ */
42
+ function findDebugId(source) {
43
+ const runtimeDebugId = HERMES_RUNTIME_DEBUG_ID_RE.exec(source)?.groups?.["debugId"];
44
+ if (runtimeDebugId !== undefined) {
45
+ return runtimeDebugId;
46
+ }
47
+ return [...source.matchAll(DEBUG_ID_RE)].at(LAST_INDEX)?.groups?.["debugId"]?.trim();
48
+ }
49
+
50
+ /**
51
+ * @param {string} source
52
+ * @returns {string | undefined}
53
+ */
54
+ function findSourceMappingUrl(source) {
55
+ return SOURCE_MAPPING_RE.exec(source)?.groups?.["url"]?.trim();
56
+ }
57
+
58
+ /**
59
+ * @param {string} hex
60
+ * @returns {string}
61
+ */
62
+ function formatUuid(hex) {
63
+ /** @type {string[]} */
64
+ const groups = [];
65
+ let offset = UUID_START;
66
+ for (const length of UUID_GROUP_LENGTHS) {
67
+ groups.push(hex.slice(offset, offset + length));
68
+ offset += length;
69
+ }
70
+ return groups.join("-");
71
+ }
72
+
73
+ /**
74
+ * @param {string} namespace
75
+ * @param {string} name
76
+ * @returns {string}
77
+ */
78
+ function uuidV5(namespace, name) {
79
+ const bytes = createHash("sha1")
80
+ .update(Buffer.from(namespace.replaceAll("-", ""), "hex"))
81
+ .update(Buffer.from(name, "utf8"))
82
+ .digest()
83
+ .subarray(UUID_START, UUID_BYTE_LENGTH);
84
+ bytes.writeUInt8((bytes.readUInt8(UUID_VERSION_BYTE) % UUID_VERSION_MODULUS) + UUID_VERSION_5_BITS, UUID_VERSION_BYTE);
85
+ bytes.writeUInt8(
86
+ (bytes.readUInt8(UUID_VARIANT_BYTE) % UUID_VARIANT_MODULUS) + UUID_RFC_4122_VARIANT_BITS,
87
+ UUID_VARIANT_BYTE
88
+ );
89
+ return formatUuid(bytes.toString("hex"));
90
+ }
91
+
92
+ /**
93
+ * @param {JsonObject} payload
94
+ * @returns {string}
95
+ */
96
+ function canonicalSourceMapWithoutDebugId(payload) {
97
+ const keys = Object.keys(payload).filter((key) => !SOURCE_MAP_DEBUG_ID_KEYS.includes(key));
98
+ return stableJson(Object.fromEntries(keys.map((key) => [key, payload[key]])));
99
+ }
100
+
101
+ /**
102
+ * @param {string} relativeJsPath
103
+ * @param {string} jsSource
104
+ * @param {JsonObject} sourceMapPayload
105
+ * @returns {string}
106
+ */
107
+ function generateDebugId(relativeJsPath, jsSource, sourceMapPayload) {
108
+ const digest = createHash("sha256");
109
+ digest.update(relativeJsPath);
110
+ digest.update("\0");
111
+ digest.update(jsSource.replaceAll(DEBUG_ID_RE, ""));
112
+ digest.update("\0");
113
+ digest.update(canonicalSourceMapWithoutDebugId(sourceMapPayload));
114
+ return uuidV5(DEBUG_ID_NAMESPACE, digest.digest("hex"));
115
+ }
116
+
117
+ /**
118
+ * @param {string} source
119
+ * @returns {string}
120
+ */
121
+ function executableShebang(source) {
122
+ return source.startsWith("#!") ? (SHEBANG_LINE_RE.exec(source)?.[UUID_START] ?? "") : "";
123
+ }
124
+
125
+ /**
126
+ * @param {string} source
127
+ * @returns {boolean}
128
+ */
129
+ function sourceStartsWithDirective(source) {
130
+ const body = source.slice(executableShebang(source).length).replace(LEADING_TRIVIA_RE, "");
131
+ return body.startsWith("\"") || body.startsWith("'");
132
+ }
133
+
134
+ /**
135
+ * @param {string} source
136
+ * @param {string} debugId
137
+ * @param {string} relativePath
138
+ * @returns {string}
139
+ */
140
+ function sourceWithRuntimeDebugId(source, debugId, relativePath) {
141
+ if (source.includes(RUNTIME_DEBUG_ID_MARKER)) {
142
+ return source;
143
+ }
144
+ const registryLine = `;try{${RUNTIME_DEBUG_ID_MARKER}(function(){var g=globalThis,s=${DEBUG_ID_REGISTRY_EXPRESSION},r=g[s];if(!r||typeof r!=="object")r=g[s]=Object.create(null);r[${JSON.stringify(relativePath)}]=${JSON.stringify(debugId)}})()}catch(_){}\n`;
145
+ const shebang = executableShebang(source);
146
+ const separator = shebang === source && shebang !== "" ? "\n" : "";
147
+ return `${shebang}${separator}${registryLine}${source.slice(shebang.length)}`;
148
+ }
149
+
150
+ /**
151
+ * @param {string} source
152
+ * @param {string} debugId
153
+ * @param {string} relativePath
154
+ * @returns {string}
155
+ */
156
+ function sourceWithDebugId(source, debugId, relativePath) {
157
+ const prepared = sourceWithRuntimeDebugId(source, debugId, relativePath);
158
+ if (findDebugId(prepared) !== undefined) {
159
+ return prepared;
160
+ }
161
+ const debugLine = `//# debugId=${debugId}\n`;
162
+ const last = [...prepared.matchAll(SOURCE_MAPPING_COMMENT_RE)].at(LAST_INDEX);
163
+ if (last === undefined) {
164
+ return `${prepared}${prepared.endsWith("\n") ? "" : "\n"}${debugLine}`;
165
+ }
166
+ const prefix = prepared.slice(UUID_START, last.index);
167
+ const separator = prefix.endsWith("\n") || prefix.endsWith("\r") ? "" : "\n";
168
+ return `${prefix}${separator}${debugLine}${prepared.slice(last.index)}`;
169
+ }
170
+
171
+ export {
172
+ RUNTIME_DEBUG_ID_MARKER,
173
+ findDebugId,
174
+ findSourceMappingUrl,
175
+ generateDebugId,
176
+ sourceStartsWithDirective,
177
+ sourceWithDebugId
178
+ };