@saptools/cf-inspector 0.4.11 → 0.5.0

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/dist/index.js CHANGED
@@ -474,42 +474,93 @@ async function removeBreakpoint(session, breakpointId) {
474
474
  // src/inspector/discovery.ts
475
475
  init_types();
476
476
  import { request } from "http";
477
+ import { performance } from "perf_hooks";
478
+ var InvalidDiscoveryPayloadError = class extends CfInspectorError {
479
+ };
477
480
  async function fetchJson(url, timeoutMs) {
478
- return await new Promise((resolve, reject) => {
479
- const req = request(url, { method: "GET" }, (res) => {
480
- const chunks = [];
481
- res.on("data", (chunk) => {
482
- chunks.push(chunk);
483
- });
484
- res.on("end", () => {
485
- try {
486
- resolve(parseJsonResponse(chunks));
487
- } catch (err) {
488
- reject(parseDiscoveryError(url, err));
489
- }
490
- });
491
- res.on("error", (err) => {
492
- reject(newDiscoveryError(`Inspector discovery response error: ${err.message}`));
481
+ const deadline = performance.now() + timeoutMs;
482
+ let lastError;
483
+ while (performance.now() < deadline) {
484
+ try {
485
+ const remainingMs = deadline - performance.now();
486
+ if (remainingMs <= 0) {
487
+ break;
488
+ }
489
+ return await new Promise((resolve, reject) => {
490
+ const req = request(url, { method: "GET" }, (res) => {
491
+ const chunks = [];
492
+ res.on("data", (chunk) => {
493
+ chunks.push(chunk);
494
+ });
495
+ res.on("end", () => {
496
+ try {
497
+ resolve(parseJsonResponse(chunks));
498
+ } catch (err) {
499
+ reject(parseDiscoveryError(url, err));
500
+ }
501
+ });
502
+ res.on("error", (err) => {
503
+ reject(newDiscoveryError(`Inspector discovery response error: ${err.message}`));
504
+ });
505
+ });
506
+ const attemptTimeoutMs = Math.min(2e3, remainingMs);
507
+ req.setTimeout(attemptTimeoutMs, () => {
508
+ req.destroy(
509
+ new CfInspectorError(
510
+ "INSPECTOR_DISCOVERY_FAILED",
511
+ `Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`
512
+ )
513
+ );
514
+ });
515
+ req.on("error", (err) => {
516
+ reject(err instanceof CfInspectorError ? err : formatDiscoveryRequestError(url, err));
517
+ });
518
+ req.end();
493
519
  });
494
- });
495
- req.setTimeout(timeoutMs, () => {
496
- req.destroy(
497
- new CfInspectorError(
498
- "INSPECTOR_DISCOVERY_FAILED",
499
- `Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`
500
- )
501
- );
502
- });
503
- req.on("error", (err) => {
504
- reject(
505
- err instanceof CfInspectorError ? err : new CfInspectorError(
506
- "INSPECTOR_DISCOVERY_FAILED",
507
- `Inspector discovery at ${url} failed: ${err.message}`
508
- )
509
- );
510
- });
511
- req.end();
512
- });
520
+ } catch (err) {
521
+ if (err instanceof InvalidDiscoveryPayloadError) {
522
+ throw err;
523
+ }
524
+ lastError = err;
525
+ const now = performance.now();
526
+ if (now < deadline) {
527
+ const sleepMs = Math.min(1e3, deadline - now);
528
+ await new Promise((r) => setTimeout(r, sleepMs));
529
+ }
530
+ }
531
+ }
532
+ if (lastError instanceof Error) {
533
+ throw lastError;
534
+ }
535
+ throw new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", `Inspector discovery at ${url} timed out after ${timeoutMs.toString()}ms`);
536
+ }
537
+ function isNodeSystemError(err) {
538
+ return err instanceof Error;
539
+ }
540
+ function isConnectionRefusedOrUnreachable(code) {
541
+ return code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "EHOSTUNREACH" || code === "ENETUNREACH";
542
+ }
543
+ function formatEndpoint(url, err) {
544
+ if (typeof err.address === "string" && typeof err.port === "number") {
545
+ return `${err.address}:${err.port.toString()}`;
546
+ }
547
+ const parsed = new URL(url);
548
+ return parsed.host;
549
+ }
550
+ function formatDiscoveryRequestError(url, err) {
551
+ const detail = err instanceof Error ? err.message : String(err);
552
+ if (!isNodeSystemError(err) || !isConnectionRefusedOrUnreachable(err.code)) {
553
+ return new CfInspectorError(
554
+ "INSPECTOR_DISCOVERY_FAILED",
555
+ `Inspector discovery at ${url} failed: ${detail}`
556
+ );
557
+ }
558
+ const endpoint = formatEndpoint(url, err);
559
+ return new CfInspectorError(
560
+ "INSPECTOR_DISCOVERY_FAILED",
561
+ `Cannot reach Node inspector discovery at ${url}. Nothing is listening on ${endpoint}, or the inspector tunnel is stale/closed. Restart the local inspector or tunnel and retry. If this port came from cf-debugger, stop the stale session and start a fresh tunnel, or run cf-inspector with --app/--region/--org/--space so it can open a tunnel.`,
562
+ detail
563
+ );
513
564
  }
514
565
  function parseJsonResponse(chunks) {
515
566
  const text = Buffer.concat(chunks).toString("utf8");
@@ -517,7 +568,10 @@ function parseJsonResponse(chunks) {
517
568
  }
518
569
  function parseDiscoveryError(url, err) {
519
570
  const message = err instanceof Error ? err.message : String(err);
520
- return newDiscoveryError(`Failed to parse inspector discovery response from ${url}: ${message}`);
571
+ return new InvalidDiscoveryPayloadError(
572
+ "INSPECTOR_DISCOVERY_FAILED",
573
+ `Failed to parse inspector discovery response from ${url}: ${message}`
574
+ );
521
575
  }
522
576
  function newDiscoveryError(message) {
523
577
  return new CfInspectorError("INSPECTOR_DISCOVERY_FAILED", message);
@@ -591,7 +645,7 @@ async function fetchInspectorVersion(host, port, timeoutMs) {
591
645
 
592
646
  // src/inspector/pause.ts
593
647
  init_types();
594
- import { performance } from "perf_hooks";
648
+ import { performance as performance2 } from "perf_hooks";
595
649
  function pauseMatches(pause, breakpointIds, pauseReasons) {
596
650
  if (pauseReasons !== void 0 && pauseReasons.length > 0) {
597
651
  return pauseReasons.includes(pause.reason);
@@ -602,7 +656,7 @@ function pauseMatches(pause, breakpointIds, pauseReasons) {
602
656
  return pause.hitBreakpoints.some((id) => breakpointIds.includes(id));
603
657
  }
604
658
  function remainingUntil(deadlineMs) {
605
- return Math.max(0, deadlineMs - performance.now());
659
+ return Math.max(0, deadlineMs - performance2.now());
606
660
  }
607
661
  function hasResumedSincePause(session, pause) {
608
662
  const pauseAt = pause.receivedAtMs;
@@ -632,7 +686,7 @@ async function waitForUnmatchedPauseToResume(session, pause, deadlineMs, timeout
632
686
  }
633
687
  try {
634
688
  await session.client.waitFor("Debugger.resumed", { timeoutMs: remainingMs });
635
- session.debuggerState.lastResumedAtMs = performance.now();
689
+ session.debuggerState.lastResumedAtMs = performance2.now();
636
690
  } catch (err) {
637
691
  if (err instanceof CfInspectorError && err.code === "BREAKPOINT_NOT_HIT") {
638
692
  throwUnrelatedPauseTimeout(pause, timeoutMs);
@@ -655,7 +709,7 @@ async function handleUnmatchedPause(session, pause, options, deadlineMs) {
655
709
  await waitForUnmatchedPauseToResume(session, pause, deadlineMs, options.timeoutMs);
656
710
  }
657
711
  async function waitForPause(session, options) {
658
- const deadlineMs = performance.now() + options.timeoutMs;
712
+ const deadlineMs = performance2.now() + options.timeoutMs;
659
713
  const buffer = session.pauseBuffer;
660
714
  while (buffer.length > 0 || remainingUntil(deadlineMs) > 0) {
661
715
  while (buffer.length > 0) {
@@ -688,14 +742,14 @@ async function waitForLivePause(session, options, deadlineMs) {
688
742
  params = await session.client.waitFor("Debugger.paused", {
689
743
  timeoutMs: remainingMs,
690
744
  predicate: () => {
691
- receivedAtMs = performance.now();
745
+ receivedAtMs = performance2.now();
692
746
  return true;
693
747
  }
694
748
  });
695
749
  } finally {
696
750
  session.pauseWaitGate.active = false;
697
751
  }
698
- return toPauseEvent(params, receivedAtMs ?? performance.now(), session.scripts);
752
+ return toPauseEvent(params, receivedAtMs ?? performance2.now(), session.scripts);
699
753
  }
700
754
 
701
755
  // src/inspector/runtime.ts
@@ -706,15 +760,30 @@ async function resume(session) {
706
760
  async function setPauseOnExceptions(session, state) {
707
761
  await session.client.send("Debugger.setPauseOnExceptions", { state });
708
762
  }
709
- async function evaluateOnFrame(session, callFrameId, expression) {
763
+ async function evaluateOnFrame(session, callFrameId, expression, options = {}) {
710
764
  return await session.client.send("Debugger.evaluateOnCallFrame", {
711
765
  callFrameId,
712
766
  expression,
713
767
  returnByValue: false,
714
768
  generatePreview: true,
715
- silent: true
769
+ silent: true,
770
+ ...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
716
771
  });
717
772
  }
773
+ function isSideEffectRefusal(result) {
774
+ const classNames = [
775
+ result.result?.className,
776
+ result.exceptionDetails?.exception?.className
777
+ ];
778
+ const descriptions = [
779
+ result.result?.description,
780
+ result.exceptionDetails?.exception?.description
781
+ ];
782
+ const isEvalError = classNames.includes("EvalError");
783
+ return isEvalError && descriptions.some(
784
+ (description) => typeof description === "string" && description.toLowerCase().includes("possible side-effect in debug-evaluate")
785
+ );
786
+ }
718
787
  async function evaluateGlobal(session, expression) {
719
788
  return await session.client.send("Runtime.evaluate", {
720
789
  expression,
@@ -766,7 +835,7 @@ async function getProperties(session, objectId) {
766
835
  }
767
836
 
768
837
  // src/inspector/session.ts
769
- import { performance as performance2 } from "perf_hooks";
838
+ import { performance as performance3 } from "perf_hooks";
770
839
 
771
840
  // src/cdp/client.ts
772
841
  init_types();
@@ -1008,12 +1077,203 @@ var CdpClient = class _CdpClient {
1008
1077
  this.emitter.removeAllListeners();
1009
1078
  }
1010
1079
  };
1080
+ var NodeWorkerTransport = class {
1081
+ constructor(parent, sessionId) {
1082
+ this.parent = parent;
1083
+ this.sessionId = sessionId;
1084
+ this.detachParentListeners = [
1085
+ parent.on("NodeWorker.receivedMessageFromWorker", (raw) => {
1086
+ this.forwardWorkerMessage(raw);
1087
+ }),
1088
+ parent.on("NodeWorker.detachedFromWorker", (raw) => {
1089
+ this.handleWorkerDetach(raw);
1090
+ }),
1091
+ parent.onClose((error) => {
1092
+ this.closeWithError(error);
1093
+ })
1094
+ ];
1095
+ }
1096
+ parent;
1097
+ sessionId;
1098
+ emitter = new EventEmitter();
1099
+ detachParentListeners;
1100
+ readyState = 1;
1101
+ send(payload) {
1102
+ if (this.readyState !== 1) {
1103
+ throw new CfInspectorError("INSPECTOR_CONNECTION_FAILED", "Worker inspector session is closed");
1104
+ }
1105
+ void this.parent.send("NodeWorker.sendMessageToWorker", {
1106
+ sessionId: this.sessionId,
1107
+ message: payload
1108
+ }).catch((error) => {
1109
+ const normalized = error instanceof Error ? error : new Error(String(error));
1110
+ this.closeWithError(normalized);
1111
+ });
1112
+ }
1113
+ close() {
1114
+ this.finishClose();
1115
+ }
1116
+ on(event, listener) {
1117
+ this.emitter.on(event, listener);
1118
+ }
1119
+ off(event, listener) {
1120
+ this.emitter.off(event, listener);
1121
+ }
1122
+ forwardWorkerMessage(raw) {
1123
+ const params = asNodeWorkerEventParams(raw);
1124
+ if (params.sessionId !== this.sessionId || typeof params.message !== "string") {
1125
+ return;
1126
+ }
1127
+ this.emitter.emit("message", params.message);
1128
+ }
1129
+ handleWorkerDetach(raw) {
1130
+ const params = asNodeWorkerEventParams(raw);
1131
+ if (params.sessionId === this.sessionId) {
1132
+ this.finishClose();
1133
+ }
1134
+ }
1135
+ closeWithError(error) {
1136
+ if (this.readyState !== 1) {
1137
+ return;
1138
+ }
1139
+ this.emitter.emit("error", error);
1140
+ this.finishClose();
1141
+ }
1142
+ finishClose() {
1143
+ if (this.readyState !== 1) {
1144
+ return;
1145
+ }
1146
+ this.readyState = 3;
1147
+ for (const detach of this.detachParentListeners) {
1148
+ detach();
1149
+ }
1150
+ this.emitter.emit("close");
1151
+ this.emitter.removeAllListeners();
1152
+ }
1153
+ };
1154
+ function asNodeWorkerEventParams(raw) {
1155
+ if (!isUnknownRecord(raw)) {
1156
+ return {};
1157
+ }
1158
+ const sessionId = raw["sessionId"];
1159
+ const message = raw["message"];
1160
+ return {
1161
+ ...typeof sessionId === "string" ? { sessionId } : {},
1162
+ ...typeof message === "string" ? { message } : {}
1163
+ };
1164
+ }
1165
+ function isUnknownRecord(value) {
1166
+ return typeof value === "object" && value !== null;
1167
+ }
1168
+ async function createNodeWorkerClient(parent, sessionId, requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS) {
1169
+ const transport = new NodeWorkerTransport(parent, sessionId);
1170
+ return await CdpClient.connect({
1171
+ url: `node-worker://${sessionId}`,
1172
+ transportFactory: () => Promise.resolve(transport),
1173
+ requestTimeoutMs
1174
+ });
1175
+ }
1011
1176
 
1012
1177
  // src/inspector/session.ts
1013
1178
  init_types();
1014
1179
  var DEFAULT_CONNECT_TIMEOUT_MS = 5e3;
1015
1180
  var DEFAULT_HOST = "127.0.0.1";
1016
1181
  var PAUSE_BUFFER_LIMIT = 32;
1182
+ var NodeWorkerDiscovery = class {
1183
+ constructor(client) {
1184
+ this.client = client;
1185
+ this.detachListeners = [
1186
+ client.on("NodeWorker.attachedToWorker", (raw) => {
1187
+ const worker = toInspectorWorkerTarget(raw);
1188
+ if (worker !== void 0) {
1189
+ this.workers.set(worker.sessionId, worker);
1190
+ }
1191
+ }),
1192
+ client.on("NodeWorker.detachedFromWorker", (raw) => {
1193
+ const sessionId = readField(raw, "sessionId");
1194
+ if (typeof sessionId === "string") {
1195
+ this.workers.delete(sessionId);
1196
+ }
1197
+ })
1198
+ ];
1199
+ }
1200
+ client;
1201
+ workers = /* @__PURE__ */ new Map();
1202
+ detachListeners;
1203
+ supported = false;
1204
+ disposed = false;
1205
+ async enable() {
1206
+ try {
1207
+ await this.client.send("NodeWorker.enable", { waitForDebuggerOnStart: false });
1208
+ this.supported = true;
1209
+ } catch (error) {
1210
+ if (!isUnsupportedNodeWorkerDomain(error)) {
1211
+ throw error;
1212
+ }
1213
+ }
1214
+ }
1215
+ list() {
1216
+ return [...this.workers.values()].sort(compareWorkers);
1217
+ }
1218
+ async dispose() {
1219
+ if (this.disposed) {
1220
+ return;
1221
+ }
1222
+ this.disposed = true;
1223
+ if (this.supported && !this.client.isClosed) {
1224
+ try {
1225
+ await this.client.send("NodeWorker.disable");
1226
+ } catch {
1227
+ }
1228
+ }
1229
+ for (const detach of this.detachListeners) {
1230
+ detach();
1231
+ }
1232
+ }
1233
+ };
1234
+ function isUnsupportedNodeWorkerDomain(error) {
1235
+ if (!(error instanceof CfInspectorError) || error.code !== "CDP_REQUEST_FAILED") {
1236
+ return false;
1237
+ }
1238
+ return error.detail?.includes('"code":-32601') === true;
1239
+ }
1240
+ function compareWorkers(left, right) {
1241
+ const leftId = Number.parseInt(left.workerId, 10);
1242
+ const rightId = Number.parseInt(right.workerId, 10);
1243
+ if (!Number.isNaN(leftId) && !Number.isNaN(rightId) && leftId !== rightId) {
1244
+ return leftId - rightId;
1245
+ }
1246
+ return left.workerId.localeCompare(right.workerId);
1247
+ }
1248
+ function toInspectorWorkerTarget(raw) {
1249
+ const sessionId = readField(raw, "sessionId");
1250
+ const info = readField(raw, "workerInfo");
1251
+ if (typeof sessionId !== "string" || !isUnknownRecord2(info)) {
1252
+ return void 0;
1253
+ }
1254
+ const workerId = asString(info["workerId"]);
1255
+ if (workerId.length === 0) {
1256
+ return void 0;
1257
+ }
1258
+ return {
1259
+ sessionId,
1260
+ workerId,
1261
+ type: asString(info["type"]),
1262
+ title: asString(info["title"]),
1263
+ url: asString(info["url"])
1264
+ };
1265
+ }
1266
+ function readField(value, name) {
1267
+ return isUnknownRecord2(value) ? value[name] : void 0;
1268
+ }
1269
+ function isUnknownRecord2(value) {
1270
+ return typeof value === "object" && value !== null;
1271
+ }
1272
+ async function startNodeWorkerDiscovery(client) {
1273
+ const discovery = new NodeWorkerDiscovery(client);
1274
+ await discovery.enable();
1275
+ return discovery;
1276
+ }
1017
1277
  async function connectInspector(options) {
1018
1278
  const host = options.host ?? DEFAULT_HOST;
1019
1279
  const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
@@ -1030,13 +1290,70 @@ async function connectInspector(options) {
1030
1290
  url: target.webSocketDebuggerUrl,
1031
1291
  connectTimeoutMs
1032
1292
  });
1293
+ let workerDiscovery;
1033
1294
  try {
1034
- return await initSession(client, target);
1295
+ workerDiscovery = await startNodeWorkerDiscovery(client);
1296
+ if (options.workerIndex === void 0) {
1297
+ const session = await initSession(client, target);
1298
+ return withWorkerMetadata(session, workerDiscovery, targetIndex, targets.length);
1299
+ }
1300
+ return await initWorkerSession(
1301
+ client,
1302
+ workerDiscovery,
1303
+ options.workerIndex,
1304
+ targetIndex,
1305
+ targets.length
1306
+ );
1035
1307
  } catch (err) {
1308
+ await workerDiscovery?.dispose();
1036
1309
  client.dispose();
1037
1310
  throw err;
1038
1311
  }
1039
1312
  }
1313
+ async function initWorkerSession(parent, discovery, workerIndex, targetIndex, targetCount) {
1314
+ const workers = discovery.list();
1315
+ if (!discovery.supported) {
1316
+ throw new CfInspectorError(
1317
+ "INSPECTOR_DISCOVERY_FAILED",
1318
+ "This runtime does not expose the NodeWorker CDP domain; --worker cannot be used. Run list-targets for available raw targets."
1319
+ );
1320
+ }
1321
+ const worker = workers[workerIndex];
1322
+ if (worker === void 0) {
1323
+ throw new CfInspectorError(
1324
+ "INSPECTOR_DISCOVERY_FAILED",
1325
+ `No NodeWorker sub-session at index ${workerIndex.toString()} (available: ${workers.length.toString()}). Ensure the worker is alive, then rerun list-targets.`
1326
+ );
1327
+ }
1328
+ const client = await createNodeWorkerClient(parent, worker.sessionId);
1329
+ const session = await initSession(client, workerToInspectorTarget(worker));
1330
+ return withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent);
1331
+ }
1332
+ function withWorkerMetadata(session, discovery, targetIndex, targetCount, workerIndex, parent) {
1333
+ return {
1334
+ ...session,
1335
+ targetIndex,
1336
+ targetCount,
1337
+ ...workerIndex === void 0 ? {} : { workerIndex },
1338
+ workerTargets: discovery.list(),
1339
+ workerDiscoverySupported: discovery.supported,
1340
+ dispose: async () => {
1341
+ await session.dispose();
1342
+ await discovery.dispose();
1343
+ parent?.dispose();
1344
+ }
1345
+ };
1346
+ }
1347
+ function workerToInspectorTarget(worker) {
1348
+ return {
1349
+ description: "Node worker sub-session",
1350
+ id: worker.workerId,
1351
+ title: worker.title,
1352
+ type: worker.type,
1353
+ url: worker.url,
1354
+ webSocketDebuggerUrl: `node-worker://${worker.sessionId}`
1355
+ };
1356
+ }
1040
1357
  async function initSession(client, target) {
1041
1358
  const scripts = /* @__PURE__ */ new Map();
1042
1359
  client.on("Debugger.scriptParsed", (raw) => {
@@ -1056,14 +1373,14 @@ async function initSession(client, target) {
1056
1373
  return;
1057
1374
  }
1058
1375
  const params = raw;
1059
- const event = toPauseEvent(params, performance2.now(), scripts);
1376
+ const event = toPauseEvent(params, performance3.now(), scripts);
1060
1377
  if (pauseBuffer.length >= PAUSE_BUFFER_LIMIT) {
1061
1378
  pauseBuffer.shift();
1062
1379
  }
1063
1380
  pauseBuffer.push(event);
1064
1381
  });
1065
1382
  client.on("Debugger.resumed", () => {
1066
- debuggerState.lastResumedAtMs = performance2.now();
1383
+ debuggerState.lastResumedAtMs = performance3.now();
1067
1384
  });
1068
1385
  await client.send("Runtime.enable");
1069
1386
  await client.send("Debugger.enable");
@@ -1084,9 +1401,61 @@ async function initSession(client, target) {
1084
1401
  };
1085
1402
  }
1086
1403
 
1404
+ // src/cli/captureParser.ts
1405
+ function isQuoteChar(value) {
1406
+ return value === "'" || value === '"' || value === "`";
1407
+ }
1408
+ function consumeQuotedChar(state, char) {
1409
+ if (state.quote === void 0) {
1410
+ return false;
1411
+ }
1412
+ if (state.escaped) {
1413
+ state.escaped = false;
1414
+ return true;
1415
+ }
1416
+ if (char === "\\") {
1417
+ state.escaped = true;
1418
+ return true;
1419
+ }
1420
+ if (char === state.quote) {
1421
+ state.quote = void 0;
1422
+ }
1423
+ return true;
1424
+ }
1425
+ function stripQuotedText(expression) {
1426
+ const state = { quote: void 0, escaped: false };
1427
+ let stripped = "";
1428
+ for (const char of expression) {
1429
+ if (consumeQuotedChar(state, char)) {
1430
+ stripped += " ";
1431
+ continue;
1432
+ }
1433
+ if (isQuoteChar(char)) {
1434
+ state.quote = char;
1435
+ stripped += " ";
1436
+ continue;
1437
+ }
1438
+ stripped += char;
1439
+ }
1440
+ return stripped;
1441
+ }
1442
+ function looksLikeMutation(expression) {
1443
+ const stripped = stripQuotedText(expression);
1444
+ const hasUpdate = /(?:\+\+|--)/u.test(stripped);
1445
+ const hasAssignment = /(?:\*\*=|&&=|\|\|=|\?\?=|[+\-*/%&|^]=|(?:^|[^=!<>])=(?!=|>))/u.test(stripped);
1446
+ const hasDelete = /\bdelete\b/u.test(stripped);
1447
+ const hasMutatingMethod = /\.\s*(?:push|pop|shift|unshift|splice|sort|reverse|fill|copyWithin|set|add|delete|clear)\s*\(/u.test(stripped);
1448
+ const hasObjectMutation = /\bObject\s*\.\s*(?:assign|defineProperty|defineProperties)\s*\(/u.test(stripped);
1449
+ return hasUpdate || hasAssignment || hasDelete || hasMutatingMethod || hasObjectMutation;
1450
+ }
1451
+
1452
+ // src/snapshot/evaluation.ts
1453
+ init_types();
1454
+
1087
1455
  // src/snapshot/values.ts
1088
1456
  init_types();
1089
- var DEFAULT_MAX_VALUE_LENGTH = 4096;
1457
+ var DEFAULT_MAX_VALUE_LENGTH = 131072;
1458
+ var DEFAULT_STREAM_MAX_VALUE_LENGTH = 4096;
1090
1459
  function isPrimitive(value) {
1091
1460
  const t = typeof value;
1092
1461
  return t === "string" || t === "number" || t === "boolean" || t === "bigint" || t === "symbol";
@@ -1114,9 +1483,16 @@ function resolveMaxValueLength(value) {
1114
1483
  }
1115
1484
  function limitValueLength(raw, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
1116
1485
  if (raw.length <= maxValueLength) {
1117
- return raw;
1486
+ return { text: raw, truncated: false };
1118
1487
  }
1119
- return `${raw.slice(0, maxValueLength)}...`;
1488
+ return {
1489
+ text: raw.slice(0, maxValueLength),
1490
+ truncated: true,
1491
+ originalLength: raw.length
1492
+ };
1493
+ }
1494
+ function textTruncationFields(limited) {
1495
+ return limited.truncated ? { truncated: true, originalLength: limited.originalLength } : {};
1120
1496
  }
1121
1497
  function parseQuotedString(value) {
1122
1498
  try {
@@ -1201,7 +1577,12 @@ function toStructuredValue(variable) {
1201
1577
  // src/snapshot/evaluation.ts
1202
1578
  function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
1203
1579
  if (result.exceptionDetails !== void 0) {
1204
- return { expression, error: readEvalError(result, maxValueLength) };
1580
+ const limited = readEvalError(result, maxValueLength);
1581
+ return {
1582
+ expression,
1583
+ error: limited.text,
1584
+ ...textTruncationFields(limited)
1585
+ };
1205
1586
  }
1206
1587
  const inner = result.result;
1207
1588
  if (!inner) {
@@ -1209,8 +1590,12 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
1209
1590
  }
1210
1591
  const type = typeof inner.type === "string" ? inner.type : void 0;
1211
1592
  const buildCaptured = (rendered) => {
1212
- const sanitized = limitValueLength(rendered, maxValueLength);
1213
- const base = { expression, value: sanitized };
1593
+ const limited = limitValueLength(rendered, maxValueLength);
1594
+ const base = {
1595
+ expression,
1596
+ value: limited.text,
1597
+ ...textTruncationFields(limited)
1598
+ };
1214
1599
  return type === void 0 ? base : { ...base, type };
1215
1600
  };
1216
1601
  if (type === "string" && typeof inner.value === "string") {
@@ -1227,6 +1612,18 @@ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_V
1227
1612
  }
1228
1613
  return buildCaptured("undefined");
1229
1614
  }
1615
+ function sideEffectRefusalToCaptured(expression) {
1616
+ const error = new CfInspectorError(
1617
+ "MUTATION_NOT_ALLOWED",
1618
+ `V8 blocked the capture expression "${expression}" because it may have side effects. Pass --allow-mutation to run it explicitly.`
1619
+ );
1620
+ return {
1621
+ expression,
1622
+ error: `${error.code}: ${error.message}`,
1623
+ mutationRisk: true,
1624
+ blocked: true
1625
+ };
1626
+ }
1230
1627
  function readEvalError(result, maxValueLength) {
1231
1628
  const text = typeof result.exceptionDetails?.exception?.description === "string" ? result.exceptionDetails.exception.description : typeof result.exceptionDetails?.text === "string" ? result.exceptionDetails.text : "evaluation failed";
1232
1629
  return limitValueLength(text, maxValueLength);
@@ -1284,56 +1681,88 @@ async function captureProperties(session, objectId, limit, depth, maxValueLength
1284
1681
  return await captureProperty(session, prop, depth, maxValueLength);
1285
1682
  })
1286
1683
  );
1287
- return variables;
1684
+ const omittedCount = Math.max(properties.length - limited.length, 0);
1685
+ return omittedCount === 0 ? { variables } : { variables, omittedCount };
1288
1686
  }
1289
1687
  async function captureProperty(session, prop, depth, maxValueLength) {
1290
1688
  const name = typeof prop.name === "string" ? prop.name : "?";
1291
1689
  const described = describeProperty(prop);
1292
- const children = await capturePropertyChildren(session, described, depth, maxValueLength);
1293
- const sanitizedValue = limitValueLength(described.value, maxValueLength);
1294
- const base = { name, value: sanitizedValue };
1690
+ const capturedChildren = await capturePropertyChildren(
1691
+ session,
1692
+ described,
1693
+ depth,
1694
+ maxValueLength
1695
+ );
1696
+ const limited = limitValueLength(described.value, maxValueLength);
1697
+ const base = {
1698
+ name,
1699
+ value: limited.text,
1700
+ ...textTruncationFields(limited)
1701
+ };
1295
1702
  const withType = described.type === void 0 ? base : { ...base, type: described.type };
1296
- return children === void 0 ? withType : { ...withType, children };
1703
+ const children = capturedChildren?.variables;
1704
+ const withChildren = children === void 0 || children.length === 0 ? withType : { ...withType, children };
1705
+ const omittedCount = capturedChildren?.omittedCount ?? 0;
1706
+ return omittedCount === 0 ? withChildren : { ...withChildren, truncated: true, omittedCount };
1297
1707
  }
1298
1708
  async function capturePropertyChildren(session, described, depth, maxValueLength) {
1299
- if (depth <= 0 || described.objectId === void 0 || !isExpandable(described.type)) {
1709
+ if (described.objectId === void 0 || !isExpandable(described.type)) {
1300
1710
  return void 0;
1301
1711
  }
1712
+ if (depth <= 0) {
1713
+ return await countDepthOmissions(session, described.objectId);
1714
+ }
1302
1715
  try {
1303
- const nested = await captureProperties(
1716
+ return await captureProperties(
1304
1717
  session,
1305
1718
  described.objectId,
1306
1719
  MAX_CHILD_VARIABLES,
1307
1720
  depth - 1,
1308
1721
  maxValueLength
1309
1722
  );
1310
- return nested.length > 0 ? nested : void 0;
1311
1723
  } catch {
1312
1724
  return void 0;
1313
1725
  }
1314
1726
  }
1727
+ async function countDepthOmissions(session, objectId) {
1728
+ try {
1729
+ const properties = await getProperties(session, objectId);
1730
+ return properties.length === 0 ? void 0 : { variables: [], omittedCount: properties.length };
1731
+ } catch {
1732
+ return void 0;
1733
+ }
1734
+ }
1735
+ function countPropertyOmissions(captured) {
1736
+ return (captured.omittedCount ?? 0) + captured.variables.reduce((total, variable) => {
1737
+ const childOmissions = variable.children === void 0 ? 0 : countPropertyOmissions({ variables: variable.children });
1738
+ return total + (variable.omittedCount ?? 0) + childOmissions;
1739
+ }, 0);
1740
+ }
1315
1741
 
1316
1742
  // src/snapshot/exception.ts
1317
1743
  function asString2(value) {
1318
1744
  return typeof value === "string" && value.length > 0 ? value : void 0;
1319
1745
  }
1320
- async function materializeObject(session, objectId, maxValueLength) {
1746
+ async function materializeObject(session, objectId) {
1321
1747
  try {
1322
- const properties = await captureProperties(
1748
+ const captured = await captureProperties(
1323
1749
  session,
1324
1750
  objectId,
1325
1751
  MAX_SCOPE_VARIABLES,
1326
1752
  MAX_VARIABLE_DEPTH,
1327
- maxValueLength
1753
+ Number.MAX_SAFE_INTEGER
1328
1754
  );
1329
- if (properties.length === 0) {
1755
+ if (captured.variables.length === 0) {
1330
1756
  return void 0;
1331
1757
  }
1332
1758
  const structured = {};
1333
- for (const variable of properties) {
1759
+ for (const variable of captured.variables) {
1334
1760
  structured[variable.name] = toStructuredValue(variable);
1335
1761
  }
1336
- return JSON.stringify(structured);
1762
+ return {
1763
+ value: JSON.stringify(structured),
1764
+ omittedCount: countPropertyOmissions(captured)
1765
+ };
1337
1766
  } catch {
1338
1767
  return void 0;
1339
1768
  }
@@ -1386,18 +1815,44 @@ async function captureException(session, pause, maxValueLength) {
1386
1815
  return { error: "exception data has no objectId or value" };
1387
1816
  }
1388
1817
  const message = await readPropertyDescription(session, objectId, "message");
1389
- const rendered = await materializeObject(session, objectId, maxValueLength);
1818
+ const rendered = await materializeObject(session, objectId);
1390
1819
  if (rendered !== void 0) {
1391
- const result = buildResult(type, description, rendered, maxValueLength);
1392
- return message === void 0 ? result : { ...result, description: limitValueLength(message, maxValueLength) };
1820
+ return buildResult(
1821
+ type,
1822
+ message ?? description,
1823
+ rendered.value,
1824
+ maxValueLength,
1825
+ rendered.omittedCount
1826
+ );
1393
1827
  }
1394
1828
  return buildResult(type, description, description ?? "[exception]", maxValueLength);
1395
1829
  }
1396
- function buildResult(type, description, value, maxValueLength) {
1397
- const safeValue = limitValueLength(value, maxValueLength);
1398
- const base = { value: safeValue };
1830
+ function buildResult(type, description, value, maxValueLength, omittedCount = 0) {
1831
+ const limitedValue = limitValueLength(value, maxValueLength);
1832
+ const limitedDescription = description === void 0 ? void 0 : limitValueLength(description, maxValueLength);
1833
+ const base = {
1834
+ value: limitedValue.text,
1835
+ ...exceptionTruncationFields(limitedValue, limitedDescription)
1836
+ };
1399
1837
  const withType = type === void 0 ? base : { ...base, type };
1400
- return description === void 0 ? withType : { ...withType, description: limitValueLength(description, maxValueLength) };
1838
+ const withDescription = limitedDescription === void 0 ? withType : { ...withType, description: limitedDescription.text };
1839
+ return omittedCount === 0 ? withDescription : { ...withDescription, truncated: true, omittedCount };
1840
+ }
1841
+ function exceptionTruncationFields(value, description) {
1842
+ const valueLength = value.truncated ? value.originalLength : void 0;
1843
+ const descriptionLength = description?.truncated === true ? description.originalLength : void 0;
1844
+ const lengths = [valueLength, descriptionLength].filter(
1845
+ (length) => length !== void 0
1846
+ );
1847
+ if (lengths.length === 0) {
1848
+ return {};
1849
+ }
1850
+ return {
1851
+ truncated: true,
1852
+ originalLength: Math.max(...lengths),
1853
+ ...valueLength === void 0 ? {} : { valueOriginalLength: valueLength },
1854
+ ...descriptionLength === void 0 ? {} : { descriptionOriginalLength: descriptionLength }
1855
+ };
1401
1856
  }
1402
1857
 
1403
1858
  // src/snapshot/objects.ts
@@ -1412,20 +1867,23 @@ function objectIdFromEvalResult(result) {
1412
1867
  }
1413
1868
  return objectId;
1414
1869
  }
1415
- async function renderObjectCapture(session, objectId, maxValueLength) {
1870
+ async function renderObjectCapture(session, objectId) {
1416
1871
  try {
1417
- const properties = await captureProperties(
1872
+ const captured = await captureProperties(
1418
1873
  session,
1419
1874
  objectId,
1420
1875
  MAX_SCOPE_VARIABLES,
1421
1876
  MAX_VARIABLE_DEPTH,
1422
- maxValueLength
1877
+ Number.MAX_SAFE_INTEGER
1423
1878
  );
1424
1879
  const structured = {};
1425
- for (const variable of properties) {
1880
+ for (const variable of captured.variables) {
1426
1881
  structured[variable.name] = toStructuredValue(variable);
1427
1882
  }
1428
- return JSON.stringify(structured);
1883
+ return {
1884
+ value: JSON.stringify(structured),
1885
+ omittedCount: countPropertyOmissions(captured)
1886
+ };
1429
1887
  } catch {
1430
1888
  return void 0;
1431
1889
  }
@@ -1447,16 +1905,22 @@ async function withSerializedObjectCapture(session, expression, evalResult, capt
1447
1905
  if (objectId === void 0) {
1448
1906
  return captured;
1449
1907
  }
1450
- const rendered = await renderObjectCapture(session, objectId, maxValueLength);
1908
+ const rendered = await renderObjectCapture(session, objectId);
1451
1909
  if (rendered === void 0) {
1452
1910
  return captured;
1453
1911
  }
1454
- const normalized = normalizeRenderedObjectCapture(rendered, captured.value);
1912
+ const normalized = normalizeRenderedObjectCapture(rendered.value, captured.value);
1455
1913
  if (normalized === void 0) {
1456
1914
  return captured;
1457
1915
  }
1458
- const value = limitValueLength(normalized, maxValueLength);
1459
- return captured.type === void 0 ? { expression, value } : { expression, value, type: captured.type };
1916
+ const limited = limitValueLength(normalized, maxValueLength);
1917
+ const base = {
1918
+ expression,
1919
+ value: limited.text,
1920
+ ...textTruncationFields(limited),
1921
+ ...captured.type === void 0 ? {} : { type: captured.type }
1922
+ };
1923
+ return rendered.omittedCount === 0 ? base : { ...base, truncated: true, omittedCount: rendered.omittedCount };
1460
1924
  }
1461
1925
 
1462
1926
  // src/snapshot/scopes.ts
@@ -1471,35 +1935,39 @@ var PRIORITY_BY_TYPE = {
1471
1935
  module: 6,
1472
1936
  script: 7
1473
1937
  };
1474
- function selectScopes(scopeChain) {
1938
+ function rankedScopes(scopeChain) {
1475
1939
  const eligible = scopeChain.filter((scope) => scope.objectId !== void 0 && scope.type !== "global");
1476
- return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type)).slice(0, MAX_SCOPES);
1940
+ return [...eligible].sort((a, b) => priorityOf(a.type) - priorityOf(b.type));
1477
1941
  }
1478
1942
  function priorityOf(type) {
1479
1943
  return PRIORITY_BY_TYPE[type] ?? Number.MAX_SAFE_INTEGER;
1480
1944
  }
1481
1945
  async function captureScopes(session, frame, maxValueLength) {
1482
- const scopes = selectScopes(frame.scopeChain);
1483
- return await Promise.all(
1946
+ const ranked = rankedScopes(frame.scopeChain);
1947
+ const scopes = ranked.slice(0, MAX_SCOPES);
1948
+ const capturedScopes = await Promise.all(
1484
1949
  scopes.map(async (scope) => {
1485
1950
  const objectId = scope.objectId;
1486
1951
  if (objectId === void 0) {
1487
1952
  return { type: scope.type, variables: [] };
1488
1953
  }
1489
1954
  try {
1490
- const variables = await captureProperties(
1955
+ const captured = await captureProperties(
1491
1956
  session,
1492
1957
  objectId,
1493
1958
  MAX_SCOPE_VARIABLES,
1494
1959
  MAX_VARIABLE_DEPTH,
1495
1960
  maxValueLength
1496
1961
  );
1497
- return { type: scope.type, variables };
1962
+ const base = { type: scope.type, variables: captured.variables };
1963
+ return captured.omittedCount === void 0 ? base : { ...base, truncated: true, omittedCount: captured.omittedCount };
1498
1964
  } catch {
1499
1965
  return { type: scope.type, variables: [] };
1500
1966
  }
1501
1967
  })
1502
1968
  );
1969
+ const omittedCount = Math.max(ranked.length - capturedScopes.length, 0);
1970
+ return omittedCount === 0 ? { scopes: capturedScopes } : { scopes: capturedScopes, omittedCount };
1503
1971
  }
1504
1972
 
1505
1973
  // src/snapshot/stack.ts
@@ -1519,23 +1987,48 @@ function buildBaseFrame(frame) {
1519
1987
  };
1520
1988
  return frame.url === void 0 ? base : { ...base, url: frame.url };
1521
1989
  }
1522
- async function captureFrameExpression(session, callFrameId, expression, maxValueLength) {
1990
+ async function captureFrameExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
1991
+ const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
1523
1992
  try {
1524
- const result = await evaluateOnFrame(session, callFrameId, expression);
1993
+ const result = await evaluateOnFrame(session, callFrameId, expression, {
1994
+ ...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
1995
+ });
1996
+ if (isSideEffectRefusal(result)) {
1997
+ return sideEffectRefusalToCaptured(expression);
1998
+ }
1525
1999
  const captured = evalResultToCaptured(expression, result, maxValueLength);
1526
- return await withSerializedObjectCapture(session, expression, result, captured, maxValueLength);
2000
+ const serialized = await withSerializedObjectCapture(
2001
+ session,
2002
+ expression,
2003
+ result,
2004
+ captured,
2005
+ maxValueLength
2006
+ );
2007
+ return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
1527
2008
  } catch (err) {
1528
2009
  const message = err instanceof Error ? err.message : String(err);
1529
- return { expression, error: limitValueLength(message, maxValueLength) };
2010
+ const limited = limitValueLength(message, maxValueLength);
2011
+ const captured = {
2012
+ expression,
2013
+ error: limited.text,
2014
+ ...textTruncationFields(limited)
2015
+ };
2016
+ return mutationRisk ? { ...captured, mutationRisk: true } : captured;
1530
2017
  }
1531
2018
  }
1532
- async function captureFrameExpressions(session, frame, expressions, maxValueLength) {
2019
+ async function captureFrameExpressions(session, frame, expressions, maxValueLength, throwOnSideEffect) {
1533
2020
  if (expressions.length === 0) {
1534
2021
  return [];
1535
2022
  }
1536
2023
  return await Promise.all(
1537
2024
  expressions.map(
1538
- (expression) => captureFrameExpression(session, frame.callFrameId, expression, maxValueLength)
2025
+ (expression) => captureFrameExpression(
2026
+ session,
2027
+ frame.callFrameId,
2028
+ expression,
2029
+ maxValueLength,
2030
+ throwOnSideEffect
2031
+ )
1539
2032
  )
1540
2033
  );
1541
2034
  }
@@ -1555,7 +2048,8 @@ async function walkStack(session, callFrames, options) {
1555
2048
  session,
1556
2049
  frame,
1557
2050
  options.stackCaptures,
1558
- options.maxValueLength
2051
+ options.maxValueLength,
2052
+ options.throwOnSideEffect
1559
2053
  );
1560
2054
  return { ...base, captures };
1561
2055
  })
@@ -1577,14 +2071,25 @@ async function captureSnapshot(session, pause, options = {}) {
1577
2071
  column: top.columnNumber + 1
1578
2072
  };
1579
2073
  if (options.includeScopes === true) {
1580
- const scopes = await captureScopes(session, top, maxValueLength);
1581
- topFrame = { ...topFrame, scopes };
2074
+ const capturedScopes = await captureScopes(session, top, maxValueLength);
2075
+ topFrame = {
2076
+ ...topFrame,
2077
+ scopes: capturedScopes.scopes,
2078
+ ...capturedScopes.omittedCount === void 0 ? {} : { truncated: true, omittedCount: capturedScopes.omittedCount }
2079
+ };
1582
2080
  }
1583
- captures = await captureExpressions(session, top.callFrameId, options.captures, maxValueLength);
2081
+ captures = await captureExpressions(
2082
+ session,
2083
+ top.callFrameId,
2084
+ options.captures,
2085
+ maxValueLength,
2086
+ options.throwOnSideEffect
2087
+ );
1584
2088
  stack = await walkStack(session, pause.callFrames, {
1585
2089
  stackDepth: options.stackDepth ?? DEFAULT_STACK_DEPTH,
1586
2090
  stackCaptures: options.stackCaptures ?? [],
1587
- maxValueLength
2091
+ maxValueLength,
2092
+ ...options.throwOnSideEffect === void 0 ? {} : { throwOnSideEffect: options.throwOnSideEffect }
1588
2093
  });
1589
2094
  }
1590
2095
  const exception = await captureException(session, pause, maxValueLength);
@@ -1607,24 +2112,49 @@ function buildResult2(input) {
1607
2112
  const withStack = input.stack.length > 0 ? { ...withFrame, stack: input.stack } : withFrame;
1608
2113
  return input.exception === void 0 ? withStack : { ...withStack, exception: input.exception };
1609
2114
  }
1610
- async function captureExpressions(session, callFrameId, captures, maxValueLength) {
2115
+ async function captureExpressions(session, callFrameId, captures, maxValueLength, throwOnSideEffect) {
1611
2116
  if (captures === void 0 || captures.length === 0) {
1612
2117
  return [];
1613
2118
  }
1614
2119
  return await Promise.all(
1615
2120
  captures.map(async (expression) => {
1616
- return await captureExpression(session, callFrameId, expression, maxValueLength);
2121
+ return await captureExpression(
2122
+ session,
2123
+ callFrameId,
2124
+ expression,
2125
+ maxValueLength,
2126
+ throwOnSideEffect
2127
+ );
1617
2128
  })
1618
2129
  );
1619
2130
  }
1620
- async function captureExpression(session, callFrameId, expression, maxValueLength) {
2131
+ async function captureExpression(session, callFrameId, expression, maxValueLength, throwOnSideEffect) {
2132
+ const mutationRisk = throwOnSideEffect === false && looksLikeMutation(expression);
1621
2133
  try {
1622
- const result = await evaluateOnFrame(session, callFrameId, expression);
2134
+ const result = await evaluateOnFrame(session, callFrameId, expression, {
2135
+ ...throwOnSideEffect === void 0 ? {} : { throwOnSideEffect }
2136
+ });
2137
+ if (isSideEffectRefusal(result)) {
2138
+ return sideEffectRefusalToCaptured(expression);
2139
+ }
1623
2140
  const captured = evalResultToCaptured(expression, result, maxValueLength);
1624
- return await withSerializedObjectCapture(session, expression, result, captured, maxValueLength);
2141
+ const serialized = await withSerializedObjectCapture(
2142
+ session,
2143
+ expression,
2144
+ result,
2145
+ captured,
2146
+ maxValueLength
2147
+ );
2148
+ return mutationRisk ? { ...serialized, mutationRisk: true } : serialized;
1625
2149
  } catch (err) {
1626
2150
  const message = err instanceof Error ? err.message : String(err);
1627
- return { expression, error: limitValueLength(message, maxValueLength) };
2151
+ const limited = limitValueLength(message, maxValueLength);
2152
+ const captured = {
2153
+ expression,
2154
+ error: limited.text,
2155
+ ...textTruncationFields(limited)
2156
+ };
2157
+ return mutationRisk ? { ...captured, mutationRisk: true } : captured;
1628
2158
  }
1629
2159
  }
1630
2160
 
@@ -1712,7 +2242,7 @@ function readArg(arg, index) {
1712
2242
  }
1713
2243
  return index === 0 ? void 0 : "";
1714
2244
  }
1715
- function parseLogEvent(rawArgs, sentinel, location, timestamp) {
2245
+ function parseLogEvent(rawArgs, sentinel, location, timestamp, maxValueLength = DEFAULT_STREAM_MAX_VALUE_LENGTH) {
1716
2246
  if (!Array.isArray(rawArgs) || rawArgs.length < 2) {
1717
2247
  return void 0;
1718
2248
  }
@@ -1724,21 +2254,37 @@ function parseLogEvent(rawArgs, sentinel, location, timestamp) {
1724
2254
  const ts = new Date(typeof timestamp === "number" ? timestamp : Date.now()).toISOString();
1725
2255
  const at = `${location.file}:${location.line.toString()}`;
1726
2256
  if (payload.startsWith("!err:")) {
1727
- return { ts, at, error: payload.slice("!err:".length) };
2257
+ const limited = limitValueLength(payload.slice("!err:".length), maxValueLength);
2258
+ return {
2259
+ ts,
2260
+ at,
2261
+ error: limited.text,
2262
+ ...textTruncationFields(limited)
2263
+ };
1728
2264
  }
1729
- return parsePayload(ts, at, payload);
2265
+ return parsePayload(ts, at, payload, maxValueLength);
1730
2266
  }
1731
- function parsePayload(ts, at, payload) {
2267
+ function parsePayload(ts, at, payload, maxValueLength) {
1732
2268
  try {
1733
2269
  const parsed = JSON.parse(payload);
1734
2270
  if (typeof parsed === "string") {
1735
- return { ts, at, value: parsed };
2271
+ return buildValueEvent(ts, at, parsed, maxValueLength);
1736
2272
  }
1737
- return { ts, at, value: JSON.stringify(parsed) };
2273
+ return buildValueEvent(ts, at, JSON.stringify(parsed), maxValueLength);
1738
2274
  } catch {
1739
- return { ts, at, value: payload, raw: payload };
2275
+ return buildValueEvent(ts, at, payload, maxValueLength, true);
1740
2276
  }
1741
2277
  }
2278
+ function buildValueEvent(ts, at, value, maxValueLength, includeRaw = false) {
2279
+ const limited = limitValueLength(value, maxValueLength);
2280
+ return {
2281
+ ts,
2282
+ at,
2283
+ value: limited.text,
2284
+ ...includeRaw ? { raw: limited.text } : {},
2285
+ ...textTruncationFields(limited)
2286
+ };
2287
+ }
1742
2288
 
1743
2289
  // src/logpoint/stream.ts
1744
2290
  function validateMaxEvents(maxEvents) {
@@ -1768,6 +2314,9 @@ function validateHitCount2(hitCount) {
1768
2314
  async function streamLogpoint(session, options) {
1769
2315
  const maxEvents = validateMaxEvents(options.maxEvents);
1770
2316
  const hitCount = validateHitCount2(options.hitCount);
2317
+ const maxValueLength = resolveMaxValueLength(
2318
+ options.maxValueLength ?? DEFAULT_STREAM_MAX_VALUE_LENGTH
2319
+ );
1771
2320
  const sentinel = generateSentinel();
1772
2321
  const condition = buildLogpointCondition(sentinel, options.expression, {
1773
2322
  ...options.condition === void 0 ? {} : { predicate: options.condition },
@@ -1780,7 +2329,7 @@ async function streamLogpoint(session, options) {
1780
2329
  if (maxEventsReached) {
1781
2330
  return;
1782
2331
  }
1783
- const event = toLogpointEvent(raw, sentinel, options.location);
2332
+ const event = toLogpointEvent(raw, sentinel, options.location, maxValueLength);
1784
2333
  if (event === void 0) {
1785
2334
  return;
1786
2335
  }
@@ -1820,13 +2369,13 @@ async function streamLogpoint(session, options) {
1820
2369
  await removeBreakpointBestEffort(session, handle.breakpointId);
1821
2370
  }
1822
2371
  }
1823
- function toLogpointEvent(raw, sentinel, location) {
2372
+ function toLogpointEvent(raw, sentinel, location, maxValueLength) {
1824
2373
  const params = raw;
1825
2374
  if (asString3(params.type) !== "log") {
1826
2375
  return void 0;
1827
2376
  }
1828
2377
  const ts = typeof params.timestamp === "number" ? params.timestamp : void 0;
1829
- return parseLogEvent(params.args, sentinel, location, ts);
2378
+ return parseLogEvent(params.args, sentinel, location, ts, maxValueLength);
1830
2379
  }
1831
2380
  async function removeBreakpointBestEffort(session, breakpointId) {
1832
2381
  try {