@saptools/cf-inspector 0.3.4 → 0.3.6

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
@@ -109,7 +109,7 @@ cf-inspector snapshot --port 9229 \
109
109
  | `--port <number>` | Local port the inspector or tunnel listens on. **Required** unless `--app/--region/--org/--space` are all set |
110
110
  | `--bp <file:line>` | **Required.** Source location to break at. Pass multiple times to race several locations — the first one to hit wins |
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
- | `--capture <expr,…>` | Top-level comma-separated expressions to evaluate in the paused frame; nested commas inside objects, arrays, calls, or strings are preserved |
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
114
  | `--remote-root <value>` | Optional path-mapping anchor: literal path or `regex:<pattern>` / `/pattern/flags` |
115
115
  | `--no-json` | Print a human-readable summary instead of JSON |
package/dist/cli.js CHANGED
@@ -1232,6 +1232,123 @@ function evalResultToCaptured(expression, result) {
1232
1232
  }
1233
1233
  return buildCaptured("undefined");
1234
1234
  }
1235
+ function objectIdFromEvalResult(result) {
1236
+ const inner = result.result;
1237
+ if (inner?.type !== "object") {
1238
+ return void 0;
1239
+ }
1240
+ const objectId = inner.objectId;
1241
+ if (typeof objectId !== "string" || objectId.length === 0) {
1242
+ return void 0;
1243
+ }
1244
+ return objectId;
1245
+ }
1246
+ function parseQuotedString(value) {
1247
+ try {
1248
+ const parsed = JSON.parse(value);
1249
+ return typeof parsed === "string" ? parsed : value;
1250
+ } catch {
1251
+ return value;
1252
+ }
1253
+ }
1254
+ function parseNumericIndex(name) {
1255
+ const parsed = Number.parseInt(name, 10);
1256
+ if (!Number.isInteger(parsed) || parsed < 0 || parsed.toString() !== name) {
1257
+ return void 0;
1258
+ }
1259
+ return parsed;
1260
+ }
1261
+ function scalarFromVariable(variable) {
1262
+ const value = variable.value;
1263
+ if (variable.type === "string") {
1264
+ return parseQuotedString(value);
1265
+ }
1266
+ if (variable.type === "number") {
1267
+ const parsed = Number(value);
1268
+ return Number.isFinite(parsed) ? parsed : value;
1269
+ }
1270
+ if (variable.type === "boolean") {
1271
+ if (value === "true") {
1272
+ return true;
1273
+ }
1274
+ if (value === "false") {
1275
+ return false;
1276
+ }
1277
+ }
1278
+ if (variable.type === "undefined") {
1279
+ return "[undefined]";
1280
+ }
1281
+ if (variable.type === "bigint") {
1282
+ return value;
1283
+ }
1284
+ return value === "null" ? null : value;
1285
+ }
1286
+ function toStructuredValue(variable) {
1287
+ const children = variable.children;
1288
+ if (children === void 0 || children.length === 0) {
1289
+ return scalarFromVariable(variable);
1290
+ }
1291
+ const indexed = children.flatMap((child) => {
1292
+ const index = parseNumericIndex(child.name);
1293
+ if (index === void 0) {
1294
+ return [];
1295
+ }
1296
+ return [[index, toStructuredValue(child)]];
1297
+ });
1298
+ if (indexed.length > 0) {
1299
+ const maxIndex = Math.max(...indexed.map(([index]) => index));
1300
+ const out2 = Array.from({ length: maxIndex + 1 }, () => null);
1301
+ for (const [index, entry] of indexed) {
1302
+ out2[index] = entry;
1303
+ }
1304
+ return out2;
1305
+ }
1306
+ const out = {};
1307
+ for (const child of children) {
1308
+ out[child.name] = toStructuredValue(child);
1309
+ }
1310
+ return out;
1311
+ }
1312
+ async function renderObjectCapture(session, objectId) {
1313
+ try {
1314
+ const properties = await captureProperties(session, objectId, MAX_SCOPE_VARIABLES, MAX_VARIABLE_DEPTH);
1315
+ const structured = {};
1316
+ for (const variable of properties) {
1317
+ structured[variable.name] = toStructuredValue(variable);
1318
+ }
1319
+ return JSON.stringify(structured);
1320
+ } catch {
1321
+ return void 0;
1322
+ }
1323
+ }
1324
+ function normalizeRenderedObjectCapture(rendered, original) {
1325
+ if (rendered === "{}" && original !== "Object") {
1326
+ return void 0;
1327
+ }
1328
+ if (original.startsWith("Array(") && rendered === '{"length":0}') {
1329
+ return "[]";
1330
+ }
1331
+ return rendered;
1332
+ }
1333
+ async function withSerializedObjectCapture(session, expression, evalResult, captured) {
1334
+ if (captured.error !== void 0 || captured.value === void 0) {
1335
+ return captured;
1336
+ }
1337
+ const objectId = objectIdFromEvalResult(evalResult);
1338
+ if (objectId === void 0) {
1339
+ return captured;
1340
+ }
1341
+ const rendered = await renderObjectCapture(session, objectId);
1342
+ if (rendered === void 0) {
1343
+ return captured;
1344
+ }
1345
+ const normalized = normalizeRenderedObjectCapture(rendered, captured.value);
1346
+ if (normalized === void 0) {
1347
+ return captured;
1348
+ }
1349
+ const value = sanitizeValue(expression, normalized);
1350
+ return captured.type === void 0 ? { expression, value } : { expression, value, type: captured.type };
1351
+ }
1235
1352
  async function captureSnapshot(session, pause, options = {}) {
1236
1353
  const top = pause.callFrames[0];
1237
1354
  let topFrame;
@@ -1250,7 +1367,8 @@ async function captureSnapshot(session, pause, options = {}) {
1250
1367
  options.captures.map(async (expression) => {
1251
1368
  try {
1252
1369
  const result = await evaluateOnFrame(session, top.callFrameId, expression);
1253
- return evalResultToCaptured(expression, result);
1370
+ const captured = evalResultToCaptured(expression, result);
1371
+ return await withSerializedObjectCapture(session, expression, result, captured);
1254
1372
  } catch (err) {
1255
1373
  const message = err instanceof Error ? err.message : String(err);
1256
1374
  return { expression, error: message };