@rasputin-ai/core 0.5.0-alpha.9 → 0.5.1
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 +3 -3
- package/dist/announce-deploy/announce-deploy.d.ts +2 -2
- package/dist/announce-deploy/announce-deploy.d.ts.map +1 -1
- package/dist/create-client/create-client-types.d.ts +23 -8
- package/dist/create-client/create-client-types.d.ts.map +1 -1
- package/dist/create-client/create-client.d.ts.map +1 -1
- package/dist/create-client/is-client-enabled.d.ts +17 -3
- package/dist/create-client/is-client-enabled.d.ts.map +1 -1
- package/dist/create-ingest-event/create-ingest-event-types.d.ts +4 -1
- package/dist/create-ingest-event/create-ingest-event-types.d.ts.map +1 -1
- package/dist/create-ingest-event/runtime-execution-state-types.d.ts +104 -43
- package/dist/create-ingest-event/runtime-execution-state-types.d.ts.map +1 -1
- package/dist/derivation/canonical-json.d.ts +0 -1
- package/dist/derivation/canonical-json.d.ts.map +1 -1
- package/dist/derivation/hash-instrumentation-manifest.d.ts +2 -2
- package/dist/derivation/hash-instrumentation-manifest.d.ts.map +1 -1
- package/dist/derivation/rasputin-wire-tag.d.ts +14 -2
- package/dist/derivation/rasputin-wire-tag.d.ts.map +1 -1
- package/dist/derivation/sensitive-property-name.d.ts +3 -0
- package/dist/derivation/sensitive-property-name.d.ts.map +1 -0
- package/dist/derivation/sha256.d.ts +0 -1
- package/dist/derivation/sha256.d.ts.map +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +860 -1238
- package/dist/instrumentation-manifest/instrumentation-manifest-types.d.ts +26 -2
- package/dist/instrumentation-manifest/instrumentation-manifest-types.d.ts.map +1 -1
- package/dist/instrumentation-manifest/upload-instrumentation-manifest.d.ts +1 -0
- package/dist/instrumentation-manifest/upload-instrumentation-manifest.d.ts.map +1 -1
- package/dist/normalize-frames/normalize-frames.d.ts.map +1 -1
- package/dist/parse-stack/fold-synthetic-frames.d.ts +15 -0
- package/dist/parse-stack/fold-synthetic-frames.d.ts.map +1 -0
- package/dist/resolve-source-maps/resolve-source-maps.d.ts.map +1 -1
- package/dist/sdk-meta.d.ts +1 -1
- package/dist/sdk-meta.d.ts.map +1 -1
- package/dist/source-identity/source-identity.d.ts +14 -1
- package/dist/source-identity/source-identity.d.ts.map +1 -1
- package/dist/suppression/create-suppression.d.ts.map +1 -1
- package/dist/suppression/suppression-types.d.ts +2 -0
- package/dist/suppression/suppression-types.d.ts.map +1 -1
- package/dist/transport/create-transport.d.ts.map +1 -1
- package/dist/transport/node-http-fetch.d.ts +3 -0
- package/dist/transport/node-http-fetch.d.ts.map +1 -0
- package/dist/transport/process-shutdown-hooks.d.ts +8 -0
- package/dist/transport/process-shutdown-hooks.d.ts.map +1 -0
- package/dist/transport/send-batch.d.ts +1 -0
- package/dist/transport/send-batch.d.ts.map +1 -1
- package/dist/transport/transport-queue.d.ts +2 -1
- package/dist/transport/transport-queue.d.ts.map +1 -1
- package/dist/transport/transport-types.d.ts +36 -11
- package/dist/transport/transport-types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/derivation/captured-value-markers.d.ts +0 -5
- package/dist/derivation/captured-value-markers.d.ts.map +0 -1
- package/dist/derivation/evaluate-derivation-plan.d.ts +0 -53
- package/dist/derivation/evaluate-derivation-plan.d.ts.map +0 -1
- package/dist/derivation/wire-values-equal.d.ts +0 -3
- package/dist/derivation/wire-values-equal.d.ts.map +0 -1
- package/dist/instrumentation-manifest/derivation-plan-types.d.ts +0 -142
- package/dist/instrumentation-manifest/derivation-plan-types.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,27 +1,122 @@
|
|
|
1
|
+
// src/transport/node-http-fetch.ts
|
|
2
|
+
import * as http from "node:http";
|
|
3
|
+
import * as https from "node:https";
|
|
4
|
+
var headerRecord = (headers) => {
|
|
5
|
+
const view = new Headers(headers);
|
|
6
|
+
const record = {};
|
|
7
|
+
view.forEach((value, key) => {
|
|
8
|
+
record[key] = value;
|
|
9
|
+
});
|
|
10
|
+
return record;
|
|
11
|
+
};
|
|
12
|
+
var writeBody = (req, body) => {
|
|
13
|
+
if (body == null) {
|
|
14
|
+
req.end();
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (typeof body === "string" || body instanceof Uint8Array) {
|
|
18
|
+
req.end(body);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
req.end();
|
|
22
|
+
};
|
|
23
|
+
var nodeHttpFetch = (input, init) => new Promise((resolve4, reject) => {
|
|
24
|
+
let parsed;
|
|
25
|
+
try {
|
|
26
|
+
parsed = new URL(String(input));
|
|
27
|
+
} catch (error) {
|
|
28
|
+
reject(error);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const lib = parsed.protocol === "https:" ? https : http;
|
|
32
|
+
const req = lib.request(
|
|
33
|
+
{
|
|
34
|
+
protocol: parsed.protocol,
|
|
35
|
+
hostname: parsed.hostname,
|
|
36
|
+
port: parsed.port,
|
|
37
|
+
path: `${parsed.pathname}${parsed.search}`,
|
|
38
|
+
method: init?.method ?? "GET",
|
|
39
|
+
headers: headerRecord(init?.headers)
|
|
40
|
+
},
|
|
41
|
+
(response) => {
|
|
42
|
+
const chunks = [];
|
|
43
|
+
response.on("data", (chunk) => {
|
|
44
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
45
|
+
});
|
|
46
|
+
response.on("end", () => {
|
|
47
|
+
const headers = new Headers();
|
|
48
|
+
for (const [key, value] of Object.entries(response.headers)) {
|
|
49
|
+
if (value === void 0) continue;
|
|
50
|
+
if (Array.isArray(value)) {
|
|
51
|
+
for (const item of value) headers.append(key, item);
|
|
52
|
+
} else {
|
|
53
|
+
headers.set(key, value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
resolve4(
|
|
57
|
+
new Response(Buffer.concat(chunks), {
|
|
58
|
+
status: response.statusCode ?? 0,
|
|
59
|
+
headers
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
const abort = () => {
|
|
66
|
+
req.destroy();
|
|
67
|
+
reject(Object.assign(new Error("aborted"), { name: "AbortError" }));
|
|
68
|
+
};
|
|
69
|
+
if (init?.signal) {
|
|
70
|
+
if (init.signal.aborted) {
|
|
71
|
+
abort();
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
init.signal.addEventListener("abort", abort, { once: true });
|
|
75
|
+
}
|
|
76
|
+
req.setTimeout(1e4, abort);
|
|
77
|
+
req.on("error", reject);
|
|
78
|
+
writeBody(req, init?.body ?? null);
|
|
79
|
+
});
|
|
80
|
+
var defaultIngestFetch = () => process.versions.bun ? globalThis.fetch : nodeHttpFetch;
|
|
81
|
+
|
|
1
82
|
// src/announce-deploy/announce-deploy.ts
|
|
83
|
+
var trimmedString = (value) => typeof value === "string" ? value.trim() : "";
|
|
2
84
|
var announceDeploy = async (options) => {
|
|
3
|
-
if (options.enabled === false) return "skipped";
|
|
4
|
-
const release = options.release?.trim() ?? "";
|
|
5
|
-
const environment = options.environment.trim();
|
|
6
|
-
if (!environment) return "skipped";
|
|
7
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
8
85
|
try {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
86
|
+
if (options.enabled === false) return "skipped";
|
|
87
|
+
const release = trimmedString(options.release);
|
|
88
|
+
const environment = trimmedString(options.environment);
|
|
89
|
+
if (!environment) return "skipped";
|
|
90
|
+
const fetchFn = options.fetch ?? defaultIngestFetch();
|
|
91
|
+
const timeout = new AbortController();
|
|
92
|
+
const timer = setTimeout(() => timeout.abort(), 2e3);
|
|
93
|
+
timer.unref?.();
|
|
94
|
+
try {
|
|
95
|
+
const response = await fetchFn(options.deployUrl, {
|
|
96
|
+
method: "POST",
|
|
97
|
+
headers: {
|
|
98
|
+
Authorization: `Bearer ${options.projectApiKey}`,
|
|
99
|
+
"Content-Type": "application/json",
|
|
100
|
+
Accept: "application/json"
|
|
101
|
+
},
|
|
102
|
+
body: JSON.stringify({ release, environment }),
|
|
103
|
+
signal: timeout.signal
|
|
104
|
+
});
|
|
105
|
+
if (response.ok) return "ok";
|
|
106
|
+
return "failed";
|
|
107
|
+
} catch {
|
|
108
|
+
return "failed";
|
|
109
|
+
} finally {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
}
|
|
20
112
|
} catch {
|
|
21
113
|
return "failed";
|
|
22
114
|
}
|
|
23
115
|
};
|
|
24
116
|
|
|
117
|
+
// src/create-client/create-client.ts
|
|
118
|
+
import { Buffer as Buffer2 } from "node:buffer";
|
|
119
|
+
|
|
25
120
|
// src/create-ingest-event/truncate-ingest-message.ts
|
|
26
121
|
var MAX_MESSAGE_BYTES = 8 * 1024;
|
|
27
122
|
var utf8Bytes = (value) => Buffer.byteLength(value, "utf8");
|
|
@@ -213,74 +308,41 @@ var finalizeResolution = (resolution, stackFrames) => {
|
|
|
213
308
|
return "exact";
|
|
214
309
|
};
|
|
215
310
|
|
|
216
|
-
// src/detect-release/detect-release.ts
|
|
217
|
-
import { readFileSync } from "node:fs";
|
|
218
|
-
import { join } from "node:path";
|
|
219
|
-
var ENV_KEYS = [
|
|
220
|
-
"RASPUTIN_RELEASE",
|
|
221
|
-
"VERCEL_GIT_COMMIT_SHA",
|
|
222
|
-
"RAILWAY_GIT_COMMIT_SHA",
|
|
223
|
-
"RENDER_GIT_COMMIT",
|
|
224
|
-
"COMMIT_REF",
|
|
225
|
-
"CF_PAGES_COMMIT_SHA",
|
|
226
|
-
"HEROKU_SLUG_COMMIT",
|
|
227
|
-
"GIT_COMMIT",
|
|
228
|
-
"COMMIT_SHA",
|
|
229
|
-
"GIT_SHA"
|
|
230
|
-
];
|
|
231
|
-
var SHA_RE = /^[0-9a-f]{7,40}$/i;
|
|
232
|
-
var isSha = (value) => SHA_RE.test(value);
|
|
233
|
-
var warnInvalid = (source, value) => {
|
|
234
|
-
console.warn(
|
|
235
|
-
`[rasputin] Ignoring invalid release from ${source}: "${value}". Expected a git commit SHA (7\u201340 hex characters).`
|
|
236
|
-
);
|
|
237
|
-
};
|
|
238
|
-
var readGitHead = (cwd) => {
|
|
239
|
-
try {
|
|
240
|
-
const gitDir = join(cwd, ".git");
|
|
241
|
-
const head = readFileSync(join(gitDir, "HEAD"), "utf8").trim();
|
|
242
|
-
if (isSha(head)) return head;
|
|
243
|
-
const ref = head.replace(/^ref:\s*/, "");
|
|
244
|
-
try {
|
|
245
|
-
const sha = readFileSync(join(gitDir, ref), "utf8").trim();
|
|
246
|
-
return isSha(sha) ? sha : void 0;
|
|
247
|
-
} catch {
|
|
248
|
-
const packed = readFileSync(join(gitDir, "packed-refs"), "utf8");
|
|
249
|
-
const match = packed.match(new RegExp(`^([0-9a-f]{40}) ${ref}$`, "m"));
|
|
250
|
-
return match?.[1];
|
|
251
|
-
}
|
|
252
|
-
} catch {
|
|
253
|
-
return void 0;
|
|
254
|
-
}
|
|
255
|
-
};
|
|
256
|
-
var detectRelease = (options = {}) => {
|
|
257
|
-
const explicit = options.release?.trim();
|
|
258
|
-
if (explicit) {
|
|
259
|
-
if (isSha(explicit)) return explicit;
|
|
260
|
-
warnInvalid("release option", explicit);
|
|
261
|
-
}
|
|
262
|
-
const env = options.env ?? process.env;
|
|
263
|
-
for (const key of ENV_KEYS) {
|
|
264
|
-
const value = env[key]?.trim();
|
|
265
|
-
if (!value) continue;
|
|
266
|
-
if (isSha(value)) return value;
|
|
267
|
-
warnInvalid(key, value);
|
|
268
|
-
}
|
|
269
|
-
const fromGit = readGitHead(options.cwd ?? process.cwd());
|
|
270
|
-
if (fromGit) return fromGit;
|
|
271
|
-
console.warn(
|
|
272
|
-
"[rasputin] No release detected. Set `RASPUTIN_RELEASE` to your git commit SHA, pass `release` in RasputinInit, or deploy on a platform that exposes a commit SHA env var (e.g. VERCEL_GIT_COMMIT_SHA). Events are not sent without a release."
|
|
273
|
-
);
|
|
274
|
-
return void 0;
|
|
275
|
-
};
|
|
276
|
-
|
|
277
311
|
// src/normalize-frames/normalize-frames.ts
|
|
278
312
|
import { isAbsolute as isAbsolute2, resolve as resolve2 } from "node:path";
|
|
279
313
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
280
314
|
|
|
315
|
+
// src/parse-stack/fold-synthetic-frames.ts
|
|
316
|
+
var RASPUTIN_SHELL_PREFIX = "__rasputinShell__";
|
|
317
|
+
var RASPUTIN_HANDLE_RUN_PREFIX = "__rasputinHandleRun__";
|
|
318
|
+
var frameFile = (frame) => (frame.file ?? frame.generated?.file ?? "").replaceAll("\\", "/");
|
|
319
|
+
var functionName = (frame) => frame.function ?? "";
|
|
320
|
+
var coreFunctionName = (name) => name.trim().replace(/^(async|new|get|set|bound)\s+/, "").replace(/^Object\./, "");
|
|
321
|
+
var isRasputinShellFrame = (name) => typeof name === "string" && coreFunctionName(name).startsWith(RASPUTIN_SHELL_PREFIX);
|
|
322
|
+
var isRasputinHandleRunFrame = (name) => typeof name === "string" && coreFunctionName(name).startsWith(RASPUTIN_HANDLE_RUN_PREFIX);
|
|
323
|
+
var isEngineAsyncStoreFile = (file) => /^(node:|bun:)/i.test(file) && /async[_-]?hooks|async_local_storage|async_context_frame/i.test(file);
|
|
324
|
+
var isInternalAsyncStoreFrame = (frame) => {
|
|
325
|
+
const name = functionName(frame);
|
|
326
|
+
const file = frameFile(frame);
|
|
327
|
+
if (name === "AsyncLocalStorage.run") return true;
|
|
328
|
+
if ((name === "run" || name === "Object.run") && isEngineAsyncStoreFile(file)) return true;
|
|
329
|
+
return false;
|
|
330
|
+
};
|
|
331
|
+
var isSyntheticRasputinFrame = (frame) => {
|
|
332
|
+
const name = functionName(frame);
|
|
333
|
+
if (isRasputinShellFrame(name) || isRasputinHandleRunFrame(name)) return true;
|
|
334
|
+
return isInternalAsyncStoreFrame(frame);
|
|
335
|
+
};
|
|
336
|
+
var foldSyntheticFrames = (frames) => {
|
|
337
|
+
const filtered = frames.filter((frame) => !isSyntheticRasputinFrame(frame));
|
|
338
|
+
if (filtered.length > 0) return filtered;
|
|
339
|
+
const withoutInternals = frames.filter((frame) => !isInternalAsyncStoreFrame(frame));
|
|
340
|
+
return withoutInternals.length > 0 ? withoutInternals : [...frames];
|
|
341
|
+
};
|
|
342
|
+
|
|
281
343
|
// src/source-identity/source-identity.ts
|
|
282
344
|
import { createHash } from "node:crypto";
|
|
283
|
-
import { existsSync, readFileSync
|
|
345
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
284
346
|
import { basename, dirname, isAbsolute, relative, resolve, sep } from "node:path";
|
|
285
347
|
import { fileURLToPath } from "node:url";
|
|
286
348
|
var packageBoundaryByDirectory = /* @__PURE__ */ new Map();
|
|
@@ -307,7 +369,7 @@ var readPackageBoundary = (directory) => {
|
|
|
307
369
|
if (existsSync(packageJson)) {
|
|
308
370
|
let name;
|
|
309
371
|
try {
|
|
310
|
-
const parsed = JSON.parse(
|
|
372
|
+
const parsed = JSON.parse(readFileSync(packageJson, "utf8"));
|
|
311
373
|
if (typeof parsed.name === "string" && parsed.name.trim()) name = parsed.name.trim();
|
|
312
374
|
} catch {
|
|
313
375
|
}
|
|
@@ -390,7 +452,7 @@ var isInApp = (file, absolute, underRoot, source) => {
|
|
|
390
452
|
};
|
|
391
453
|
var normalizeFrames = (frames, options) => {
|
|
392
454
|
const appRoot = options.appRoot;
|
|
393
|
-
return frames.map((frame) => {
|
|
455
|
+
return foldSyntheticFrames(frames).map((frame) => {
|
|
394
456
|
const generated = normalizeFile(frame.generated.file, appRoot);
|
|
395
457
|
const original = frame.original ? normalizeFile(frame.original.file, appRoot) : void 0;
|
|
396
458
|
const generatedSource = generated.absolute ? sourceLocatorFromFile(generated.absolute) : void 0;
|
|
@@ -481,10 +543,10 @@ var parseStack = (stack) => {
|
|
|
481
543
|
|
|
482
544
|
// src/repo-root/repo-root-from.ts
|
|
483
545
|
import { existsSync as existsSync2 } from "node:fs";
|
|
484
|
-
import { dirname as dirname2, join
|
|
546
|
+
import { dirname as dirname2, join, resolve as resolve3 } from "node:path";
|
|
485
547
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
486
|
-
var isGitRoot = (dir) => existsSync2(
|
|
487
|
-
var hasPackageJson = (dir) => existsSync2(
|
|
548
|
+
var isGitRoot = (dir) => existsSync2(join(dir, ".git"));
|
|
549
|
+
var hasPackageJson = (dir) => existsSync2(join(dir, "package.json"));
|
|
488
550
|
var repoRootFrom = (moduleUrl) => {
|
|
489
551
|
let current = resolve3(dirname2(fileURLToPath3(moduleUrl)));
|
|
490
552
|
let packageRoot;
|
|
@@ -542,12 +604,39 @@ Or set repoRoot yourself.
|
|
|
542
604
|
|
|
543
605
|
// src/resolve-source-maps/resolve-source-maps.ts
|
|
544
606
|
import { readFile } from "node:fs/promises";
|
|
545
|
-
import { dirname as dirname3, isAbsolute as isAbsolute3, join as
|
|
607
|
+
import { dirname as dirname3, isAbsolute as isAbsolute3, join as join2 } from "node:path";
|
|
546
608
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
547
609
|
import { LEAST_UPPER_BOUND, originalPositionFor, TraceMap } from "@jridgewell/trace-mapping";
|
|
548
610
|
var SOURCE_EXT2 = /\.(ts|tsx|mts|cts)$/i;
|
|
549
611
|
var SOURCEMAP_COMMENT = /(?:\/\/[#@][ \t]*sourceMappingURL=([^\s'"]+)|\/\*[#@][ \t]*sourceMappingURL=([^\s*'"]+)[ \t]*\*\/)\s*$/;
|
|
612
|
+
var MAX_MAP_CACHE = 64;
|
|
613
|
+
var MAX_MAP_CACHE_BYTES = 8 * 1024 * 1024;
|
|
550
614
|
var mapCache = /* @__PURE__ */ new Map();
|
|
615
|
+
var mapCacheBytesByPath = /* @__PURE__ */ new Map();
|
|
616
|
+
var mapCacheBytes = 0;
|
|
617
|
+
var evictOldestMap = () => {
|
|
618
|
+
const oldest = mapCache.keys().next().value;
|
|
619
|
+
if (oldest === void 0) return false;
|
|
620
|
+
mapCache.delete(oldest);
|
|
621
|
+
mapCacheBytes = Math.max(0, mapCacheBytes - (mapCacheBytesByPath.get(oldest) ?? 0));
|
|
622
|
+
mapCacheBytesByPath.delete(oldest);
|
|
623
|
+
return true;
|
|
624
|
+
};
|
|
625
|
+
var setMapCache = (generatedPath, map, bytes) => {
|
|
626
|
+
const previous = mapCacheBytesByPath.get(generatedPath) ?? 0;
|
|
627
|
+
if (mapCache.has(generatedPath)) {
|
|
628
|
+
mapCache.delete(generatedPath);
|
|
629
|
+
mapCacheBytes = Math.max(0, mapCacheBytes - previous);
|
|
630
|
+
mapCacheBytesByPath.delete(generatedPath);
|
|
631
|
+
}
|
|
632
|
+
if (bytes > MAX_MAP_CACHE_BYTES) return;
|
|
633
|
+
while ((mapCache.size >= MAX_MAP_CACHE || mapCacheBytes + bytes > MAX_MAP_CACHE_BYTES) && evictOldestMap()) {
|
|
634
|
+
}
|
|
635
|
+
if (mapCacheBytes + bytes > MAX_MAP_CACHE_BYTES) return;
|
|
636
|
+
mapCache.set(generatedPath, map);
|
|
637
|
+
mapCacheBytesByPath.set(generatedPath, bytes);
|
|
638
|
+
mapCacheBytes += bytes;
|
|
639
|
+
};
|
|
551
640
|
var toPath = (file) => {
|
|
552
641
|
if (file.startsWith("file://")) {
|
|
553
642
|
try {
|
|
@@ -592,7 +681,7 @@ var readMapPayload = async (generatedPath) => {
|
|
|
592
681
|
if (comment?.startsWith("data:")) return decodeDataUrl(comment);
|
|
593
682
|
if (comment) {
|
|
594
683
|
try {
|
|
595
|
-
return await readFile(
|
|
684
|
+
return await readFile(join2(dirname3(generatedPath), comment), "utf8");
|
|
596
685
|
} catch {
|
|
597
686
|
}
|
|
598
687
|
}
|
|
@@ -604,18 +693,25 @@ var readMapPayload = async (generatedPath) => {
|
|
|
604
693
|
};
|
|
605
694
|
var loadTraceMap = async (generatedPath) => {
|
|
606
695
|
const cached = mapCache.get(generatedPath);
|
|
607
|
-
if (cached !== void 0)
|
|
696
|
+
if (cached !== void 0) {
|
|
697
|
+
const bytes = mapCacheBytesByPath.get(generatedPath) ?? 0;
|
|
698
|
+
mapCache.delete(generatedPath);
|
|
699
|
+
mapCacheBytesByPath.delete(generatedPath);
|
|
700
|
+
mapCache.set(generatedPath, cached);
|
|
701
|
+
mapCacheBytesByPath.set(generatedPath, bytes);
|
|
702
|
+
return cached;
|
|
703
|
+
}
|
|
608
704
|
const payload = await readMapPayload(generatedPath);
|
|
609
705
|
if (!payload) {
|
|
610
|
-
|
|
706
|
+
setMapCache(generatedPath, null, 0);
|
|
611
707
|
return null;
|
|
612
708
|
}
|
|
613
709
|
try {
|
|
614
710
|
const map = new TraceMap(payload);
|
|
615
|
-
|
|
711
|
+
setMapCache(generatedPath, map, payload.length);
|
|
616
712
|
return map;
|
|
617
713
|
} catch {
|
|
618
|
-
|
|
714
|
+
setMapCache(generatedPath, null, payload.length);
|
|
619
715
|
return null;
|
|
620
716
|
}
|
|
621
717
|
};
|
|
@@ -639,7 +735,7 @@ var resolveFrame = async (raw) => {
|
|
|
639
735
|
return {
|
|
640
736
|
...base,
|
|
641
737
|
original: {
|
|
642
|
-
file: isAbsolute3(pos.source) ? pos.source :
|
|
738
|
+
file: isAbsolute3(pos.source) ? pos.source : join2(dirname3(generatedPath), pos.source),
|
|
643
739
|
line: pos.line,
|
|
644
740
|
column: pos.column ?? void 0,
|
|
645
741
|
name: pos.name ?? void 0
|
|
@@ -659,7 +755,7 @@ var resolveSourceMaps = async (frames) => {
|
|
|
659
755
|
|
|
660
756
|
// src/sdk-meta.ts
|
|
661
757
|
var SDK_NAME = "@rasputin-ai/core";
|
|
662
|
-
var SDK_VERSION = "0.5.
|
|
758
|
+
var SDK_VERSION = "0.5.1";
|
|
663
759
|
|
|
664
760
|
// src/suppression/identity-needs-message-template.ts
|
|
665
761
|
var identityNeedsMessageTemplate = (type, code) => {
|
|
@@ -798,7 +894,8 @@ var computeBurstKey = (errorType, message, code, frames) => {
|
|
|
798
894
|
var DEFAULTS = {
|
|
799
895
|
windowMs: 6e4,
|
|
800
896
|
capPerWindow: 5,
|
|
801
|
-
maxBurstBuckets: 1e3
|
|
897
|
+
maxBurstBuckets: 1e3,
|
|
898
|
+
maxPendingSummaries: 1e3
|
|
802
899
|
};
|
|
803
900
|
var sameDim = (a, b) => (a ?? null) === (b ?? null);
|
|
804
901
|
var captureIdentity = (input) => ({
|
|
@@ -813,8 +910,14 @@ var createSuppression = (options = {}) => {
|
|
|
813
910
|
const windowMs = options.windowMs ?? DEFAULTS.windowMs;
|
|
814
911
|
const capPerWindow = options.capPerWindow ?? DEFAULTS.capPerWindow;
|
|
815
912
|
const maxBurstBuckets = options.maxBurstBuckets ?? DEFAULTS.maxBurstBuckets;
|
|
913
|
+
const maxPendingSummaries = options.maxPendingSummaries ?? DEFAULTS.maxPendingSummaries;
|
|
816
914
|
const burstBuckets = /* @__PURE__ */ new Map();
|
|
817
915
|
const pending = [];
|
|
916
|
+
const pushPending = (draft) => {
|
|
917
|
+
pending.push(draft);
|
|
918
|
+
if (pending.length > maxPendingSummaries)
|
|
919
|
+
pending.splice(0, pending.length - maxPendingSummaries);
|
|
920
|
+
};
|
|
818
921
|
const touch = (burstKey, bucket) => {
|
|
819
922
|
burstBuckets.delete(burstKey);
|
|
820
923
|
burstBuckets.set(burstKey, bucket);
|
|
@@ -825,7 +928,7 @@ var createSuppression = (options = {}) => {
|
|
|
825
928
|
if (oldest === void 0) break;
|
|
826
929
|
const bucket = burstBuckets.get(oldest);
|
|
827
930
|
if (bucket && bucket.suppressed > 0) {
|
|
828
|
-
|
|
931
|
+
pushPending(toDraft(bucket, Date.now()));
|
|
829
932
|
}
|
|
830
933
|
burstBuckets.delete(oldest);
|
|
831
934
|
}
|
|
@@ -849,7 +952,7 @@ var createSuppression = (options = {}) => {
|
|
|
849
952
|
});
|
|
850
953
|
const flushSuppressed = (bucket, windowEndMs) => {
|
|
851
954
|
if (bucket.suppressed <= 0) return;
|
|
852
|
-
|
|
955
|
+
pushPending(toDraft(bucket, windowEndMs));
|
|
853
956
|
bucket.suppressed = 0;
|
|
854
957
|
};
|
|
855
958
|
const decide = (input) => {
|
|
@@ -939,14 +1042,75 @@ var createSuppression = (options = {}) => {
|
|
|
939
1042
|
};
|
|
940
1043
|
};
|
|
941
1044
|
|
|
1045
|
+
// src/transport/process-shutdown-hooks.ts
|
|
1046
|
+
var SIGNAL_EXIT_CODES = { SIGTERM: 143, SIGINT: 130 };
|
|
1047
|
+
var RASPUTIN_PROCESS_LISTENER = Symbol.for("rasputin.process.listener.v1");
|
|
1048
|
+
var removeProcessListener = process.off.bind(process);
|
|
1049
|
+
var tagListener = (listener) => {
|
|
1050
|
+
Object.defineProperty(listener, RASPUTIN_PROCESS_LISTENER, { value: true });
|
|
1051
|
+
return listener;
|
|
1052
|
+
};
|
|
1053
|
+
var hostProcessListenerCount = (event) => {
|
|
1054
|
+
const listeners = event === "beforeExit" ? process.listeners("beforeExit") : process.listeners(event);
|
|
1055
|
+
return listeners.filter((listener) => !(RASPUTIN_PROCESS_LISTENER in listener)).length;
|
|
1056
|
+
};
|
|
1057
|
+
var exitAfterFlush = (done, code) => {
|
|
1058
|
+
void done.finally(() => {
|
|
1059
|
+
process.exit(code);
|
|
1060
|
+
});
|
|
1061
|
+
};
|
|
1062
|
+
var participants = /* @__PURE__ */ new Set();
|
|
1063
|
+
var installed = false;
|
|
1064
|
+
var shuttingDown = false;
|
|
1065
|
+
var onBeforeExit = tagListener(() => {
|
|
1066
|
+
for (const participant of participants) participant.onBeforeExit();
|
|
1067
|
+
});
|
|
1068
|
+
var handleSignal = (signal) => {
|
|
1069
|
+
if (shuttingDown) return;
|
|
1070
|
+
shuttingDown = true;
|
|
1071
|
+
const hostOwns = hostProcessListenerCount(signal) > 0;
|
|
1072
|
+
const snapshot = [...participants];
|
|
1073
|
+
const done = Promise.all(snapshot.map((participant) => participant.onSignal().catch(() => {
|
|
1074
|
+
}))).then(() => {
|
|
1075
|
+
for (const participant of snapshot) participant.dropRemaining();
|
|
1076
|
+
}).then(() => {
|
|
1077
|
+
});
|
|
1078
|
+
if (!hostOwns) exitAfterFlush(done, SIGNAL_EXIT_CODES[signal] ?? 143);
|
|
1079
|
+
};
|
|
1080
|
+
var onTerm = tagListener(() => {
|
|
1081
|
+
handleSignal("SIGTERM");
|
|
1082
|
+
});
|
|
1083
|
+
var onInt = tagListener(() => {
|
|
1084
|
+
handleSignal("SIGINT");
|
|
1085
|
+
});
|
|
1086
|
+
var registerProcessShutdownHooks = (participant) => {
|
|
1087
|
+
participants.add(participant);
|
|
1088
|
+
if (!installed) {
|
|
1089
|
+
process.on("beforeExit", onBeforeExit);
|
|
1090
|
+
process.on("SIGTERM", onTerm);
|
|
1091
|
+
process.on("SIGINT", onInt);
|
|
1092
|
+
installed = true;
|
|
1093
|
+
}
|
|
1094
|
+
return () => {
|
|
1095
|
+
participants.delete(participant);
|
|
1096
|
+
if (participants.size > 0 || !installed) return;
|
|
1097
|
+
removeProcessListener("beforeExit", onBeforeExit);
|
|
1098
|
+
removeProcessListener("SIGTERM", onTerm);
|
|
1099
|
+
removeProcessListener("SIGINT", onInt);
|
|
1100
|
+
installed = false;
|
|
1101
|
+
shuttingDown = false;
|
|
1102
|
+
};
|
|
1103
|
+
};
|
|
1104
|
+
|
|
942
1105
|
// src/transport/send-batch.ts
|
|
943
1106
|
import { gzipSync } from "node:zlib";
|
|
944
1107
|
var sleep = (ms, signal) => new Promise((resolve4) => {
|
|
945
|
-
if (signal?.aborted) {
|
|
1108
|
+
if (ms <= 0 || signal?.aborted) {
|
|
946
1109
|
resolve4();
|
|
947
1110
|
return;
|
|
948
1111
|
}
|
|
949
1112
|
const timer = setTimeout(resolve4, ms);
|
|
1113
|
+
timer.unref?.();
|
|
950
1114
|
signal?.addEventListener(
|
|
951
1115
|
"abort",
|
|
952
1116
|
() => {
|
|
@@ -960,6 +1124,25 @@ var backoffMs = (attempt) => {
|
|
|
960
1124
|
const base = Math.min(3e4, 500 * 2 ** attempt);
|
|
961
1125
|
return Math.floor(base * (0.5 + Math.random()));
|
|
962
1126
|
};
|
|
1127
|
+
var abortError = () => Object.assign(new Error("aborted"), { name: "AbortError" });
|
|
1128
|
+
var fetchUntilAborted = (fetchFn, url, init) => new Promise((resolve4, reject) => {
|
|
1129
|
+
if (init.signal.aborted) {
|
|
1130
|
+
reject(abortError());
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
const onAbort = () => reject(abortError());
|
|
1134
|
+
init.signal.addEventListener("abort", onAbort, { once: true });
|
|
1135
|
+
void fetchFn(url, init).then(
|
|
1136
|
+
(value) => {
|
|
1137
|
+
init.signal.removeEventListener("abort", onAbort);
|
|
1138
|
+
resolve4(value);
|
|
1139
|
+
},
|
|
1140
|
+
(error) => {
|
|
1141
|
+
init.signal.removeEventListener("abort", onAbort);
|
|
1142
|
+
reject(error);
|
|
1143
|
+
}
|
|
1144
|
+
);
|
|
1145
|
+
});
|
|
963
1146
|
var retryAfterMs = (response) => {
|
|
964
1147
|
const header = response.headers.get("retry-after");
|
|
965
1148
|
if (!header) return null;
|
|
@@ -994,14 +1177,22 @@ var sendBatch = async (options) => {
|
|
|
994
1177
|
failureKind,
|
|
995
1178
|
statusCode
|
|
996
1179
|
});
|
|
1180
|
+
const abortAfter = (ms) => {
|
|
1181
|
+
const controller = new AbortController();
|
|
1182
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
1183
|
+
timer.unref?.();
|
|
1184
|
+
return { signal: controller.signal, cancel: () => clearTimeout(timer) };
|
|
1185
|
+
};
|
|
1186
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 2e3;
|
|
997
1187
|
const json = JSON.stringify(payload);
|
|
1188
|
+
const jsonBytes = Buffer.byteLength(json, "utf8");
|
|
998
1189
|
const headers = {
|
|
999
1190
|
Authorization: `Bearer ${options.projectApiKey}`,
|
|
1000
1191
|
"Content-Type": "application/json",
|
|
1001
1192
|
Accept: "application/json"
|
|
1002
1193
|
};
|
|
1003
1194
|
let body = json;
|
|
1004
|
-
if (
|
|
1195
|
+
if (jsonBytes >= options.gzipThresholdBytes) {
|
|
1005
1196
|
const compressed = gzipSync(json);
|
|
1006
1197
|
const bytes = new Uint8Array(compressed.byteLength);
|
|
1007
1198
|
bytes.set(compressed);
|
|
@@ -1010,13 +1201,15 @@ var sendBatch = async (options) => {
|
|
|
1010
1201
|
}
|
|
1011
1202
|
for (let attempt = 0; attempt <= options.maxRetries; attempt++) {
|
|
1012
1203
|
if (options.signal?.aborted) return result("failed", "aborted");
|
|
1204
|
+
attempts++;
|
|
1205
|
+
const timeout = abortAfter(requestTimeoutMs);
|
|
1206
|
+
const signal = options.signal ? AbortSignal.any([options.signal, timeout.signal]) : timeout.signal;
|
|
1013
1207
|
try {
|
|
1014
|
-
|
|
1015
|
-
const response = await options.fetch(options.ingestUrl, {
|
|
1208
|
+
const response = await fetchUntilAborted(options.fetch, options.ingestUrl, {
|
|
1016
1209
|
method: "POST",
|
|
1017
1210
|
headers,
|
|
1018
1211
|
body,
|
|
1019
|
-
signal
|
|
1212
|
+
signal
|
|
1020
1213
|
});
|
|
1021
1214
|
if (response.ok) return result("ok");
|
|
1022
1215
|
if (response.status === 429) {
|
|
@@ -1038,6 +1231,8 @@ var sendBatch = async (options) => {
|
|
|
1038
1231
|
networkErrors++;
|
|
1039
1232
|
if (attempt === options.maxRetries) return result("failed", "network_error");
|
|
1040
1233
|
await sleep(backoffMs(attempt), options.signal);
|
|
1234
|
+
} finally {
|
|
1235
|
+
timeout.cancel();
|
|
1041
1236
|
}
|
|
1042
1237
|
}
|
|
1043
1238
|
return result("failed", options.signal?.aborted ? "aborted" : "network_error");
|
|
@@ -1049,11 +1244,40 @@ var RANK = {
|
|
|
1049
1244
|
summary: 1,
|
|
1050
1245
|
first: 2
|
|
1051
1246
|
};
|
|
1052
|
-
var createQueue = (maxSize) => {
|
|
1247
|
+
var createQueue = (maxSize, maxBytes = 8 * 1024 * 1024) => {
|
|
1053
1248
|
const items = [];
|
|
1249
|
+
const itemBytes = [];
|
|
1054
1250
|
let enqueued = 0;
|
|
1055
1251
|
let droppedIncoming = 0;
|
|
1056
1252
|
let droppedQueued = 0;
|
|
1253
|
+
let queuedBytes = 0;
|
|
1254
|
+
let reservedBytes = 0;
|
|
1255
|
+
const estimateBytes = (item) => {
|
|
1256
|
+
let bytes = 256;
|
|
1257
|
+
try {
|
|
1258
|
+
bytes = Buffer.byteLength(
|
|
1259
|
+
JSON.stringify(item.kind === "event" ? item.event : item.summary),
|
|
1260
|
+
"utf8"
|
|
1261
|
+
);
|
|
1262
|
+
} catch {
|
|
1263
|
+
bytes = 256;
|
|
1264
|
+
}
|
|
1265
|
+
for (const frame of item.rawFrames) {
|
|
1266
|
+
try {
|
|
1267
|
+
bytes += Buffer.byteLength(JSON.stringify(frame), "utf8");
|
|
1268
|
+
} catch {
|
|
1269
|
+
bytes += 64;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
return bytes;
|
|
1273
|
+
};
|
|
1274
|
+
const dropAt = (index) => {
|
|
1275
|
+
const bytes = itemBytes[index] ?? 0;
|
|
1276
|
+
items.splice(index, 1);
|
|
1277
|
+
itemBytes.splice(index, 1);
|
|
1278
|
+
queuedBytes = Math.max(0, queuedBytes - bytes);
|
|
1279
|
+
droppedQueued++;
|
|
1280
|
+
};
|
|
1057
1281
|
const oldestLowestIndex = () => {
|
|
1058
1282
|
let best = 0;
|
|
1059
1283
|
for (let i = 1; i < items.length; i++) {
|
|
@@ -1065,7 +1289,17 @@ var createQueue = (maxSize) => {
|
|
|
1065
1289
|
return best;
|
|
1066
1290
|
};
|
|
1067
1291
|
const enqueue = (item) => {
|
|
1068
|
-
|
|
1292
|
+
const bytes = item.encodedBytes ?? estimateBytes(item);
|
|
1293
|
+
item.encodedBytes = bytes;
|
|
1294
|
+
if (bytes > maxBytes) {
|
|
1295
|
+
droppedIncoming++;
|
|
1296
|
+
return;
|
|
1297
|
+
}
|
|
1298
|
+
while (items.length >= maxSize || queuedBytes + reservedBytes + bytes > maxBytes) {
|
|
1299
|
+
if (items.length === 0) {
|
|
1300
|
+
droppedIncoming++;
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1069
1303
|
const victimIndex = oldestLowestIndex();
|
|
1070
1304
|
const victim = items[victimIndex];
|
|
1071
1305
|
if (!victim) break;
|
|
@@ -1073,16 +1307,25 @@ var createQueue = (maxSize) => {
|
|
|
1073
1307
|
droppedIncoming++;
|
|
1074
1308
|
return;
|
|
1075
1309
|
}
|
|
1076
|
-
|
|
1077
|
-
droppedQueued++;
|
|
1310
|
+
dropAt(victimIndex);
|
|
1078
1311
|
}
|
|
1079
1312
|
items.push(item);
|
|
1313
|
+
itemBytes.push(bytes);
|
|
1314
|
+
queuedBytes += bytes;
|
|
1080
1315
|
enqueued++;
|
|
1081
1316
|
};
|
|
1082
|
-
const drain = (count) =>
|
|
1317
|
+
const drain = (count) => {
|
|
1318
|
+
const drained = items.splice(0, count);
|
|
1319
|
+
const drainedBytes = itemBytes.splice(0, count);
|
|
1320
|
+
for (const size of drainedBytes) queuedBytes = Math.max(0, queuedBytes - size);
|
|
1321
|
+
return drained;
|
|
1322
|
+
};
|
|
1083
1323
|
return {
|
|
1084
1324
|
enqueue,
|
|
1085
1325
|
drain,
|
|
1326
|
+
setReservedBytes: (bytes) => {
|
|
1327
|
+
reservedBytes = Math.max(0, bytes);
|
|
1328
|
+
},
|
|
1086
1329
|
size: () => items.length,
|
|
1087
1330
|
getStats: () => ({
|
|
1088
1331
|
queued: items.length,
|
|
@@ -1093,6 +1336,8 @@ var createQueue = (maxSize) => {
|
|
|
1093
1336
|
}),
|
|
1094
1337
|
clear: () => {
|
|
1095
1338
|
items.length = 0;
|
|
1339
|
+
itemBytes.length = 0;
|
|
1340
|
+
queuedBytes = 0;
|
|
1096
1341
|
}
|
|
1097
1342
|
};
|
|
1098
1343
|
};
|
|
@@ -1101,25 +1346,15 @@ var createQueue = (maxSize) => {
|
|
|
1101
1346
|
var DEFAULTS2 = {
|
|
1102
1347
|
enabled: true,
|
|
1103
1348
|
maxQueueSize: 500,
|
|
1349
|
+
maxQueueBytes: 8 * 1024 * 1024,
|
|
1104
1350
|
batchSize: 30,
|
|
1105
1351
|
flushIntervalMs: 5e3,
|
|
1106
1352
|
gzipThresholdBytes: 10 * 1024,
|
|
1107
1353
|
maxRetries: 5,
|
|
1108
|
-
installSignalHandlers: true
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
const nativeExit = process.exit.bind(process);
|
|
1113
|
-
let heldCode;
|
|
1114
|
-
const restore = () => {
|
|
1115
|
-
process.exit = nativeExit;
|
|
1116
|
-
if (heldCode !== void 0) nativeExit(heldCode);
|
|
1117
|
-
};
|
|
1118
|
-
const holdExit = ((code) => {
|
|
1119
|
-
heldCode = code ?? 0;
|
|
1120
|
-
});
|
|
1121
|
-
process.exit = holdExit;
|
|
1122
|
-
void done.finally(restore);
|
|
1354
|
+
installSignalHandlers: true,
|
|
1355
|
+
maxBatchReplays: 8,
|
|
1356
|
+
maxRetryBatchAgeMs: 6e4,
|
|
1357
|
+
shutdownFlushMs: 2e3
|
|
1123
1358
|
};
|
|
1124
1359
|
var createTransport = (options) => {
|
|
1125
1360
|
const enabled = options.enabled ?? DEFAULTS2.enabled;
|
|
@@ -1127,12 +1362,16 @@ var createTransport = (options) => {
|
|
|
1127
1362
|
const flushIntervalMs = options.flushIntervalMs ?? DEFAULTS2.flushIntervalMs;
|
|
1128
1363
|
const gzipThresholdBytes = options.gzipThresholdBytes ?? DEFAULTS2.gzipThresholdBytes;
|
|
1129
1364
|
const maxRetries = options.maxRetries ?? DEFAULTS2.maxRetries;
|
|
1130
|
-
const
|
|
1131
|
-
const
|
|
1365
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? 2e3;
|
|
1366
|
+
const fetchFn = options.fetch ?? defaultIngestFetch();
|
|
1367
|
+
const queue = createQueue(
|
|
1368
|
+
options.maxQueueSize ?? DEFAULTS2.maxQueueSize,
|
|
1369
|
+
options.maxQueueBytes ?? DEFAULTS2.maxQueueBytes
|
|
1370
|
+
);
|
|
1132
1371
|
let timer;
|
|
1133
1372
|
let flushing;
|
|
1134
1373
|
let closed = false;
|
|
1135
|
-
let
|
|
1374
|
+
let shuttingDown2 = false;
|
|
1136
1375
|
let retryBatch = null;
|
|
1137
1376
|
let flushesStarted = 0;
|
|
1138
1377
|
let flushesJoined = 0;
|
|
@@ -1148,10 +1387,45 @@ var createTransport = (options) => {
|
|
|
1148
1387
|
let serverErrorResponses = 0;
|
|
1149
1388
|
let lastFailureKind = null;
|
|
1150
1389
|
let lastFailureStatusCode = null;
|
|
1390
|
+
let flushAbort;
|
|
1391
|
+
let flushAbortTimer;
|
|
1392
|
+
let flushDeadlineMs = 0;
|
|
1393
|
+
let inFlightBytes = 0;
|
|
1394
|
+
let retryBytes = 0;
|
|
1395
|
+
const estimateItemsBytes = (items) => {
|
|
1396
|
+
let bytes = 0;
|
|
1397
|
+
for (const item of items) {
|
|
1398
|
+
bytes += item.encodedBytes ?? 256;
|
|
1399
|
+
}
|
|
1400
|
+
return bytes;
|
|
1401
|
+
};
|
|
1402
|
+
const syncReservedBytes = () => {
|
|
1403
|
+
queue.setReservedBytes(inFlightBytes + retryBytes);
|
|
1404
|
+
};
|
|
1405
|
+
const setFlushDeadline = (timeoutMs, holdProcess = false) => {
|
|
1406
|
+
const nextDeadline = timeoutMs > 0 ? Date.now() + timeoutMs : Number.POSITIVE_INFINITY;
|
|
1407
|
+
if (flushAbort && nextDeadline >= flushDeadlineMs) return;
|
|
1408
|
+
flushDeadlineMs = nextDeadline;
|
|
1409
|
+
if (!flushAbort) flushAbort = new AbortController();
|
|
1410
|
+
if (flushAbortTimer) clearTimeout(flushAbortTimer);
|
|
1411
|
+
if (Number.isFinite(nextDeadline)) {
|
|
1412
|
+
flushAbortTimer = setTimeout(
|
|
1413
|
+
() => flushAbort?.abort(),
|
|
1414
|
+
Math.max(0, nextDeadline - Date.now())
|
|
1415
|
+
);
|
|
1416
|
+
if (!holdProcess) flushAbortTimer.unref?.();
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1419
|
+
const clearFlushDeadline = () => {
|
|
1420
|
+
if (flushAbortTimer) clearTimeout(flushAbortTimer);
|
|
1421
|
+
flushAbortTimer = void 0;
|
|
1422
|
+
flushAbort = void 0;
|
|
1423
|
+
flushDeadlineMs = 0;
|
|
1424
|
+
};
|
|
1151
1425
|
const schedule = () => {
|
|
1152
|
-
if (timer || !enabled || closed) return;
|
|
1426
|
+
if (timer || !enabled || closed || shuttingDown2) return;
|
|
1153
1427
|
timer = setInterval(() => {
|
|
1154
|
-
void
|
|
1428
|
+
void kickBackgroundFlush();
|
|
1155
1429
|
}, flushIntervalMs);
|
|
1156
1430
|
timer.unref?.();
|
|
1157
1431
|
};
|
|
@@ -1169,40 +1443,81 @@ var createTransport = (options) => {
|
|
|
1169
1443
|
return item.summary;
|
|
1170
1444
|
}
|
|
1171
1445
|
};
|
|
1172
|
-
const
|
|
1173
|
-
const
|
|
1174
|
-
|
|
1446
|
+
const whenAborted = (signal) => new Promise((_, reject) => {
|
|
1447
|
+
const abort = () => reject(signal.reason ?? new Error("aborted"));
|
|
1448
|
+
if (signal.aborted) {
|
|
1449
|
+
abort();
|
|
1450
|
+
return;
|
|
1451
|
+
}
|
|
1452
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
1453
|
+
});
|
|
1454
|
+
const performFlush = async () => {
|
|
1455
|
+
options.beforeFlush?.();
|
|
1456
|
+
const controller = flushAbort ?? new AbortController();
|
|
1175
1457
|
try {
|
|
1176
1458
|
while (queue.size() > 0 || retryBatch) {
|
|
1177
1459
|
if (controller.signal.aborted) break;
|
|
1178
1460
|
const replaying = retryBatch !== null;
|
|
1179
1461
|
const batch = retryBatch?.items ?? queue.drain(batchSize);
|
|
1180
1462
|
const idempotencyKey = retryBatch?.idempotencyKey ?? crypto.randomUUID();
|
|
1463
|
+
const retryCreatedAt = retryBatch?.createdAt ?? Date.now();
|
|
1464
|
+
const retryReplays = retryBatch?.replays ?? 0;
|
|
1181
1465
|
retryBatch = null;
|
|
1466
|
+
retryBytes = 0;
|
|
1467
|
+
inFlightBytes = estimateItemsBytes(batch);
|
|
1468
|
+
syncReservedBytes();
|
|
1182
1469
|
if (batch.length === 0) break;
|
|
1183
1470
|
if (replaying) batchReplays++;
|
|
1184
1471
|
const events = [];
|
|
1185
1472
|
const summaries = [];
|
|
1186
1473
|
for (const item of batch) {
|
|
1474
|
+
if (controller.signal.aborted) break;
|
|
1187
1475
|
if (item.kind === "summary") {
|
|
1188
|
-
|
|
1476
|
+
try {
|
|
1477
|
+
summaries.push(
|
|
1478
|
+
await Promise.race([prepareSummary(item), whenAborted(controller.signal)])
|
|
1479
|
+
);
|
|
1480
|
+
} catch {
|
|
1481
|
+
if (controller.signal.aborted) break;
|
|
1482
|
+
summaries.push(item.summary);
|
|
1483
|
+
}
|
|
1189
1484
|
continue;
|
|
1190
1485
|
}
|
|
1191
1486
|
if (options.prepareEvent && item.rawFrames.length > 0) {
|
|
1192
1487
|
try {
|
|
1193
1488
|
events.push(
|
|
1194
|
-
await
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1489
|
+
await Promise.race([
|
|
1490
|
+
options.prepareEvent({
|
|
1491
|
+
event: item.event,
|
|
1492
|
+
rawFrames: item.rawFrames
|
|
1493
|
+
}),
|
|
1494
|
+
whenAborted(controller.signal)
|
|
1495
|
+
])
|
|
1198
1496
|
);
|
|
1199
1497
|
} catch {
|
|
1498
|
+
if (controller.signal.aborted) break;
|
|
1200
1499
|
events.push(item.event);
|
|
1201
1500
|
}
|
|
1202
1501
|
} else {
|
|
1203
1502
|
events.push(item.event);
|
|
1204
1503
|
}
|
|
1205
1504
|
}
|
|
1505
|
+
const retainOrDrop = (nextReplays, createdAt) => {
|
|
1506
|
+
if (nextReplays >= DEFAULTS2.maxBatchReplays || Date.now() - createdAt >= DEFAULTS2.maxRetryBatchAgeMs) {
|
|
1507
|
+
batchesDropped++;
|
|
1508
|
+
retryBatch = null;
|
|
1509
|
+
retryBytes = 0;
|
|
1510
|
+
} else {
|
|
1511
|
+
retryBatch = { items: batch, idempotencyKey, createdAt, replays: nextReplays };
|
|
1512
|
+
retryBytes = inFlightBytes;
|
|
1513
|
+
}
|
|
1514
|
+
inFlightBytes = 0;
|
|
1515
|
+
syncReservedBytes();
|
|
1516
|
+
};
|
|
1517
|
+
if (controller.signal.aborted) {
|
|
1518
|
+
retainOrDrop((replaying ? retryReplays : 0) + 1, replaying ? retryCreatedAt : Date.now());
|
|
1519
|
+
break;
|
|
1520
|
+
}
|
|
1206
1521
|
const result = await sendBatch({
|
|
1207
1522
|
ingestUrl: options.ingestUrl,
|
|
1208
1523
|
projectApiKey: options.projectApiKey,
|
|
@@ -1212,7 +1527,8 @@ var createTransport = (options) => {
|
|
|
1212
1527
|
sdkVersion: options.sdkVersion,
|
|
1213
1528
|
sdkName: options.sdkName,
|
|
1214
1529
|
gzipThresholdBytes,
|
|
1215
|
-
maxRetries,
|
|
1530
|
+
maxRetries: shuttingDown2 ? 0 : maxRetries,
|
|
1531
|
+
requestTimeoutMs,
|
|
1216
1532
|
fetch: fetchFn,
|
|
1217
1533
|
signal: controller.signal
|
|
1218
1534
|
});
|
|
@@ -1230,70 +1546,120 @@ var createTransport = (options) => {
|
|
|
1230
1546
|
else batchesFailed++;
|
|
1231
1547
|
}
|
|
1232
1548
|
if (result.outcome === "failed") {
|
|
1233
|
-
|
|
1549
|
+
retainOrDrop(
|
|
1550
|
+
result.aborted ? (replaying ? retryReplays : 0) + 1 : replaying ? retryReplays + 1 : 0,
|
|
1551
|
+
replaying ? retryCreatedAt : Date.now()
|
|
1552
|
+
);
|
|
1234
1553
|
break;
|
|
1235
1554
|
}
|
|
1555
|
+
inFlightBytes = 0;
|
|
1556
|
+
syncReservedBytes();
|
|
1236
1557
|
}
|
|
1237
1558
|
} finally {
|
|
1238
|
-
|
|
1559
|
+
clearFlushDeadline();
|
|
1239
1560
|
if (queue.size() === 0 && !retryBatch) stopTimer();
|
|
1240
1561
|
}
|
|
1241
1562
|
};
|
|
1563
|
+
const startFlushWorker = () => {
|
|
1564
|
+
if (flushing) return flushing;
|
|
1565
|
+
flushesStarted++;
|
|
1566
|
+
let settle;
|
|
1567
|
+
const activeFlush = new Promise((resolve4, reject) => {
|
|
1568
|
+
settle = (work) => {
|
|
1569
|
+
void work.then(resolve4, reject);
|
|
1570
|
+
};
|
|
1571
|
+
});
|
|
1572
|
+
flushing = activeFlush;
|
|
1573
|
+
settle(performFlush());
|
|
1574
|
+
void activeFlush.finally(() => {
|
|
1575
|
+
if (flushing === activeFlush) flushing = void 0;
|
|
1576
|
+
});
|
|
1577
|
+
return activeFlush;
|
|
1578
|
+
};
|
|
1579
|
+
const kickBackgroundFlush = () => {
|
|
1580
|
+
if (!enabled || closed || shuttingDown2) return;
|
|
1581
|
+
setFlushDeadline(1e4, false);
|
|
1582
|
+
if (flushing) return;
|
|
1583
|
+
startFlushWorker();
|
|
1584
|
+
};
|
|
1242
1585
|
const flush = async (timeoutMs = 1e4) => {
|
|
1243
1586
|
if (!enabled || closed) {
|
|
1244
1587
|
queue.clear();
|
|
1245
1588
|
retryBatch = null;
|
|
1246
1589
|
return;
|
|
1247
1590
|
}
|
|
1591
|
+
setFlushDeadline(timeoutMs, true);
|
|
1248
1592
|
if (flushing) {
|
|
1249
1593
|
flushesJoined++;
|
|
1250
1594
|
return flushing;
|
|
1251
1595
|
}
|
|
1252
|
-
|
|
1253
|
-
const activeFlush = performFlush(timeoutMs);
|
|
1254
|
-
flushing = activeFlush;
|
|
1255
|
-
try {
|
|
1256
|
-
await activeFlush;
|
|
1257
|
-
} finally {
|
|
1258
|
-
if (flushing === activeFlush) flushing = void 0;
|
|
1259
|
-
}
|
|
1596
|
+
await startFlushWorker();
|
|
1260
1597
|
};
|
|
1261
|
-
const enqueue = (event, priority = "first", rawFrames = []) => {
|
|
1598
|
+
const enqueue = (event, priority = "first", rawFrames = [], encodedBytes) => {
|
|
1262
1599
|
if (!enabled || closed) return;
|
|
1263
|
-
queue.enqueue({ kind: "event", event, priority, rawFrames });
|
|
1600
|
+
queue.enqueue({ kind: "event", event, priority, rawFrames, encodedBytes });
|
|
1264
1601
|
schedule();
|
|
1265
|
-
if (queue.size() >= batchSize)
|
|
1602
|
+
if (queue.size() >= batchSize) kickBackgroundFlush();
|
|
1266
1603
|
};
|
|
1267
1604
|
const enqueueSummary = (summary, rawFrames = []) => {
|
|
1268
1605
|
if (!enabled || closed) return;
|
|
1269
1606
|
queue.enqueue({ kind: "summary", summary, priority: "summary", rawFrames });
|
|
1270
1607
|
schedule();
|
|
1271
|
-
if (queue.size() >= batchSize)
|
|
1608
|
+
if (queue.size() >= batchSize) kickBackgroundFlush();
|
|
1609
|
+
};
|
|
1610
|
+
const dropRemainingOnExit = () => {
|
|
1611
|
+
const remaining = queue.size() + (retryBatch?.items.length ?? 0);
|
|
1612
|
+
if (remaining === 0) return;
|
|
1613
|
+
queue.clear();
|
|
1614
|
+
retryBatch = null;
|
|
1615
|
+
retryBytes = 0;
|
|
1616
|
+
inFlightBytes = 0;
|
|
1617
|
+
syncReservedBytes();
|
|
1618
|
+
console.error(
|
|
1619
|
+
`[rasputin] Dropped ${remaining} telemetry event${remaining === 1 ? "" : "s"} on exit because ingest did not accept them in time.`
|
|
1620
|
+
);
|
|
1272
1621
|
};
|
|
1273
|
-
const
|
|
1274
|
-
if (closed ||
|
|
1622
|
+
const onBeforeExit2 = () => {
|
|
1623
|
+
if (closed || shuttingDown2) return;
|
|
1275
1624
|
if (queue.size() === 0 && !retryBatch && !flushing) return;
|
|
1276
|
-
|
|
1277
|
-
|
|
1625
|
+
shuttingDown2 = true;
|
|
1626
|
+
stopTimer();
|
|
1627
|
+
options.beforeFlush?.();
|
|
1628
|
+
void flush(DEFAULTS2.shutdownFlushMs).catch(() => {
|
|
1629
|
+
}).finally(dropRemainingOnExit);
|
|
1278
1630
|
};
|
|
1279
|
-
const onSignal = () => {
|
|
1280
|
-
if (
|
|
1281
|
-
|
|
1631
|
+
const onSignal = async () => {
|
|
1632
|
+
if (shuttingDown2) return;
|
|
1633
|
+
shuttingDown2 = true;
|
|
1282
1634
|
stopTimer();
|
|
1283
|
-
|
|
1284
|
-
|
|
1635
|
+
options.beforeFlush?.();
|
|
1636
|
+
await flush(DEFAULTS2.shutdownFlushMs).catch(() => {
|
|
1637
|
+
});
|
|
1638
|
+
};
|
|
1639
|
+
const unregisterSignals = enabled && (options.installSignalHandlers ?? DEFAULTS2.installSignalHandlers) ? registerProcessShutdownHooks({
|
|
1640
|
+
onBeforeExit: onBeforeExit2,
|
|
1641
|
+
onSignal,
|
|
1642
|
+
dropRemaining: dropRemainingOnExit
|
|
1643
|
+
}) : () => {
|
|
1285
1644
|
};
|
|
1286
|
-
if (enabled && (options.installSignalHandlers ?? DEFAULTS2.installSignalHandlers)) {
|
|
1287
|
-
process.on("beforeExit", onBeforeExit);
|
|
1288
|
-
process.on("SIGTERM", onSignal);
|
|
1289
|
-
process.on("SIGINT", onSignal);
|
|
1290
|
-
}
|
|
1291
1645
|
const close = async () => {
|
|
1292
1646
|
stopTimer();
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1647
|
+
unregisterSignals();
|
|
1648
|
+
shuttingDown2 = true;
|
|
1649
|
+
await new Promise((resolve4, reject) => {
|
|
1650
|
+
const timer2 = setTimeout(resolve4, DEFAULTS2.shutdownFlushMs + 250);
|
|
1651
|
+
void flush(DEFAULTS2.shutdownFlushMs).then(
|
|
1652
|
+
() => {
|
|
1653
|
+
clearTimeout(timer2);
|
|
1654
|
+
resolve4();
|
|
1655
|
+
},
|
|
1656
|
+
(error) => {
|
|
1657
|
+
clearTimeout(timer2);
|
|
1658
|
+
reject(error);
|
|
1659
|
+
}
|
|
1660
|
+
);
|
|
1661
|
+
});
|
|
1662
|
+
dropRemainingOnExit();
|
|
1297
1663
|
closed = true;
|
|
1298
1664
|
queue.clear();
|
|
1299
1665
|
retryBatch = null;
|
|
@@ -1328,55 +1694,126 @@ var createTransport = (options) => {
|
|
|
1328
1694
|
};
|
|
1329
1695
|
};
|
|
1330
1696
|
|
|
1331
|
-
// src/
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1697
|
+
// src/detect-release/detect-release.ts
|
|
1698
|
+
import { readFileSync as readFileSync2 } from "node:fs";
|
|
1699
|
+
import { join as join3 } from "node:path";
|
|
1700
|
+
var ENV_KEYS = [
|
|
1701
|
+
"RASPUTIN_RELEASE",
|
|
1702
|
+
"VERCEL_GIT_COMMIT_SHA",
|
|
1703
|
+
"RAILWAY_GIT_COMMIT_SHA",
|
|
1704
|
+
"RENDER_GIT_COMMIT",
|
|
1705
|
+
"COMMIT_REF",
|
|
1706
|
+
"CF_PAGES_COMMIT_SHA",
|
|
1707
|
+
"HEROKU_SLUG_COMMIT",
|
|
1708
|
+
"GIT_COMMIT",
|
|
1709
|
+
"COMMIT_SHA",
|
|
1710
|
+
"GIT_SHA"
|
|
1711
|
+
];
|
|
1712
|
+
var SHA_RE = /^[0-9a-f]{7,40}$/i;
|
|
1713
|
+
var isSha = (value) => SHA_RE.test(value);
|
|
1714
|
+
var warnInvalid = (source, value) => {
|
|
1715
|
+
console.warn(
|
|
1716
|
+
`[rasputin] Ignoring invalid release from ${source}: "${value}". Expected a git commit SHA (7\u201340 hex characters).`
|
|
1717
|
+
);
|
|
1718
|
+
};
|
|
1719
|
+
var readGitHead = (cwd) => {
|
|
1720
|
+
try {
|
|
1721
|
+
const gitDir = join3(cwd, ".git");
|
|
1722
|
+
const head = readFileSync2(join3(gitDir, "HEAD"), "utf8").trim();
|
|
1723
|
+
if (isSha(head)) return head;
|
|
1724
|
+
const ref = head.replace(/^ref:\s*/, "");
|
|
1725
|
+
try {
|
|
1726
|
+
const sha = readFileSync2(join3(gitDir, ref), "utf8").trim();
|
|
1727
|
+
return isSha(sha) ? sha : void 0;
|
|
1728
|
+
} catch {
|
|
1729
|
+
const packed = readFileSync2(join3(gitDir, "packed-refs"), "utf8");
|
|
1730
|
+
const match = packed.match(new RegExp(`^([0-9a-f]{40}) ${ref}$`, "m"));
|
|
1731
|
+
return match?.[1];
|
|
1732
|
+
}
|
|
1733
|
+
} catch {
|
|
1734
|
+
return void 0;
|
|
1735
|
+
}
|
|
1736
|
+
};
|
|
1737
|
+
var detectRelease = (options = {}) => {
|
|
1738
|
+
const explicit = options.release?.trim();
|
|
1739
|
+
if (explicit) {
|
|
1740
|
+
if (isSha(explicit)) return explicit;
|
|
1741
|
+
warnInvalid("release option", explicit);
|
|
1742
|
+
}
|
|
1743
|
+
const env = options.env ?? process.env;
|
|
1744
|
+
for (const key of ENV_KEYS) {
|
|
1745
|
+
const value = env[key]?.trim();
|
|
1746
|
+
if (!value) continue;
|
|
1747
|
+
if (isSha(value)) return value;
|
|
1748
|
+
warnInvalid(key, value);
|
|
1749
|
+
}
|
|
1750
|
+
const fromGit = readGitHead(options.cwd ?? process.cwd());
|
|
1751
|
+
if (fromGit) return fromGit;
|
|
1752
|
+
console.warn(
|
|
1753
|
+
"[rasputin] No release detected. Set `RASPUTIN_RELEASE` to your git commit SHA, pass `release` in RasputinInit, or deploy on a platform that exposes a commit SHA env var (e.g. VERCEL_GIT_COMMIT_SHA). Events are not sent without a release."
|
|
1754
|
+
);
|
|
1755
|
+
return void 0;
|
|
1756
|
+
};
|
|
1757
|
+
|
|
1758
|
+
// src/create-client/is-client-enabled.ts
|
|
1759
|
+
var resolveClientActivation = (options) => {
|
|
1760
|
+
if (options.enabled === false) return { enabled: false };
|
|
1761
|
+
const projectApiKey = typeof options.projectApiKey === "string" ? options.projectApiKey.trim() : "";
|
|
1762
|
+
if (!projectApiKey) return { enabled: false };
|
|
1763
|
+
const explicit = typeof options.release === "string" ? options.release.trim() : "";
|
|
1764
|
+
if (!explicit) return { enabled: false };
|
|
1765
|
+
const release = detectRelease({ release: explicit });
|
|
1766
|
+
if (!release) return { enabled: false };
|
|
1767
|
+
return { enabled: true, projectApiKey, release };
|
|
1768
|
+
};
|
|
1769
|
+
var isClientEnabled = (options) => resolveClientActivation(options).enabled;
|
|
1770
|
+
var noopClient = () => ({
|
|
1771
|
+
captureException: () => {
|
|
1772
|
+
},
|
|
1773
|
+
flush: async () => {
|
|
1774
|
+
},
|
|
1775
|
+
close: async () => {
|
|
1776
|
+
},
|
|
1777
|
+
getStats: () => ({
|
|
1778
|
+
transport: {
|
|
1779
|
+
queued: 0,
|
|
1780
|
+
enqueued: 0,
|
|
1781
|
+
droppedIncoming: 0,
|
|
1782
|
+
droppedQueued: 0,
|
|
1783
|
+
droppedTotal: 0,
|
|
1784
|
+
flushesStarted: 0,
|
|
1785
|
+
flushesJoined: 0,
|
|
1786
|
+
sendAttempts: 0,
|
|
1787
|
+
sendRetries: 0,
|
|
1788
|
+
batchReplays: 0,
|
|
1789
|
+
batchesSucceeded: 0,
|
|
1790
|
+
batchesDropped: 0,
|
|
1791
|
+
batchesFailed: 0,
|
|
1792
|
+
flushTimeouts: 0,
|
|
1793
|
+
networkErrors: 0,
|
|
1794
|
+
rateLimitedResponses: 0,
|
|
1795
|
+
serverErrorResponses: 0,
|
|
1796
|
+
lastFailureKind: null,
|
|
1797
|
+
lastFailureStatusCode: null
|
|
1798
|
+
}
|
|
1799
|
+
})
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
// src/create-client/resolve-endpoint-urls.ts
|
|
1803
|
+
var DEFAULT_API_URL = "https://api.rasputinai.dev";
|
|
1804
|
+
var resolveEndpointUrls = (apiUrl = DEFAULT_API_URL) => {
|
|
1805
|
+
const base = apiUrl.replace(/\/+$/, "");
|
|
1806
|
+
return {
|
|
1807
|
+
ingestUrl: `${base}/ingest`,
|
|
1808
|
+
deployUrl: `${base}/deploy`,
|
|
1809
|
+
instrumentationManifestUrl: `${base}/instrumentationManifest`
|
|
1810
|
+
};
|
|
1811
|
+
};
|
|
1812
|
+
|
|
1813
|
+
// src/create-client/create-client.ts
|
|
1814
|
+
var warnedUnresolvedMaps = false;
|
|
1815
|
+
var warnedPartialResolution = false;
|
|
1816
|
+
var warnUnresolvedMaps = (unresolved) => {
|
|
1380
1817
|
if (!unresolved || warnedUnresolvedMaps) return;
|
|
1381
1818
|
warnedUnresolvedMaps = true;
|
|
1382
1819
|
console.warn(
|
|
@@ -1400,22 +1837,11 @@ var stackOf = (error) => {
|
|
|
1400
1837
|
};
|
|
1401
1838
|
var createClient = (options, hooks = {}) => {
|
|
1402
1839
|
try {
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
const
|
|
1840
|
+
const activation = resolveClientActivation(options);
|
|
1841
|
+
if (!activation.enabled) return noopClient();
|
|
1842
|
+
const { projectApiKey, release } = activation;
|
|
1406
1843
|
const environment = options.environment;
|
|
1407
1844
|
const { ingestUrl, deployUrl } = resolveEndpointUrls(options.apiUrl);
|
|
1408
|
-
if (!release) {
|
|
1409
|
-
if (hooks.announceDeploy ?? true) {
|
|
1410
|
-
void announceDeploy({
|
|
1411
|
-
deployUrl,
|
|
1412
|
-
projectApiKey,
|
|
1413
|
-
environment,
|
|
1414
|
-
fetch: hooks.fetch
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
return noopClient();
|
|
1418
|
-
}
|
|
1419
1845
|
const repoRoot = resolveRepoRoot(options);
|
|
1420
1846
|
if (repoRoot) warnIfSuspiciousRepoRoot(repoRoot);
|
|
1421
1847
|
const MAX_STACK_RESOLVE_CACHE = 32;
|
|
@@ -1441,6 +1867,9 @@ var createClient = (options, hooks = {}) => {
|
|
|
1441
1867
|
}
|
|
1442
1868
|
return pending;
|
|
1443
1869
|
};
|
|
1870
|
+
const suppression = createSuppression();
|
|
1871
|
+
let enqueuePendingSummaries = () => {
|
|
1872
|
+
};
|
|
1444
1873
|
const transport = createTransport({
|
|
1445
1874
|
ingestUrl,
|
|
1446
1875
|
projectApiKey,
|
|
@@ -1449,6 +1878,7 @@ var createClient = (options, hooks = {}) => {
|
|
|
1449
1878
|
installSignalHandlers: hooks.installTransportSignalHandlers,
|
|
1450
1879
|
sdkVersion: hooks.sdkVersion ?? SDK_VERSION,
|
|
1451
1880
|
sdkName: hooks.sdkName ?? SDK_NAME,
|
|
1881
|
+
beforeFlush: () => enqueuePendingSummaries(),
|
|
1452
1882
|
prepareEvent: async ({ event, rawFrames }) => {
|
|
1453
1883
|
const prepared = await resolveStack(rawFrames);
|
|
1454
1884
|
return withResolvedFrames(event, prepared.frames, prepared.resolution);
|
|
@@ -1458,7 +1888,6 @@ var createClient = (options, hooks = {}) => {
|
|
|
1458
1888
|
return { stack_frames: prepared.stack_frames, resolution: prepared.resolution };
|
|
1459
1889
|
}
|
|
1460
1890
|
});
|
|
1461
|
-
const suppression = createSuppression();
|
|
1462
1891
|
if (hooks.announceDeploy ?? true) {
|
|
1463
1892
|
void announceDeploy({
|
|
1464
1893
|
deployUrl,
|
|
@@ -1467,11 +1896,12 @@ var createClient = (options, hooks = {}) => {
|
|
|
1467
1896
|
release,
|
|
1468
1897
|
enabled: true,
|
|
1469
1898
|
fetch: hooks.fetch
|
|
1899
|
+
}).catch(() => {
|
|
1470
1900
|
});
|
|
1471
1901
|
}
|
|
1472
1902
|
const captureException = (error, context) => {
|
|
1473
1903
|
try {
|
|
1474
|
-
const rawFrames = parseStack(stackOf(error));
|
|
1904
|
+
const rawFrames = foldSyntheticFrames(parseStack(stackOf(error)));
|
|
1475
1905
|
const frames = normalizeFrames(toResolvedFrames(rawFrames), { appRoot: repoRoot });
|
|
1476
1906
|
const event = createIngestEvent({
|
|
1477
1907
|
error,
|
|
@@ -1480,8 +1910,7 @@ var createClient = (options, hooks = {}) => {
|
|
|
1480
1910
|
release,
|
|
1481
1911
|
origin: "server",
|
|
1482
1912
|
resolution: "none",
|
|
1483
|
-
request: context?.request
|
|
1484
|
-
runtimeState: context?.runtimeState
|
|
1913
|
+
request: context?.request
|
|
1485
1914
|
});
|
|
1486
1915
|
const decision = suppression.decide({
|
|
1487
1916
|
errorType: event.type,
|
|
@@ -1494,13 +1923,20 @@ var createClient = (options, hooks = {}) => {
|
|
|
1494
1923
|
release,
|
|
1495
1924
|
route: context?.request?.route
|
|
1496
1925
|
});
|
|
1497
|
-
if (decision.action
|
|
1498
|
-
|
|
1926
|
+
if (decision.action !== "send") return;
|
|
1927
|
+
const runtimeState = context?.runtimeState ?? hooks.resolveRuntimeState?.(error, context);
|
|
1928
|
+
if (runtimeState) event.runtime_state = runtimeState;
|
|
1929
|
+
let encodedBytes;
|
|
1930
|
+
try {
|
|
1931
|
+
encodedBytes = Buffer2.byteLength(JSON.stringify(event), "utf8");
|
|
1932
|
+
} catch {
|
|
1933
|
+
encodedBytes = void 0;
|
|
1499
1934
|
}
|
|
1935
|
+
transport.enqueue(event, decision.priority, rawFrames, encodedBytes);
|
|
1500
1936
|
} catch {
|
|
1501
1937
|
}
|
|
1502
1938
|
};
|
|
1503
|
-
|
|
1939
|
+
enqueuePendingSummaries = () => {
|
|
1504
1940
|
for (const { summary, rawFrames } of suppression.drainSummaries()) {
|
|
1505
1941
|
transport.enqueueSummary(summary, rawFrames);
|
|
1506
1942
|
}
|
|
@@ -1530,68 +1966,6 @@ var createClient = (options, hooks = {}) => {
|
|
|
1530
1966
|
}
|
|
1531
1967
|
};
|
|
1532
1968
|
|
|
1533
|
-
// src/derivation/rasputin-wire-tag.ts
|
|
1534
|
-
var RASPUTIN_WIRE_TAG = "\0rasputin";
|
|
1535
|
-
var rasputinUnknown = () => [RASPUTIN_WIRE_TAG, "unknown"];
|
|
1536
|
-
var rasputinUnavailable = (reason) => [
|
|
1537
|
-
RASPUTIN_WIRE_TAG,
|
|
1538
|
-
"unavailable",
|
|
1539
|
-
reason
|
|
1540
|
-
];
|
|
1541
|
-
var rasputinOmitted = () => [RASPUTIN_WIRE_TAG, "omitted"];
|
|
1542
|
-
var rasputinRedacted = () => [RASPUTIN_WIRE_TAG, "redacted"];
|
|
1543
|
-
var rasputinTruncated = (payload) => [
|
|
1544
|
-
RASPUTIN_WIRE_TAG,
|
|
1545
|
-
"truncated",
|
|
1546
|
-
payload
|
|
1547
|
-
];
|
|
1548
|
-
var isRasputinTaggedValue = (value) => {
|
|
1549
|
-
if (!Array.isArray(value) || value.length < 2 || value[0] !== RASPUTIN_WIRE_TAG) return false;
|
|
1550
|
-
const kind = value[1];
|
|
1551
|
-
return kind === "unknown" || kind === "unavailable" || kind === "omitted" || kind === "redacted" || kind === "truncated";
|
|
1552
|
-
};
|
|
1553
|
-
var rasputinTagKind = (value) => isRasputinTaggedValue(value) ? value[1] : void 0;
|
|
1554
|
-
|
|
1555
|
-
// src/derivation/captured-value-markers.ts
|
|
1556
|
-
var REDACTED = "[RASPUTIN_REDACTED]";
|
|
1557
|
-
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1558
|
-
var capturedValueCompleteness = (value) => {
|
|
1559
|
-
if (value === REDACTED) return "partial";
|
|
1560
|
-
const tagged = rasputinTagKind(value);
|
|
1561
|
-
if (tagged === "unknown" || tagged === "truncated" || tagged === "unavailable" || tagged === "omitted") {
|
|
1562
|
-
return "partial";
|
|
1563
|
-
}
|
|
1564
|
-
if (tagged === "redacted") return "partial";
|
|
1565
|
-
if (isRasputinTaggedValue(value)) return "partial";
|
|
1566
|
-
if (Array.isArray(value)) {
|
|
1567
|
-
for (const item of value) {
|
|
1568
|
-
if (capturedValueCompleteness(item) === "partial") return "partial";
|
|
1569
|
-
}
|
|
1570
|
-
return "exact";
|
|
1571
|
-
}
|
|
1572
|
-
if (!isRecord(value)) return "exact";
|
|
1573
|
-
if (value.__rasputin_truncated === true) return "partial";
|
|
1574
|
-
if (value.__rasputin_type === "omitted" || value.__rasputin_type === "accessor") return "partial";
|
|
1575
|
-
if (value.__rasputin_type === "unserializable") return "partial";
|
|
1576
|
-
for (const key of Object.keys(value)) {
|
|
1577
|
-
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
1578
|
-
if (!descriptor || descriptor.get || descriptor.set) return "partial";
|
|
1579
|
-
if (capturedValueCompleteness(descriptor.value) === "partial") return "partial";
|
|
1580
|
-
}
|
|
1581
|
-
return "exact";
|
|
1582
|
-
};
|
|
1583
|
-
var isRedactedCapturedValue = (value) => {
|
|
1584
|
-
if (value === REDACTED) return true;
|
|
1585
|
-
if (rasputinTagKind(value) === "redacted") return true;
|
|
1586
|
-
if (isRecord(value) && value.__rasputin_type === "omitted") return true;
|
|
1587
|
-
return false;
|
|
1588
|
-
};
|
|
1589
|
-
var isSerializerMarker = (value) => {
|
|
1590
|
-
if (isRasputinTaggedValue(value)) return true;
|
|
1591
|
-
if (!isRecord(value)) return false;
|
|
1592
|
-
return value.__rasputin_truncated === true || typeof value.__rasputin_type === "string";
|
|
1593
|
-
};
|
|
1594
|
-
|
|
1595
1969
|
// src/derivation/canonical-json.ts
|
|
1596
1970
|
var sortedKeys = (value) => Object.keys(value).sort();
|
|
1597
1971
|
var canonicalJson = (value) => {
|
|
@@ -1622,967 +1996,214 @@ var canonicalJson = (value) => {
|
|
|
1622
1996
|
};
|
|
1623
1997
|
|
|
1624
1998
|
// src/derivation/sha256.ts
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
1899447441,
|
|
1628
|
-
3049323471,
|
|
1629
|
-
3921009573,
|
|
1630
|
-
961987163,
|
|
1631
|
-
1508970993,
|
|
1632
|
-
2453635748,
|
|
1633
|
-
2870763221,
|
|
1634
|
-
3624381080,
|
|
1635
|
-
310598401,
|
|
1636
|
-
607225278,
|
|
1637
|
-
1426881987,
|
|
1638
|
-
1925078388,
|
|
1639
|
-
2162078206,
|
|
1640
|
-
2614888103,
|
|
1641
|
-
3248222580,
|
|
1642
|
-
3835390401,
|
|
1643
|
-
4022224774,
|
|
1644
|
-
264347078,
|
|
1645
|
-
604807628,
|
|
1646
|
-
770255983,
|
|
1647
|
-
1249150122,
|
|
1648
|
-
1555081692,
|
|
1649
|
-
1996064986,
|
|
1650
|
-
2554220882,
|
|
1651
|
-
2821834349,
|
|
1652
|
-
2952996808,
|
|
1653
|
-
3210313671,
|
|
1654
|
-
3336571891,
|
|
1655
|
-
3584528711,
|
|
1656
|
-
113926993,
|
|
1657
|
-
338241895,
|
|
1658
|
-
666307205,
|
|
1659
|
-
773529912,
|
|
1660
|
-
1294757372,
|
|
1661
|
-
1396182291,
|
|
1662
|
-
1695183700,
|
|
1663
|
-
1986661051,
|
|
1664
|
-
2177026350,
|
|
1665
|
-
2456956037,
|
|
1666
|
-
2730485921,
|
|
1667
|
-
2820302411,
|
|
1668
|
-
3259730800,
|
|
1669
|
-
3345764771,
|
|
1670
|
-
3516065817,
|
|
1671
|
-
3600352804,
|
|
1672
|
-
4094571909,
|
|
1673
|
-
275423344,
|
|
1674
|
-
430227734,
|
|
1675
|
-
506948616,
|
|
1676
|
-
659060556,
|
|
1677
|
-
883997877,
|
|
1678
|
-
958139571,
|
|
1679
|
-
1322822218,
|
|
1680
|
-
1537002063,
|
|
1681
|
-
1747873779,
|
|
1682
|
-
1955562222,
|
|
1683
|
-
2024104815,
|
|
1684
|
-
2227730452,
|
|
1685
|
-
2361852424,
|
|
1686
|
-
2428436474,
|
|
1687
|
-
2756734187,
|
|
1688
|
-
3204031479,
|
|
1689
|
-
3329325298
|
|
1690
|
-
];
|
|
1691
|
-
var rotr = (value, bits) => value >>> bits | value << 32 - bits;
|
|
1692
|
-
var sha256Hex = (input) => {
|
|
1693
|
-
const encoded = new TextEncoder().encode(input);
|
|
1694
|
-
const bitLen = encoded.length * 8;
|
|
1695
|
-
const paddedLen = encoded.length + 9 + 63 >> 6 << 6 >>> 0;
|
|
1696
|
-
const bytes = new Uint8Array(paddedLen);
|
|
1697
|
-
bytes.set(encoded);
|
|
1698
|
-
bytes[encoded.length] = 128;
|
|
1699
|
-
const view = new DataView(bytes.buffer);
|
|
1700
|
-
view.setUint32(paddedLen - 4, bitLen, false);
|
|
1701
|
-
let h0 = 1779033703;
|
|
1702
|
-
let h1 = 3144134277;
|
|
1703
|
-
let h2 = 1013904242;
|
|
1704
|
-
let h3 = 2773480762;
|
|
1705
|
-
let h4 = 1359893119;
|
|
1706
|
-
let h5 = 2600822924;
|
|
1707
|
-
let h6 = 528734635;
|
|
1708
|
-
let h7 = 1541459225;
|
|
1709
|
-
const w = new Uint32Array(64);
|
|
1710
|
-
for (let offset = 0; offset < paddedLen; offset += 64) {
|
|
1711
|
-
for (let i = 0; i < 16; i++) w[i] = view.getUint32(offset + i * 4, false);
|
|
1712
|
-
for (let i = 16; i < 64; i++) {
|
|
1713
|
-
const s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ w[i - 15] >>> 3;
|
|
1714
|
-
const s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ w[i - 2] >>> 10;
|
|
1715
|
-
w[i] = w[i - 16] + s0 + w[i - 7] + s1 >>> 0;
|
|
1716
|
-
}
|
|
1717
|
-
let a = h0;
|
|
1718
|
-
let b = h1;
|
|
1719
|
-
let c = h2;
|
|
1720
|
-
let d = h3;
|
|
1721
|
-
let e = h4;
|
|
1722
|
-
let f = h5;
|
|
1723
|
-
let g = h6;
|
|
1724
|
-
let h = h7;
|
|
1725
|
-
for (let i = 0; i < 64; i++) {
|
|
1726
|
-
const S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
1727
|
-
const ch = e & f ^ ~e & g;
|
|
1728
|
-
const temp1 = h + S1 + ch + K[i] + w[i] >>> 0;
|
|
1729
|
-
const S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
1730
|
-
const maj = a & b ^ a & c ^ b & c;
|
|
1731
|
-
const temp2 = S0 + maj >>> 0;
|
|
1732
|
-
h = g;
|
|
1733
|
-
g = f;
|
|
1734
|
-
f = e;
|
|
1735
|
-
e = d + temp1 >>> 0;
|
|
1736
|
-
d = c;
|
|
1737
|
-
c = b;
|
|
1738
|
-
b = a;
|
|
1739
|
-
a = temp1 + temp2 >>> 0;
|
|
1740
|
-
}
|
|
1741
|
-
h0 = h0 + a >>> 0;
|
|
1742
|
-
h1 = h1 + b >>> 0;
|
|
1743
|
-
h2 = h2 + c >>> 0;
|
|
1744
|
-
h3 = h3 + d >>> 0;
|
|
1745
|
-
h4 = h4 + e >>> 0;
|
|
1746
|
-
h5 = h5 + f >>> 0;
|
|
1747
|
-
h6 = h6 + g >>> 0;
|
|
1748
|
-
h7 = h7 + h >>> 0;
|
|
1749
|
-
}
|
|
1750
|
-
return [h0, h1, h2, h3, h4, h5, h6, h7].map((word) => word.toString(16).padStart(8, "0")).join("");
|
|
1751
|
-
};
|
|
1999
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
2000
|
+
var sha256Hex = (input) => createHash2("sha256").update(input).digest("hex");
|
|
1752
2001
|
|
|
1753
2002
|
// src/derivation/hash-instrumentation-manifest.ts
|
|
2003
|
+
var hashCache = /* @__PURE__ */ new WeakMap();
|
|
1754
2004
|
var hashableSource = (source) => {
|
|
1755
2005
|
const { repositoryPath: _repositoryPath, ...rest } = source;
|
|
1756
2006
|
return rest;
|
|
1757
2007
|
};
|
|
1758
2008
|
var hashableLocated = (items) => items.map((item) => ({ ...item, source: hashableSource(item.source) }));
|
|
1759
2009
|
var hashInstrumentationManifest = (manifest) => {
|
|
1760
|
-
|
|
2010
|
+
const cached = hashCache.get(manifest);
|
|
2011
|
+
if (cached) return cached;
|
|
2012
|
+
const hash = sha256Hex(
|
|
1761
2013
|
canonicalJson({
|
|
1762
2014
|
schema_version: manifest.schema_version,
|
|
1763
2015
|
functions: hashableLocated(manifest.functions),
|
|
1764
2016
|
callSites: hashableLocated(manifest.callSites),
|
|
1765
|
-
destructures: hashableLocated(manifest.destructures)
|
|
1766
|
-
derivationPlans: manifest.derivationPlans ?? []
|
|
2017
|
+
destructures: hashableLocated(manifest.destructures)
|
|
1767
2018
|
})
|
|
1768
2019
|
);
|
|
2020
|
+
hashCache.set(manifest, hash);
|
|
2021
|
+
return hash;
|
|
1769
2022
|
};
|
|
1770
2023
|
|
|
1771
|
-
// src/derivation/wire-
|
|
1772
|
-
var
|
|
1773
|
-
var
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
var
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
const leftKeys = Object.keys(left).sort();
|
|
1791
|
-
const rightKeys = Object.keys(right).sort();
|
|
1792
|
-
if (leftKeys.length !== rightKeys.length) return false;
|
|
1793
|
-
return leftKeys.every((key, index) => {
|
|
1794
|
-
if (key !== rightKeys[index]) return false;
|
|
1795
|
-
const leftDesc = Object.getOwnPropertyDescriptor(left, key);
|
|
1796
|
-
const rightDesc = Object.getOwnPropertyDescriptor(right, key);
|
|
1797
|
-
if (!leftDesc || !rightDesc) return false;
|
|
1798
|
-
if (leftDesc.get || leftDesc.set || rightDesc.get || rightDesc.set) return false;
|
|
1799
|
-
return wireValuesEqual(leftDesc.value, rightDesc.value);
|
|
1800
|
-
});
|
|
2024
|
+
// src/derivation/rasputin-wire-tag.ts
|
|
2025
|
+
var RASPUTIN_WIRE_TAG = "\uE000rasputin";
|
|
2026
|
+
var rasputinUnknown = () => [RASPUTIN_WIRE_TAG, "unknown"];
|
|
2027
|
+
var rasputinUnavailable = (reason) => [
|
|
2028
|
+
RASPUTIN_WIRE_TAG,
|
|
2029
|
+
"unavailable",
|
|
2030
|
+
reason
|
|
2031
|
+
];
|
|
2032
|
+
var rasputinOmitted = () => [RASPUTIN_WIRE_TAG, "omitted"];
|
|
2033
|
+
var rasputinRedacted = () => [RASPUTIN_WIRE_TAG, "redacted"];
|
|
2034
|
+
var rasputinTruncated = (payload) => [
|
|
2035
|
+
RASPUTIN_WIRE_TAG,
|
|
2036
|
+
"truncated",
|
|
2037
|
+
payload
|
|
2038
|
+
];
|
|
2039
|
+
var isRasputinTaggedValue = (value) => {
|
|
2040
|
+
if (!Array.isArray(value) || value.length < 2 || value[0] !== RASPUTIN_WIRE_TAG) return false;
|
|
2041
|
+
const kind = value[1];
|
|
2042
|
+
return kind === "unknown" || kind === "unavailable" || kind === "omitted" || kind === "redacted" || kind === "truncated";
|
|
1801
2043
|
};
|
|
2044
|
+
var rasputinTagKind = (value) => isRasputinTaggedValue(value) ? value[1] : void 0;
|
|
1802
2045
|
|
|
1803
|
-
// src/derivation/
|
|
1804
|
-
var
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
for (const part of parts) {
|
|
1924
|
-
if (part.origin === "unavailable") return "unavailable";
|
|
1925
|
-
if (part.completeness === "partial") partial = true;
|
|
1926
|
-
}
|
|
1927
|
-
return partial ? "partial" : "exact";
|
|
1928
|
-
};
|
|
1929
|
-
var unwrapExactPrimitive = (result) => {
|
|
1930
|
-
if (result.origin === "unavailable") return rasputinUnavailable(result.reason);
|
|
1931
|
-
return result.value;
|
|
1932
|
-
};
|
|
1933
|
-
var isNumericPrimitive = (value) => typeof value === "number" && !isRasputinTaggedValue(value);
|
|
1934
|
-
var isPrimitiveOperand = (value) => {
|
|
1935
|
-
if (isRasputinTaggedValue(value)) return false;
|
|
1936
|
-
return value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string" || typeof value === "bigint" || typeof value === "undefined";
|
|
1937
|
-
};
|
|
1938
|
-
var omittedCallKey = (parentCallId, functionId) => `${parentCallId}\0${functionId}`;
|
|
1939
|
-
var argsIncludeOmitted = (args) => args.some((arg) => rasputinTagKind(arg) === "omitted");
|
|
1940
|
-
var recordReconstructedCallArgs = (queue, parentCallId, functionId, args) => {
|
|
1941
|
-
const key = omittedCallKey(parentCallId, functionId);
|
|
1942
|
-
const pending = queue.get(key);
|
|
1943
|
-
if (pending) pending.push(args);
|
|
1944
|
-
else queue.set(key, [args]);
|
|
1945
|
-
};
|
|
1946
|
-
var takeReconstructedCallArgs = (queue, parentCallId, functionId) => {
|
|
1947
|
-
if (parentCallId == null) return void 0;
|
|
1948
|
-
const pending = queue.get(omittedCallKey(parentCallId, functionId));
|
|
1949
|
-
if (!pending || pending.length === 0) return void 0;
|
|
1950
|
-
return pending.shift();
|
|
1951
|
-
};
|
|
1952
|
-
var resolveEnterArgs = (enter, queue) => {
|
|
1953
|
-
if (!argsIncludeOmitted(enter.args)) return enter.args;
|
|
1954
|
-
return takeReconstructedCallArgs(queue, enter.parentCallId, enter.functionId) ?? enter.args;
|
|
1955
|
-
};
|
|
1956
|
-
var takeChildCapturedReturn = (state, calleeFunctionId) => {
|
|
1957
|
-
if (state.recordingCallId == null) return void 0;
|
|
1958
|
-
const children = (state.childrenByParent.get(state.recordingCallId) ?? []).filter(
|
|
1959
|
-
(child2) => child2.functionId === calleeFunctionId
|
|
1960
|
-
);
|
|
1961
|
-
const key = omittedCallKey(state.recordingCallId, calleeFunctionId);
|
|
1962
|
-
const index = state.childCursor.get(key) ?? 0;
|
|
1963
|
-
state.childCursor.set(key, index + 1);
|
|
1964
|
-
const child = children[index];
|
|
1965
|
-
if (!child) return void 0;
|
|
1966
|
-
if (state.throwCallIds.has(child.callId)) return { threw: true };
|
|
1967
|
-
return state.exitByCallId.get(child.callId);
|
|
1968
|
-
};
|
|
1969
|
-
var readOwnDataProperty = (object, key) => {
|
|
1970
|
-
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
1971
|
-
if (!descriptor) return { ok: false, reason: "missing_property" };
|
|
1972
|
-
if (descriptor.get !== void 0 || descriptor.set !== void 0) {
|
|
1973
|
-
return { ok: false, reason: "accessor_property" };
|
|
1974
|
-
}
|
|
1975
|
-
return { ok: true, value: descriptor.value };
|
|
1976
|
-
};
|
|
1977
|
-
var budgetExceeded = (state) => {
|
|
1978
|
-
if (state.instructions > MAX_INSTRUCTIONS) return "instruction_budget";
|
|
1979
|
-
if (state.depth > MAX_DEPTH) return "depth_budget";
|
|
1980
|
-
if (state.outputBytes > MAX_OUTPUT_BYTES) return "output_size_budget";
|
|
1981
|
-
if (Date.now() - state.startedAt > MAX_WALL_MS) return "wall_time_budget";
|
|
1982
|
-
return void 0;
|
|
1983
|
-
};
|
|
1984
|
-
var evaluateExpression = (expressionId, plan, byId, cells, args, rootsById, factsById, calleeReturns, state, evaluateCallee) => {
|
|
1985
|
-
const over = budgetExceeded(state);
|
|
1986
|
-
if (over) return { origin: "unavailable", reason: over };
|
|
1987
|
-
state.instructions++;
|
|
1988
|
-
state.depth++;
|
|
1989
|
-
try {
|
|
1990
|
-
const existing = cells.get(expressionId);
|
|
1991
|
-
if (existing?.status === "done") return existing.result;
|
|
1992
|
-
if (existing?.status === "pending") {
|
|
1993
|
-
return { origin: "unavailable", reason: "cyclic_expression" };
|
|
1994
|
-
}
|
|
1995
|
-
const expression = byId.get(expressionId);
|
|
1996
|
-
if (!expression) return { origin: "unavailable", reason: "missing_expression" };
|
|
1997
|
-
cells.set(expressionId, { status: "pending" });
|
|
1998
|
-
const evalChild = (id) => evaluateExpression(
|
|
1999
|
-
id,
|
|
2000
|
-
plan,
|
|
2001
|
-
byId,
|
|
2002
|
-
cells,
|
|
2003
|
-
args,
|
|
2004
|
-
rootsById,
|
|
2005
|
-
factsById,
|
|
2006
|
-
calleeReturns,
|
|
2007
|
-
state,
|
|
2008
|
-
evaluateCallee
|
|
2009
|
-
);
|
|
2010
|
-
let result;
|
|
2011
|
-
switch (expression.kind) {
|
|
2012
|
-
case "const": {
|
|
2013
|
-
const value = primitiveFromConst(expression.value);
|
|
2014
|
-
result = { origin: "derived", completeness: "exact", value, dependencies: [] };
|
|
2015
|
-
break;
|
|
2016
|
-
}
|
|
2017
|
-
case "param": {
|
|
2018
|
-
if (expression.index < 0 || expression.index >= args.length) {
|
|
2019
|
-
result = { origin: "unavailable", reason: "missing_argument" };
|
|
2020
|
-
break;
|
|
2021
|
-
}
|
|
2022
|
-
const value = args[expression.index];
|
|
2023
|
-
if (rasputinTagKind(value) === "omitted") {
|
|
2024
|
-
result = { origin: "unavailable", reason: "omitted_argument" };
|
|
2025
|
-
break;
|
|
2026
|
-
}
|
|
2027
|
-
result = capturedFromWire(value);
|
|
2028
|
-
break;
|
|
2029
|
-
}
|
|
2030
|
-
case "root": {
|
|
2031
|
-
const root = rootsById.get(expression.rootId);
|
|
2032
|
-
if (!root) {
|
|
2033
|
-
result = { origin: "unavailable", reason: "missing_root" };
|
|
2034
|
-
break;
|
|
2035
|
-
}
|
|
2036
|
-
result = capturedResult(root);
|
|
2037
|
-
break;
|
|
2038
|
-
}
|
|
2039
|
-
case "alias":
|
|
2040
|
-
result = evalChild(expression.from);
|
|
2041
|
-
break;
|
|
2042
|
-
case "binary": {
|
|
2043
|
-
const left = evalChild(expression.left);
|
|
2044
|
-
const right = evalChild(expression.right);
|
|
2045
|
-
const blocked = exactOperandsOrUnavailable([left, right]);
|
|
2046
|
-
if (blocked) {
|
|
2047
|
-
result = blocked;
|
|
2048
|
-
break;
|
|
2049
|
-
}
|
|
2050
|
-
const leftValue = unwrapExactPrimitive(left);
|
|
2051
|
-
const rightValue = unwrapExactPrimitive(right);
|
|
2052
|
-
if (rasputinTagKind(leftValue) || rasputinTagKind(rightValue)) {
|
|
2053
|
-
result = { origin: "unavailable", reason: "tagged_operand" };
|
|
2054
|
-
break;
|
|
2055
|
-
}
|
|
2056
|
-
if (isRedactedCapturedValue(leftValue) || isRedactedCapturedValue(rightValue)) {
|
|
2057
|
-
result = { origin: "unavailable", reason: "redacted_operand" };
|
|
2058
|
-
break;
|
|
2059
|
-
}
|
|
2060
|
-
if (expression.guard === "numeric") {
|
|
2061
|
-
if (!isNumericPrimitive(leftValue) || !isNumericPrimitive(rightValue)) {
|
|
2062
|
-
result = { origin: "unavailable", reason: "numeric_guard_failed" };
|
|
2063
|
-
break;
|
|
2064
|
-
}
|
|
2065
|
-
} else if (expression.guard === "primitive") {
|
|
2066
|
-
if (!isPrimitiveOperand(leftValue) || !isPrimitiveOperand(rightValue)) {
|
|
2067
|
-
result = { origin: "unavailable", reason: "primitive_guard_failed" };
|
|
2068
|
-
break;
|
|
2069
|
-
}
|
|
2070
|
-
}
|
|
2071
|
-
const value = applyBinary(expression.op, leftValue, rightValue);
|
|
2072
|
-
if (value === void 0) {
|
|
2073
|
-
result = { origin: "unavailable", reason: "unsupported_binary" };
|
|
2074
|
-
break;
|
|
2075
|
-
}
|
|
2076
|
-
result = {
|
|
2077
|
-
origin: "derived",
|
|
2078
|
-
completeness: "exact",
|
|
2079
|
-
value,
|
|
2080
|
-
dependencies: [expression.left, expression.right]
|
|
2081
|
-
};
|
|
2082
|
-
break;
|
|
2083
|
-
}
|
|
2084
|
-
case "unary": {
|
|
2085
|
-
const operand = evalChild(expression.operand);
|
|
2086
|
-
const blocked = exactOperandsOrUnavailable([operand]);
|
|
2087
|
-
if (blocked || operand.origin === "unavailable") {
|
|
2088
|
-
result = blocked ?? operand;
|
|
2089
|
-
break;
|
|
2090
|
-
}
|
|
2091
|
-
const raw = operand.value;
|
|
2092
|
-
if (isRedactedCapturedValue(raw) || rasputinTagKind(raw)) {
|
|
2093
|
-
result = { origin: "unavailable", reason: "tagged_operand" };
|
|
2094
|
-
break;
|
|
2095
|
-
}
|
|
2096
|
-
if (expression.op === "typeof") {
|
|
2097
|
-
result = {
|
|
2098
|
-
origin: "derived",
|
|
2099
|
-
completeness: "exact",
|
|
2100
|
-
value: typeof raw,
|
|
2101
|
-
dependencies: [expression.operand]
|
|
2102
|
-
};
|
|
2103
|
-
break;
|
|
2104
|
-
}
|
|
2105
|
-
if (expression.op === "not") {
|
|
2106
|
-
result = {
|
|
2107
|
-
origin: "derived",
|
|
2108
|
-
completeness: "exact",
|
|
2109
|
-
value: !raw,
|
|
2110
|
-
dependencies: [expression.operand]
|
|
2111
|
-
};
|
|
2112
|
-
break;
|
|
2113
|
-
}
|
|
2114
|
-
if (!isNumericPrimitive(raw)) {
|
|
2115
|
-
result = { origin: "unavailable", reason: "numeric_guard_failed" };
|
|
2116
|
-
break;
|
|
2117
|
-
}
|
|
2118
|
-
result = {
|
|
2119
|
-
origin: "derived",
|
|
2120
|
-
completeness: "exact",
|
|
2121
|
-
value: expression.op === "minus" ? -raw : +raw,
|
|
2122
|
-
dependencies: [expression.operand]
|
|
2123
|
-
};
|
|
2124
|
-
break;
|
|
2125
|
-
}
|
|
2126
|
-
case "logical": {
|
|
2127
|
-
const left = evalChild(expression.left);
|
|
2128
|
-
const leftBlocked = exactOperandsOrUnavailable([left]);
|
|
2129
|
-
if (leftBlocked || left.origin === "unavailable") {
|
|
2130
|
-
result = leftBlocked ?? left;
|
|
2131
|
-
break;
|
|
2132
|
-
}
|
|
2133
|
-
const takeRight = expression.op === "and" ? Boolean(left.value) : expression.op === "or" ? !left.value : left.value == null;
|
|
2134
|
-
if (!takeRight) {
|
|
2135
|
-
result = left.origin === "derived" ? left : {
|
|
2136
|
-
origin: "derived",
|
|
2137
|
-
completeness: "exact",
|
|
2138
|
-
value: left.value,
|
|
2139
|
-
dependencies: [expression.left]
|
|
2140
|
-
};
|
|
2141
|
-
break;
|
|
2142
|
-
}
|
|
2143
|
-
const right = evalChild(expression.right);
|
|
2144
|
-
const blocked = exactOperandsOrUnavailable([left, right]);
|
|
2145
|
-
if (blocked || right.origin === "unavailable") {
|
|
2146
|
-
result = blocked ?? right;
|
|
2147
|
-
break;
|
|
2148
|
-
}
|
|
2149
|
-
result = {
|
|
2150
|
-
origin: "derived",
|
|
2151
|
-
completeness: "exact",
|
|
2152
|
-
value: right.value,
|
|
2153
|
-
dependencies: [expression.left, expression.right]
|
|
2154
|
-
};
|
|
2155
|
-
break;
|
|
2156
|
-
}
|
|
2157
|
-
case "cond": {
|
|
2158
|
-
const test = evalChild(expression.test);
|
|
2159
|
-
const testBlocked = exactOperandsOrUnavailable([test]);
|
|
2160
|
-
if (testBlocked || test.origin === "unavailable") {
|
|
2161
|
-
result = testBlocked ?? test;
|
|
2162
|
-
break;
|
|
2163
|
-
}
|
|
2164
|
-
const fact = [...factsById.values()].find(
|
|
2165
|
-
(entry) => plan.controlFacts.some((definition) => definition.id === entry.factId)
|
|
2166
|
-
);
|
|
2167
|
-
const takeConsequent = fact ? fact.value : Boolean(test.value);
|
|
2168
|
-
const branch = evalChild(takeConsequent ? expression.consequent : expression.alternate);
|
|
2169
|
-
const blocked = exactOperandsOrUnavailable([test, branch]);
|
|
2170
|
-
if (blocked || branch.origin === "unavailable") {
|
|
2171
|
-
result = blocked ?? branch;
|
|
2172
|
-
break;
|
|
2173
|
-
}
|
|
2174
|
-
result = {
|
|
2175
|
-
origin: "derived",
|
|
2176
|
-
completeness: "exact",
|
|
2177
|
-
value: branch.value,
|
|
2178
|
-
dependencies: [
|
|
2179
|
-
expression.test,
|
|
2180
|
-
takeConsequent ? expression.consequent : expression.alternate
|
|
2181
|
-
]
|
|
2182
|
-
};
|
|
2183
|
-
break;
|
|
2184
|
-
}
|
|
2185
|
-
case "template": {
|
|
2186
|
-
const parts = [];
|
|
2187
|
-
let text = "";
|
|
2188
|
-
let failed;
|
|
2189
|
-
for (const part of expression.parts) {
|
|
2190
|
-
if (part.kind === "lit") {
|
|
2191
|
-
text += part.value;
|
|
2192
|
-
continue;
|
|
2193
|
-
}
|
|
2194
|
-
const nested = evalChild(part.expressionId);
|
|
2195
|
-
parts.push(nested);
|
|
2196
|
-
if (nested.origin === "unavailable") {
|
|
2197
|
-
failed = nested;
|
|
2198
|
-
break;
|
|
2199
|
-
}
|
|
2200
|
-
if (!isPrimitiveOperand(nested.value) || isRasputinTaggedValue(nested.value)) {
|
|
2201
|
-
failed = { origin: "unavailable", reason: "template_non_primitive" };
|
|
2202
|
-
break;
|
|
2203
|
-
}
|
|
2204
|
-
text += String(nested.value);
|
|
2205
|
-
}
|
|
2206
|
-
if (failed) {
|
|
2207
|
-
result = failed;
|
|
2208
|
-
break;
|
|
2209
|
-
}
|
|
2210
|
-
const completeness = parts.length === 0 ? "exact" : mergeCompleteness(parts);
|
|
2211
|
-
if (completeness === "unavailable") {
|
|
2212
|
-
result = { origin: "unavailable", reason: "partial_dependency" };
|
|
2213
|
-
break;
|
|
2214
|
-
}
|
|
2215
|
-
result = {
|
|
2216
|
-
origin: "derived",
|
|
2217
|
-
completeness,
|
|
2218
|
-
value: text,
|
|
2219
|
-
dependencies: expression.parts.flatMap(
|
|
2220
|
-
(part) => part.kind === "expr" ? [part.expressionId] : []
|
|
2221
|
-
)
|
|
2222
|
-
};
|
|
2223
|
-
break;
|
|
2224
|
-
}
|
|
2225
|
-
case "object": {
|
|
2226
|
-
const record = {};
|
|
2227
|
-
const parts = [];
|
|
2228
|
-
let failed;
|
|
2229
|
-
for (const property of expression.properties) {
|
|
2230
|
-
const nested = evalChild(property.value);
|
|
2231
|
-
parts.push(nested);
|
|
2232
|
-
if (nested.origin === "unavailable") {
|
|
2233
|
-
failed = nested;
|
|
2234
|
-
break;
|
|
2235
|
-
}
|
|
2236
|
-
record[property.key] = nested.value;
|
|
2237
|
-
}
|
|
2238
|
-
if (failed) {
|
|
2239
|
-
result = failed;
|
|
2240
|
-
break;
|
|
2241
|
-
}
|
|
2242
|
-
const completeness = mergeCompleteness(parts);
|
|
2243
|
-
if (completeness === "unavailable") {
|
|
2244
|
-
result = { origin: "unavailable", reason: "partial_dependency" };
|
|
2245
|
-
break;
|
|
2246
|
-
}
|
|
2247
|
-
result = {
|
|
2248
|
-
origin: "derived",
|
|
2249
|
-
completeness,
|
|
2250
|
-
value: record,
|
|
2251
|
-
dependencies: expression.properties.map((property) => property.value)
|
|
2252
|
-
};
|
|
2253
|
-
break;
|
|
2254
|
-
}
|
|
2255
|
-
case "array": {
|
|
2256
|
-
const items = [];
|
|
2257
|
-
const parts = [];
|
|
2258
|
-
let failed;
|
|
2259
|
-
let unknownCount = 0;
|
|
2260
|
-
for (const element of expression.elements) {
|
|
2261
|
-
if (typeof element !== "number") {
|
|
2262
|
-
items.push(rasputinUnknown());
|
|
2263
|
-
unknownCount++;
|
|
2264
|
-
continue;
|
|
2265
|
-
}
|
|
2266
|
-
const nested = evalChild(element);
|
|
2267
|
-
parts.push(nested);
|
|
2268
|
-
if (nested.origin === "unavailable") {
|
|
2269
|
-
failed = nested;
|
|
2270
|
-
break;
|
|
2271
|
-
}
|
|
2272
|
-
items.push(nested.value);
|
|
2273
|
-
}
|
|
2274
|
-
if (failed) {
|
|
2275
|
-
result = failed;
|
|
2276
|
-
break;
|
|
2277
|
-
}
|
|
2278
|
-
const completeness = unknownCount > 0 ? "partial" : parts.length === 0 ? "exact" : mergeCompleteness(parts);
|
|
2279
|
-
if (completeness === "unavailable") {
|
|
2280
|
-
result = { origin: "unavailable", reason: "partial_dependency" };
|
|
2281
|
-
break;
|
|
2282
|
-
}
|
|
2283
|
-
result = {
|
|
2284
|
-
origin: "derived",
|
|
2285
|
-
completeness,
|
|
2286
|
-
value: items,
|
|
2287
|
-
dependencies: expression.elements.flatMap(
|
|
2288
|
-
(element) => typeof element === "number" ? [element] : []
|
|
2289
|
-
)
|
|
2290
|
-
};
|
|
2291
|
-
break;
|
|
2292
|
-
}
|
|
2293
|
-
case "prop": {
|
|
2294
|
-
const object = evalChild(expression.object);
|
|
2295
|
-
if (object.origin === "unavailable") {
|
|
2296
|
-
result = object;
|
|
2297
|
-
break;
|
|
2298
|
-
}
|
|
2299
|
-
if (isRedactedCapturedValue(object.value)) {
|
|
2300
|
-
result = { origin: "unavailable", reason: "redacted_operand" };
|
|
2301
|
-
break;
|
|
2302
|
-
}
|
|
2303
|
-
if (!isRecord3(object.value) || rasputinTagKind(object.value)) {
|
|
2304
|
-
result = { origin: "unavailable", reason: "prop_on_non_object" };
|
|
2305
|
-
break;
|
|
2306
|
-
}
|
|
2307
|
-
const owned = readOwnDataProperty(object.value, expression.key);
|
|
2308
|
-
if (!owned.ok) {
|
|
2309
|
-
result = { origin: "unavailable", reason: owned.reason };
|
|
2310
|
-
break;
|
|
2311
|
-
}
|
|
2312
|
-
const completeness = object.completeness === "partial" || capturedValueCompleteness(owned.value) === "partial" ? "partial" : "exact";
|
|
2313
|
-
result = {
|
|
2314
|
-
origin: "derived",
|
|
2315
|
-
completeness,
|
|
2316
|
-
value: owned.value,
|
|
2317
|
-
dependencies: [expression.object]
|
|
2318
|
-
};
|
|
2319
|
-
break;
|
|
2320
|
-
}
|
|
2321
|
-
case "index": {
|
|
2322
|
-
const array = evalChild(expression.array);
|
|
2323
|
-
if (array.origin === "unavailable") {
|
|
2324
|
-
result = array;
|
|
2325
|
-
break;
|
|
2326
|
-
}
|
|
2327
|
-
if (!Array.isArray(array.value)) {
|
|
2328
|
-
result = { origin: "unavailable", reason: "index_on_non_array" };
|
|
2329
|
-
break;
|
|
2330
|
-
}
|
|
2331
|
-
if (expression.index < 0 || expression.index >= array.value.length) {
|
|
2332
|
-
result = { origin: "unavailable", reason: "index_out_of_range" };
|
|
2333
|
-
break;
|
|
2334
|
-
}
|
|
2335
|
-
const value = array.value[expression.index];
|
|
2336
|
-
if (rasputinTagKind(value) === "unknown") {
|
|
2337
|
-
result = { origin: "unavailable", reason: "array_hole" };
|
|
2338
|
-
break;
|
|
2339
|
-
}
|
|
2340
|
-
const completeness = array.completeness === "partial" || capturedValueCompleteness(value) === "partial" ? "partial" : "exact";
|
|
2341
|
-
result = {
|
|
2342
|
-
origin: "derived",
|
|
2343
|
-
completeness,
|
|
2344
|
-
value,
|
|
2345
|
-
dependencies: [expression.array]
|
|
2346
|
-
};
|
|
2347
|
-
break;
|
|
2348
|
-
}
|
|
2349
|
-
case "pure_call": {
|
|
2350
|
-
const childReturn = takeChildCapturedReturn(state, expression.calleeFunctionId);
|
|
2351
|
-
if (childReturn && "threw" in childReturn) {
|
|
2352
|
-
result = { origin: "unavailable", reason: "callee_threw" };
|
|
2353
|
-
break;
|
|
2354
|
-
}
|
|
2355
|
-
const capturedReturn = childReturn && "present" in childReturn ? capturedFromWire(childReturn.value) : void 0;
|
|
2356
|
-
const callee = calleeReturns.get(expression.calleeFunctionId);
|
|
2357
|
-
const callArgs = [];
|
|
2358
|
-
let argsExact = true;
|
|
2359
|
-
for (const argId of expression.args) {
|
|
2360
|
-
const nested = evalChild(argId);
|
|
2361
|
-
if (nested.origin === "unavailable" || nested.completeness === "partial") {
|
|
2362
|
-
argsExact = false;
|
|
2363
|
-
continue;
|
|
2364
|
-
}
|
|
2365
|
-
callArgs.push(nested.value);
|
|
2366
|
-
}
|
|
2367
|
-
if (argsExact && state.recordingCallId != null) {
|
|
2368
|
-
recordReconstructedCallArgs(
|
|
2369
|
-
state.omittedCallArgs,
|
|
2370
|
-
state.recordingCallId,
|
|
2371
|
-
expression.calleeFunctionId,
|
|
2372
|
-
callArgs
|
|
2373
|
-
);
|
|
2374
|
-
}
|
|
2375
|
-
const canDeriveCallee = Boolean(
|
|
2376
|
-
argsExact && callee && !callee.fallbackReason && callee.returnExpressionId != null
|
|
2377
|
-
);
|
|
2378
|
-
const derivedReturn = canDeriveCallee && callee ? evaluateCallee(callee, callArgs) : void 0;
|
|
2379
|
-
result = resolveCheckpoint(capturedReturn, derivedReturn, expression.id);
|
|
2380
|
-
break;
|
|
2381
|
-
}
|
|
2382
|
-
}
|
|
2383
|
-
if (result.origin !== "unavailable") {
|
|
2384
|
-
state.outputBytes += estimateBytes(result.value);
|
|
2385
|
-
const sizeOver = budgetExceeded(state);
|
|
2386
|
-
if (sizeOver) result = { origin: "unavailable", reason: sizeOver };
|
|
2387
|
-
}
|
|
2388
|
-
if (result.origin === "derived" && result.completeness === "exact") {
|
|
2389
|
-
for (const dep of result.dependencies) {
|
|
2390
|
-
const child = cells.get(dep);
|
|
2391
|
-
if (child?.status === "done" && child.result.origin !== "unavailable") {
|
|
2392
|
-
if (child.result.completeness === "partial") {
|
|
2393
|
-
result = { ...result, completeness: "partial" };
|
|
2394
|
-
break;
|
|
2395
|
-
}
|
|
2396
|
-
}
|
|
2397
|
-
}
|
|
2398
|
-
}
|
|
2399
|
-
cells.set(expressionId, { status: "done", result });
|
|
2400
|
-
return result;
|
|
2401
|
-
} finally {
|
|
2402
|
-
state.depth--;
|
|
2403
|
-
}
|
|
2404
|
-
};
|
|
2405
|
-
var isJsPrimitive = (value) => {
|
|
2406
|
-
const type = typeof value;
|
|
2407
|
-
return value === null || type !== "object" && type !== "function";
|
|
2408
|
-
};
|
|
2409
|
-
var abstractEquals = (left, right) => {
|
|
2410
|
-
if (!isJsPrimitive(left) || !isJsPrimitive(right)) return void 0;
|
|
2411
|
-
return left == right;
|
|
2412
|
-
};
|
|
2413
|
-
var applyBinary = (op, left, right) => {
|
|
2414
|
-
if (op === "add" && typeof left === "number" && typeof right === "number") return left + right;
|
|
2415
|
-
if (op === "add" && typeof left === "string" && typeof right === "string") return left + right;
|
|
2416
|
-
if (typeof left !== "number" || typeof right !== "number") {
|
|
2417
|
-
if (op === "eq") return abstractEquals(left, right);
|
|
2418
|
-
if (op === "neq") {
|
|
2419
|
-
const equal = abstractEquals(left, right);
|
|
2420
|
-
return equal === void 0 ? void 0 : !equal;
|
|
2046
|
+
// src/derivation/sensitive-property-name.ts
|
|
2047
|
+
var DEFAULT_SENSITIVE_PROPERTY_NAMES = [
|
|
2048
|
+
"password",
|
|
2049
|
+
"passwd",
|
|
2050
|
+
"pwd",
|
|
2051
|
+
"passphrase",
|
|
2052
|
+
"token",
|
|
2053
|
+
"accesstoken",
|
|
2054
|
+
"refreshtoken",
|
|
2055
|
+
"sessiontoken",
|
|
2056
|
+
"authorization",
|
|
2057
|
+
"auth",
|
|
2058
|
+
"bearer",
|
|
2059
|
+
"cookie",
|
|
2060
|
+
"cookies",
|
|
2061
|
+
"signedcookies",
|
|
2062
|
+
"setcookie",
|
|
2063
|
+
"secret",
|
|
2064
|
+
"secrets",
|
|
2065
|
+
"clientsecret",
|
|
2066
|
+
"apikey",
|
|
2067
|
+
"xapikey",
|
|
2068
|
+
"credential",
|
|
2069
|
+
"credentials",
|
|
2070
|
+
"privatekey",
|
|
2071
|
+
"privkey",
|
|
2072
|
+
"pem",
|
|
2073
|
+
"jwt",
|
|
2074
|
+
"otp",
|
|
2075
|
+
"totp",
|
|
2076
|
+
"pin",
|
|
2077
|
+
"mfacode",
|
|
2078
|
+
"sessionid",
|
|
2079
|
+
"sid",
|
|
2080
|
+
"databaseurl",
|
|
2081
|
+
"connectionstring",
|
|
2082
|
+
"dsn",
|
|
2083
|
+
"mongouri",
|
|
2084
|
+
"redisurl",
|
|
2085
|
+
"signingkey",
|
|
2086
|
+
"encryptionkey",
|
|
2087
|
+
"cvv",
|
|
2088
|
+
"cvc",
|
|
2089
|
+
"cardnumber",
|
|
2090
|
+
"ssn",
|
|
2091
|
+
"creditcard",
|
|
2092
|
+
"securitycode",
|
|
2093
|
+
"twofactorcode",
|
|
2094
|
+
"masterkey",
|
|
2095
|
+
"servicerolekey",
|
|
2096
|
+
"stripekey",
|
|
2097
|
+
"rawheaders"
|
|
2098
|
+
];
|
|
2099
|
+
var DEFAULT_SENSITIVE_PROPERTY_NAME_SET = new Set(DEFAULT_SENSITIVE_PROPERTY_NAMES);
|
|
2100
|
+
var SENSITIVE_SEGMENTS = /* @__PURE__ */ new Set([
|
|
2101
|
+
"password",
|
|
2102
|
+
"passwd",
|
|
2103
|
+
"pwd",
|
|
2104
|
+
"passphrase",
|
|
2105
|
+
"token",
|
|
2106
|
+
"secret",
|
|
2107
|
+
"cookie",
|
|
2108
|
+
"cookies",
|
|
2109
|
+
"authorization",
|
|
2110
|
+
"auth",
|
|
2111
|
+
"bearer",
|
|
2112
|
+
"credential",
|
|
2113
|
+
"credentials",
|
|
2114
|
+
"jwt",
|
|
2115
|
+
"otp",
|
|
2116
|
+
"totp",
|
|
2117
|
+
"pin",
|
|
2118
|
+
"sid",
|
|
2119
|
+
"dsn",
|
|
2120
|
+
"pem",
|
|
2121
|
+
"privkey",
|
|
2122
|
+
"cvv",
|
|
2123
|
+
"cvc",
|
|
2124
|
+
"ssn",
|
|
2125
|
+
"secrets"
|
|
2126
|
+
]);
|
|
2127
|
+
var SENSITIVE_SUFFIXES = [
|
|
2128
|
+
"password",
|
|
2129
|
+
"passwd",
|
|
2130
|
+
"token",
|
|
2131
|
+
"secret",
|
|
2132
|
+
"apikey",
|
|
2133
|
+
"privatekey",
|
|
2134
|
+
"credential",
|
|
2135
|
+
"credentials",
|
|
2136
|
+
"cookie"
|
|
2137
|
+
];
|
|
2138
|
+
var compactKey = (key) => {
|
|
2139
|
+
let compacted = "";
|
|
2140
|
+
for (let index = 0; index < key.length; index++) {
|
|
2141
|
+
const code = key.charCodeAt(index);
|
|
2142
|
+
if (code === 45 || code === 46 || code === 95) continue;
|
|
2143
|
+
compacted += code >= 65 && code <= 90 ? String.fromCharCode(code + 32) : key[index];
|
|
2144
|
+
}
|
|
2145
|
+
return compacted;
|
|
2146
|
+
};
|
|
2147
|
+
var stripTrailingDigits = (value) => {
|
|
2148
|
+
let end = value.length;
|
|
2149
|
+
while (end > 0) {
|
|
2150
|
+
const code = value.charCodeAt(end - 1);
|
|
2151
|
+
if (code < 48 || code > 57) break;
|
|
2152
|
+
end--;
|
|
2153
|
+
}
|
|
2154
|
+
return end === 0 ? value : value.slice(0, end);
|
|
2155
|
+
};
|
|
2156
|
+
var segmentsOf = (key) => {
|
|
2157
|
+
const segments = [];
|
|
2158
|
+
let current = "";
|
|
2159
|
+
for (let index = 0; index < key.length; index++) {
|
|
2160
|
+
const char = key[index] ?? "";
|
|
2161
|
+
const code = key.charCodeAt(index);
|
|
2162
|
+
if (code === 45 || code === 46 || code === 95) {
|
|
2163
|
+
if (current) segments.push(current.toLowerCase());
|
|
2164
|
+
current = "";
|
|
2165
|
+
continue;
|
|
2421
2166
|
}
|
|
2422
|
-
if (
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2430
|
-
|
|
2431
|
-
case "mul":
|
|
2432
|
-
return left * right;
|
|
2433
|
-
case "div":
|
|
2434
|
-
return left / right;
|
|
2435
|
-
case "mod":
|
|
2436
|
-
return left % right;
|
|
2437
|
-
case "eq":
|
|
2438
|
-
return left === right;
|
|
2439
|
-
case "neq":
|
|
2440
|
-
return left !== right;
|
|
2441
|
-
case "seq":
|
|
2442
|
-
return left === right;
|
|
2443
|
-
case "sneq":
|
|
2444
|
-
return left !== right;
|
|
2445
|
-
case "lt":
|
|
2446
|
-
return left < right;
|
|
2447
|
-
case "lte":
|
|
2448
|
-
return left <= right;
|
|
2449
|
-
case "gt":
|
|
2450
|
-
return left > right;
|
|
2451
|
-
case "gte":
|
|
2452
|
-
return left >= right;
|
|
2453
|
-
}
|
|
2454
|
-
};
|
|
2455
|
-
var evaluatePlan = (plan, args, roots, facts, plansByFunctionId, state, recordingCallId, capturedExit, threw = false) => {
|
|
2456
|
-
const previousRecordingCallId = state.recordingCallId;
|
|
2457
|
-
state.recordingCallId = recordingCallId;
|
|
2458
|
-
try {
|
|
2459
|
-
const byId = new Map(plan.expressions.map((expression) => [expression.id, expression]));
|
|
2460
|
-
const cells = /* @__PURE__ */ new Map();
|
|
2461
|
-
const rootsById = new Map(roots.map((root) => [root.rootId, root]));
|
|
2462
|
-
const factsById = new Map(facts.map((fact) => [fact.factId, fact]));
|
|
2463
|
-
const evaluateCallee = (callee, callArgs) => {
|
|
2464
|
-
if (callee.returnExpressionId == null) {
|
|
2465
|
-
return { origin: "unavailable", reason: "callee_without_return" };
|
|
2167
|
+
if (current && code >= 65 && code <= 90) {
|
|
2168
|
+
const prev = current.charCodeAt(current.length - 1);
|
|
2169
|
+
const prevIsLower = prev >= 97 && prev <= 122;
|
|
2170
|
+
const next = key.charCodeAt(index + 1);
|
|
2171
|
+
const nextIsLower = next >= 97 && next <= 122;
|
|
2172
|
+
if (prevIsLower || nextIsLower) {
|
|
2173
|
+
segments.push(current.toLowerCase());
|
|
2174
|
+
current = char;
|
|
2175
|
+
continue;
|
|
2466
2176
|
}
|
|
2467
|
-
const nested = evaluatePlan(callee, callArgs, [], [], plansByFunctionId, state, null);
|
|
2468
|
-
return nested.returnValue ?? { origin: "unavailable", reason: "callee_without_return" };
|
|
2469
|
-
};
|
|
2470
|
-
const values = {};
|
|
2471
|
-
for (const expression of plan.expressions) {
|
|
2472
|
-
values[expression.id] = evaluateExpression(
|
|
2473
|
-
expression.id,
|
|
2474
|
-
plan,
|
|
2475
|
-
byId,
|
|
2476
|
-
cells,
|
|
2477
|
-
args,
|
|
2478
|
-
rootsById,
|
|
2479
|
-
factsById,
|
|
2480
|
-
plansByFunctionId,
|
|
2481
|
-
state,
|
|
2482
|
-
evaluateCallee
|
|
2483
|
-
);
|
|
2484
2177
|
}
|
|
2485
|
-
|
|
2486
|
-
variableId: variable.id,
|
|
2487
|
-
name: variable.name,
|
|
2488
|
-
availableAtLine: variable.availableAtLine,
|
|
2489
|
-
availableAtColumn: variable.availableAtColumn,
|
|
2490
|
-
result: values[variable.expressionId] ?? {
|
|
2491
|
-
origin: "unavailable",
|
|
2492
|
-
reason: "missing_expression"
|
|
2493
|
-
}
|
|
2494
|
-
}));
|
|
2495
|
-
const derivedReturn = plan.returnExpressionId == null ? void 0 : values[plan.returnExpressionId] ?? {
|
|
2496
|
-
origin: "unavailable",
|
|
2497
|
-
reason: "missing_return"
|
|
2498
|
-
};
|
|
2499
|
-
return {
|
|
2500
|
-
functionId: plan.functionId,
|
|
2501
|
-
callId: roots[0]?.callId ?? facts[0]?.callId ?? 0,
|
|
2502
|
-
values,
|
|
2503
|
-
variables,
|
|
2504
|
-
returnValue: threw ? void 0 : resolveCheckpoint(
|
|
2505
|
-
capturedExit ? capturedFromWire(capturedExit.value) : void 0,
|
|
2506
|
-
derivedReturn,
|
|
2507
|
-
plan.returnExpressionId
|
|
2508
|
-
)
|
|
2509
|
-
};
|
|
2510
|
-
} finally {
|
|
2511
|
-
state.recordingCallId = previousRecordingCallId;
|
|
2178
|
+
current += char;
|
|
2512
2179
|
}
|
|
2180
|
+
if (current) segments.push(current.toLowerCase());
|
|
2181
|
+
return segments;
|
|
2513
2182
|
};
|
|
2514
|
-
var
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
}
|
|
2521
|
-
const expectedHash = input.state.derivation?.manifestHash;
|
|
2522
|
-
if (!expectedHash) {
|
|
2523
|
-
return { unavailableReason: "missing_manifest_hash", functions: [] };
|
|
2524
|
-
}
|
|
2525
|
-
if (hashInstrumentationManifest(input.manifest) !== expectedHash) {
|
|
2526
|
-
return { unavailableReason: "manifest_hash_mismatch", functions: [] };
|
|
2527
|
-
}
|
|
2528
|
-
const plansByFunctionId = new Map(
|
|
2529
|
-
(input.manifest.derivationPlans ?? []).map((plan) => [plan.functionId, plan])
|
|
2183
|
+
var adjacentPairsSensitive = (left, right) => left === "api" && right === "key" || left === "private" && right === "key" || left === "client" && right === "secret" || left === "set" && right === "cookie" || left === "database" && right === "url" || left === "connection" && right === "string" || left === "mongo" && (right === "uri" || right === "url") || left === "mongodb" && (right === "uri" || right === "url") || left === "redis" && (right === "uri" || right === "url") || left === "postgres" && (right === "uri" || right === "url") || left === "database" && right === "uri" || left === "signing" && right === "key" || left === "master" && right === "key" || left === "stripe" && right === "key" || left === "service" && right === "role" || left === "security" && right === "code" || left === "two" && right === "factor" || left === "encryption" && right === "key" || left === "session" && (right === "id" || right === "key" || right === "token") || left === "card" && right === "number" || left === "mfa" && right === "code";
|
|
2184
|
+
var defaultSensitivePropertyNames = () => DEFAULT_SENSITIVE_PROPERTY_NAME_SET;
|
|
2185
|
+
var propertyNameIsSensitive = (key) => {
|
|
2186
|
+
const compacted = compactKey(key);
|
|
2187
|
+
const compactForms = [compacted, stripTrailingDigits(compacted)].filter(
|
|
2188
|
+
(value, index, values) => value.length > 0 && values.indexOf(value) === index
|
|
2530
2189
|
);
|
|
2531
|
-
const
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
const childrenByParent = /* @__PURE__ */ new Map();
|
|
2536
|
-
for (const event of input.state.events) {
|
|
2537
|
-
if (event.type === "function_enter" && event.parentCallId != null) {
|
|
2538
|
-
const child = { callId: event.callId, functionId: event.functionId };
|
|
2539
|
-
const siblings = childrenByParent.get(event.parentCallId);
|
|
2540
|
-
if (siblings) siblings.push(child);
|
|
2541
|
-
else childrenByParent.set(event.parentCallId, [child]);
|
|
2542
|
-
}
|
|
2543
|
-
if (event.type === "function_exit") {
|
|
2544
|
-
exitByCallId.set(event.callId, { present: true, value: event.returnValue });
|
|
2190
|
+
for (const form of compactForms) {
|
|
2191
|
+
if (DEFAULT_SENSITIVE_PROPERTY_NAME_SET.has(form)) return true;
|
|
2192
|
+
for (const suffix of SENSITIVE_SUFFIXES) {
|
|
2193
|
+
if (form.endsWith(suffix)) return true;
|
|
2545
2194
|
}
|
|
2546
|
-
if (
|
|
2195
|
+
if (form.includes("apikey") || form.includes("xapikey")) return true;
|
|
2547
2196
|
}
|
|
2548
|
-
const
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
outputBytes: 0,
|
|
2552
|
-
startedAt: Date.now(),
|
|
2553
|
-
recordingCallId: null,
|
|
2554
|
-
omittedCallArgs: /* @__PURE__ */ new Map(),
|
|
2555
|
-
exitByCallId,
|
|
2556
|
-
throwCallIds,
|
|
2557
|
-
childrenByParent,
|
|
2558
|
-
childCursor: /* @__PURE__ */ new Map()
|
|
2559
|
-
};
|
|
2560
|
-
const enterEvents = input.state.events.filter((event) => event.type === "function_enter");
|
|
2561
|
-
const functions = [];
|
|
2562
|
-
for (const enter of enterEvents) {
|
|
2563
|
-
const plan = plansByFunctionId.get(enter.functionId);
|
|
2564
|
-
if (!plan) continue;
|
|
2565
|
-
const callRoots = roots.filter((root) => root.callId === enter.callId);
|
|
2566
|
-
const callFacts = facts.filter((fact) => fact.callId === enter.callId);
|
|
2567
|
-
const evaluated = evaluatePlan(
|
|
2568
|
-
plan,
|
|
2569
|
-
resolveEnterArgs(enter, state.omittedCallArgs),
|
|
2570
|
-
callRoots,
|
|
2571
|
-
callFacts,
|
|
2572
|
-
plansByFunctionId,
|
|
2573
|
-
state,
|
|
2574
|
-
enter.callId,
|
|
2575
|
-
exitByCallId.get(enter.callId),
|
|
2576
|
-
throwCallIds.has(enter.callId)
|
|
2577
|
-
);
|
|
2578
|
-
evaluated.callId = enter.callId;
|
|
2579
|
-
functions.push(evaluated);
|
|
2197
|
+
const segments = segmentsOf(key).map((segment) => stripTrailingDigits(segment) || segment);
|
|
2198
|
+
for (const segment of segments) {
|
|
2199
|
+
if (SENSITIVE_SEGMENTS.has(segment)) return true;
|
|
2580
2200
|
}
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2201
|
+
for (let index = 0; index < segments.length - 1; index++) {
|
|
2202
|
+
const left = segments[index];
|
|
2203
|
+
const right = segments[index + 1];
|
|
2204
|
+
if (left && right && adjacentPairsSensitive(left, right)) return true;
|
|
2205
|
+
}
|
|
2206
|
+
return false;
|
|
2586
2207
|
};
|
|
2587
2208
|
|
|
2588
2209
|
// src/instrumentation-manifest/instrumentation-manifest-types.ts
|
|
@@ -2592,7 +2213,7 @@ var INSTRUMENTATION_MANIFEST_SCHEMA_VERSION = 3;
|
|
|
2592
2213
|
var uploadInstrumentationManifest = async (options) => {
|
|
2593
2214
|
const release = options.release.trim();
|
|
2594
2215
|
if (!release) return { ok: false };
|
|
2595
|
-
const fetchFn = options.fetch ??
|
|
2216
|
+
const fetchFn = options.fetch ?? defaultIngestFetch();
|
|
2596
2217
|
try {
|
|
2597
2218
|
const response = await fetchFn(options.url, {
|
|
2598
2219
|
method: "POST",
|
|
@@ -2601,7 +2222,8 @@ var uploadInstrumentationManifest = async (options) => {
|
|
|
2601
2222
|
"Content-Type": "application/json",
|
|
2602
2223
|
Accept: "application/json"
|
|
2603
2224
|
},
|
|
2604
|
-
body: JSON.stringify({ release, manifest: options.manifest })
|
|
2225
|
+
body: JSON.stringify({ release, manifest: options.manifest }),
|
|
2226
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2605
2227
|
});
|
|
2606
2228
|
if (!response.ok) return { ok: false };
|
|
2607
2229
|
const body = await response.json();
|
|
@@ -2615,21 +2237,21 @@ export {
|
|
|
2615
2237
|
INSTRUMENTATION_MANIFEST_SCHEMA_VERSION,
|
|
2616
2238
|
RASPUTIN_WIRE_TAG,
|
|
2617
2239
|
announceDeploy,
|
|
2618
|
-
capturedValueCompleteness,
|
|
2619
2240
|
createClient,
|
|
2620
2241
|
createIngestEvent,
|
|
2621
2242
|
createSuppression,
|
|
2622
2243
|
createTransport,
|
|
2244
|
+
defaultSensitivePropertyNames,
|
|
2623
2245
|
detectRelease,
|
|
2624
|
-
|
|
2625
|
-
evaluatedValueAtLine,
|
|
2246
|
+
foldSyntheticFrames,
|
|
2626
2247
|
hashInstrumentationManifest,
|
|
2627
2248
|
isClientEnabled,
|
|
2249
|
+
isRasputinHandleRunFrame,
|
|
2250
|
+
isRasputinShellFrame,
|
|
2628
2251
|
isRasputinTaggedValue,
|
|
2629
|
-
isRedactedCapturedValue,
|
|
2630
|
-
isSerializerMarker,
|
|
2631
2252
|
normalizeFrames,
|
|
2632
2253
|
parseStack,
|
|
2254
|
+
propertyNameIsSensitive,
|
|
2633
2255
|
rasputinOmitted,
|
|
2634
2256
|
rasputinRedacted,
|
|
2635
2257
|
rasputinTagKind,
|