@saptools/cf-inspector 0.3.8 → 0.3.9

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 CHANGED
@@ -111,6 +111,7 @@ cf-inspector snapshot --port 9229 \
111
111
  | `--condition <expr>` | Only pause when this JS expression evaluates truthy in the paused frame. Errors in the condition are silently treated as `false` by V8 |
112
112
  | `--capture <expr,…>` | Top-level comma-separated expressions to evaluate in the paused frame; nested commas inside objects, arrays, calls, or strings are preserved. Object results are materialized to JSON strings when serializable, with fallback to CDP descriptions for non-serializable values |
113
113
  | `--timeout <seconds>` | How long to wait for the breakpoint to hit (default: `30`) |
114
+ | `--max-value-length <chars>` | Maximum characters per captured value before truncation (default: `4096`) |
114
115
  | `--remote-root <value>` | Optional path-mapping anchor: literal path or `regex:<pattern>` / `/pattern/flags` |
115
116
  | `--include-scopes` | Include expanded paused-frame scopes under `topFrame.scopes`. Omitted by default to keep targeted captures concise |
116
117
  | `--no-json` | Print a human-readable summary instead of JSON |
@@ -221,6 +222,7 @@ const bp = await setBreakpoint(session, {
221
222
  const pause = await waitForPause(session, { timeoutMs: 30_000 });
222
223
  const snapshot = await captureSnapshot(session, pause, {
223
224
  captures: ["this.user"],
225
+ maxValueLength: 4096,
224
226
  });
225
227
  const topFrame = pause.callFrames[0];
226
228
  if (topFrame === undefined) {
@@ -242,7 +244,7 @@ console.log({ bp, snapshot, customValue });
242
244
  | `setBreakpoint(session, location)` | Set a breakpoint by file/line + optional remote root |
243
245
  | `removeBreakpoint(session, id)` | Remove a breakpoint by id |
244
246
  | `waitForPause(session, options)` | Resolve when the next `Debugger.paused` event fires |
245
- | `captureSnapshot(session, pause, options)` | Build a structured snapshot of the paused frame. Pass `includeScopes: true` to expand scopes |
247
+ | `captureSnapshot(session, pause, options)` | Build a structured snapshot of the paused frame. Pass `includeScopes: true` to expand scopes or `maxValueLength` to override the default captured value limit |
246
248
  | `evaluateOnFrame(session, frameId, expression)` | Evaluate in a paused frame |
247
249
  | `evaluateGlobal(session, expression)` | Evaluate against the global Runtime |
248
250
  | `listScripts(session)` | Return the scripts the V8 instance knows about |
package/dist/cli.js CHANGED
@@ -1067,11 +1067,12 @@ async function waitForStop(session, options) {
1067
1067
  }
1068
1068
 
1069
1069
  // src/snapshot.ts
1070
+ init_types();
1070
1071
  var MAX_SCOPES = 3;
1071
1072
  var MAX_SCOPE_VARIABLES = 20;
1072
1073
  var MAX_CHILD_VARIABLES = 8;
1073
1074
  var MAX_VARIABLE_DEPTH = 2;
1074
- var MAX_VALUE_LENGTH = 240;
1075
+ var DEFAULT_MAX_VALUE_LENGTH = 4096;
1075
1076
  var PRIORITY_BY_TYPE = {
1076
1077
  local: 0,
1077
1078
  arguments: 1,
@@ -1132,16 +1133,28 @@ function formatPrimitive(value) {
1132
1133
  }
1133
1134
  return String(value);
1134
1135
  }
1135
- function limitValueLength(raw) {
1136
- if (raw.length <= MAX_VALUE_LENGTH) {
1136
+ function resolveMaxValueLength(value) {
1137
+ if (value === void 0) {
1138
+ return DEFAULT_MAX_VALUE_LENGTH;
1139
+ }
1140
+ if (!Number.isInteger(value) || value <= 0) {
1141
+ throw new CfInspectorError(
1142
+ "INVALID_ARGUMENT",
1143
+ `Invalid maxValueLength: ${value.toString()} \u2014 expected a positive integer`
1144
+ );
1145
+ }
1146
+ return value;
1147
+ }
1148
+ function limitValueLength(raw, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
1149
+ if (raw.length <= maxValueLength) {
1137
1150
  return raw;
1138
1151
  }
1139
- return `${raw.slice(0, MAX_VALUE_LENGTH)}...`;
1152
+ return `${raw.slice(0, maxValueLength)}...`;
1140
1153
  }
1141
1154
  function isExpandable(type) {
1142
1155
  return type === "object" || type === "function";
1143
1156
  }
1144
- async function captureProperties(session, objectId, limit, depth) {
1157
+ async function captureProperties(session, objectId, limit, depth, maxValueLength) {
1145
1158
  const properties = await getProperties(session, objectId);
1146
1159
  const limited = properties.slice(0, limit);
1147
1160
  const variables = await Promise.all(
@@ -1155,7 +1168,8 @@ async function captureProperties(session, objectId, limit, depth) {
1155
1168
  session,
1156
1169
  described.objectId,
1157
1170
  MAX_CHILD_VARIABLES,
1158
- depth - 1
1171
+ depth - 1,
1172
+ maxValueLength
1159
1173
  );
1160
1174
  if (nested.length > 0) {
1161
1175
  children = nested;
@@ -1163,7 +1177,7 @@ async function captureProperties(session, objectId, limit, depth) {
1163
1177
  } catch {
1164
1178
  }
1165
1179
  }
1166
- const sanitizedValue = limitValueLength(described.value);
1180
+ const sanitizedValue = limitValueLength(described.value, maxValueLength);
1167
1181
  const base = { name, value: sanitizedValue };
1168
1182
  const withType = described.type === void 0 ? base : { ...base, type: described.type };
1169
1183
  return children === void 0 ? withType : { ...withType, children };
@@ -1178,7 +1192,7 @@ function selectScopes(scopeChain) {
1178
1192
  function priorityOf(type) {
1179
1193
  return PRIORITY_BY_TYPE[type] ?? Number.MAX_SAFE_INTEGER;
1180
1194
  }
1181
- async function captureScopes(session, frame) {
1195
+ async function captureScopes(session, frame, maxValueLength) {
1182
1196
  const scopes = selectScopes(frame.scopeChain);
1183
1197
  return await Promise.all(
1184
1198
  scopes.map(async (scope) => {
@@ -1187,7 +1201,13 @@ async function captureScopes(session, frame) {
1187
1201
  return { type: scope.type, variables: [] };
1188
1202
  }
1189
1203
  try {
1190
- const variables = await captureProperties(session, objectId, MAX_SCOPE_VARIABLES, MAX_VARIABLE_DEPTH);
1204
+ const variables = await captureProperties(
1205
+ session,
1206
+ objectId,
1207
+ MAX_SCOPE_VARIABLES,
1208
+ MAX_VARIABLE_DEPTH,
1209
+ maxValueLength
1210
+ );
1191
1211
  return { type: scope.type, variables };
1192
1212
  } catch {
1193
1213
  return { type: scope.type, variables: [] };
@@ -1195,10 +1215,10 @@ async function captureScopes(session, frame) {
1195
1215
  })
1196
1216
  );
1197
1217
  }
1198
- function evalResultToCaptured(expression, result) {
1218
+ function evalResultToCaptured(expression, result, maxValueLength = DEFAULT_MAX_VALUE_LENGTH) {
1199
1219
  if (result.exceptionDetails !== void 0) {
1200
1220
  const text = typeof result.exceptionDetails.exception?.description === "string" ? result.exceptionDetails.exception.description : typeof result.exceptionDetails.text === "string" ? result.exceptionDetails.text : "evaluation failed";
1201
- return { expression, error: limitValueLength(text) };
1221
+ return { expression, error: limitValueLength(text, maxValueLength) };
1202
1222
  }
1203
1223
  const inner = result.result;
1204
1224
  if (!inner) {
@@ -1206,7 +1226,7 @@ function evalResultToCaptured(expression, result) {
1206
1226
  }
1207
1227
  const type = typeof inner.type === "string" ? inner.type : void 0;
1208
1228
  const buildCaptured = (rendered) => {
1209
- const sanitized = limitValueLength(rendered);
1229
+ const sanitized = limitValueLength(rendered, maxValueLength);
1210
1230
  const base = { expression, value: sanitized };
1211
1231
  return type === void 0 ? base : { ...base, type };
1212
1232
  };
@@ -1301,9 +1321,15 @@ function toStructuredValue(variable) {
1301
1321
  }
1302
1322
  return out;
1303
1323
  }
1304
- async function renderObjectCapture(session, objectId) {
1324
+ async function renderObjectCapture(session, objectId, maxValueLength) {
1305
1325
  try {
1306
- const properties = await captureProperties(session, objectId, MAX_SCOPE_VARIABLES, MAX_VARIABLE_DEPTH);
1326
+ const properties = await captureProperties(
1327
+ session,
1328
+ objectId,
1329
+ MAX_SCOPE_VARIABLES,
1330
+ MAX_VARIABLE_DEPTH,
1331
+ maxValueLength
1332
+ );
1307
1333
  const structured = {};
1308
1334
  for (const variable of properties) {
1309
1335
  structured[variable.name] = toStructuredValue(variable);
@@ -1322,7 +1348,7 @@ function normalizeRenderedObjectCapture(rendered, original) {
1322
1348
  }
1323
1349
  return rendered;
1324
1350
  }
1325
- async function withSerializedObjectCapture(session, expression, evalResult, captured) {
1351
+ async function withSerializedObjectCapture(session, expression, evalResult, captured, maxValueLength) {
1326
1352
  if (captured.error !== void 0 || captured.value === void 0) {
1327
1353
  return captured;
1328
1354
  }
@@ -1330,7 +1356,7 @@ async function withSerializedObjectCapture(session, expression, evalResult, capt
1330
1356
  if (objectId === void 0) {
1331
1357
  return captured;
1332
1358
  }
1333
- const rendered = await renderObjectCapture(session, objectId);
1359
+ const rendered = await renderObjectCapture(session, objectId, maxValueLength);
1334
1360
  if (rendered === void 0) {
1335
1361
  return captured;
1336
1362
  }
@@ -1338,10 +1364,11 @@ async function withSerializedObjectCapture(session, expression, evalResult, capt
1338
1364
  if (normalized === void 0) {
1339
1365
  return captured;
1340
1366
  }
1341
- const value = limitValueLength(normalized);
1367
+ const value = limitValueLength(normalized, maxValueLength);
1342
1368
  return captured.type === void 0 ? { expression, value } : { expression, value, type: captured.type };
1343
1369
  }
1344
1370
  async function captureSnapshot(session, pause, options = {}) {
1371
+ const maxValueLength = resolveMaxValueLength(options.maxValueLength);
1345
1372
  const top = pause.callFrames[0];
1346
1373
  let topFrame;
1347
1374
  let captures = [];
@@ -1353,7 +1380,7 @@ async function captureSnapshot(session, pause, options = {}) {
1353
1380
  column: top.columnNumber + 1
1354
1381
  };
1355
1382
  if (options.includeScopes === true) {
1356
- const scopes = await captureScopes(session, top);
1383
+ const scopes = await captureScopes(session, top, maxValueLength);
1357
1384
  topFrame = { ...topFrame, scopes };
1358
1385
  }
1359
1386
  if (options.captures !== void 0 && options.captures.length > 0) {
@@ -1361,11 +1388,17 @@ async function captureSnapshot(session, pause, options = {}) {
1361
1388
  options.captures.map(async (expression) => {
1362
1389
  try {
1363
1390
  const result = await evaluateOnFrame(session, top.callFrameId, expression);
1364
- const captured = evalResultToCaptured(expression, result);
1365
- return await withSerializedObjectCapture(session, expression, result, captured);
1391
+ const captured = evalResultToCaptured(expression, result, maxValueLength);
1392
+ return await withSerializedObjectCapture(
1393
+ session,
1394
+ expression,
1395
+ result,
1396
+ captured,
1397
+ maxValueLength
1398
+ );
1366
1399
  } catch (err) {
1367
1400
  const message = err instanceof Error ? err.message : String(err);
1368
- return { expression, error: limitValueLength(message) };
1401
+ return { expression, error: limitValueLength(message, maxValueLength) };
1369
1402
  }
1370
1403
  })
1371
1404
  );
@@ -1643,6 +1676,7 @@ async function handleSnapshot(opts) {
1643
1676
  const remoteRoot = parseRemoteRoot(opts.remoteRoot);
1644
1677
  const captures = parseCaptureList(opts.capture);
1645
1678
  const timeoutSec = parsePositiveInt(opts.timeout, "--timeout") ?? DEFAULT_BREAKPOINT_TIMEOUT_SEC;
1679
+ const maxValueLength = parsePositiveInt(opts.maxValueLength, "--max-value-length");
1646
1680
  const timeoutMs = timeoutSec * 1e3;
1647
1681
  const condition = opts.condition !== void 0 && opts.condition.trim().length > 0 ? opts.condition.trim() : void 0;
1648
1682
  const result = await withSession(target, async (session) => {
@@ -1677,7 +1711,8 @@ async function handleSnapshot(opts) {
1677
1711
  const pausedStartedAt = pause.receivedAtMs ?? performance2.now();
1678
1712
  const snapshot = await captureSnapshot(session, pause, {
1679
1713
  captures,
1680
- includeScopes: opts.includeScopes === true
1714
+ includeScopes: opts.includeScopes === true,
1715
+ ...maxValueLength === void 0 ? {} : { maxValueLength }
1681
1716
  });
1682
1717
  if (opts.keepPaused === true) {
1683
1718
  return withPausedDuration(snapshot, null);
@@ -1848,7 +1883,7 @@ async function main(argv) {
1848
1883
  "Breakpoint location (repeatable; first hit wins), e.g. src/handler.ts:42",
1849
1884
  collectStrings,
1850
1885
  []
1851
- ).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option(
1886
+ ).option("--capture <expr,\u2026>", "Top-level comma-separated expressions to evaluate in the paused frame").option("--timeout <seconds>", "How long to wait for the breakpoint to hit (default: 30)").option("--max-value-length <chars>", "Maximum characters per captured value before truncation (default: 4096)").option("--remote-root <value>", "Path-mapping anchor: literal path or regex:<pattern> / /pattern/flags").option(
1852
1887
  "--condition <expr>",
1853
1888
  "Only pause when this JS expression evaluates truthy in the paused frame"
1854
1889
  ).option("--include-scopes", "Include expanded paused-frame scopes in the snapshot").option("--no-json", "Print a human-readable summary instead of JSON").option("--keep-paused", "Skip Debugger.resume after capture; Node may resume when this CLI disconnects").option("--fail-on-unmatched-pause", "Fail immediately if the target pauses somewhere else").action(async (opts) => {