@crouton-kit/capture 1.4.21 → 1.4.23
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 +2 -0
- package/bin/capture +635 -577
- package/package.json +1 -1
- package/src/capture.ts +1 -1
- package/src/cdp/args.ts +57 -1
- package/src/cdp/commands/page/exec.ts +34 -2
- package/src/cdp/commands/tab/close.ts +3 -2
- package/src/interact.ts +17 -0
package/bin/capture
CHANGED
|
@@ -9095,6 +9095,347 @@ var init_console_recorder = __esm({
|
|
|
9095
9095
|
}
|
|
9096
9096
|
});
|
|
9097
9097
|
|
|
9098
|
+
// src/output/artifact.ts
|
|
9099
|
+
function isUrlRef(ref) {
|
|
9100
|
+
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(ref);
|
|
9101
|
+
}
|
|
9102
|
+
function stripTrailingSep(p) {
|
|
9103
|
+
return p.length > 1 && (p.endsWith("/") || p.endsWith(path5.sep)) ? p.slice(0, -1) : p;
|
|
9104
|
+
}
|
|
9105
|
+
function resolveRefFromPath(ref, config3) {
|
|
9106
|
+
const resolved = assertUnderCaptureRoot(stripTrailingSep(ref));
|
|
9107
|
+
const metaPath = path5.join(resolved, "meta.json");
|
|
9108
|
+
if (!fs5.existsSync(metaPath)) {
|
|
9109
|
+
throw new ArtifactResolutionError(
|
|
9110
|
+
ref,
|
|
9111
|
+
[resolved],
|
|
9112
|
+
`no ${config3.label} found at this path (missing meta.json)`,
|
|
9113
|
+
config3.creatingCommand
|
|
9114
|
+
);
|
|
9115
|
+
}
|
|
9116
|
+
return { kind: config3.kind, id: path5.basename(resolved), dir: resolved };
|
|
9117
|
+
}
|
|
9118
|
+
function resolveRefFromId(ref, config3) {
|
|
9119
|
+
const active = getActiveSession();
|
|
9120
|
+
if (!active) {
|
|
9121
|
+
throw new ArtifactResolutionError(
|
|
9122
|
+
ref,
|
|
9123
|
+
[],
|
|
9124
|
+
`no active capture session \u2014 a bare id resolves against the active session's ${config3.idSegments.join("/")} directory`,
|
|
9125
|
+
`capture session start (then re-run), or pass the absolute ${config3.label} path printed by ${config3.creatingCommand}`
|
|
9126
|
+
);
|
|
9127
|
+
}
|
|
9128
|
+
const dir = path5.join(active.dir, ...config3.idSegments, ref);
|
|
9129
|
+
const resolved = assertUnderCaptureRoot(dir);
|
|
9130
|
+
const metaPath = path5.join(resolved, "meta.json");
|
|
9131
|
+
if (!fs5.existsSync(metaPath)) {
|
|
9132
|
+
throw new ArtifactResolutionError(
|
|
9133
|
+
ref,
|
|
9134
|
+
[resolved],
|
|
9135
|
+
`no ${config3.label} named ${JSON.stringify(ref)} found in the active session (${active.sessionId})`,
|
|
9136
|
+
config3.creatingCommand
|
|
9137
|
+
);
|
|
9138
|
+
}
|
|
9139
|
+
return { kind: config3.kind, id: ref, dir: resolved };
|
|
9140
|
+
}
|
|
9141
|
+
function rejectRelativePath(ref) {
|
|
9142
|
+
if (!path5.isAbsolute(ref) && (ref.includes("/") || ref.includes(path5.sep))) {
|
|
9143
|
+
throw new ArtifactResolutionError(
|
|
9144
|
+
ref,
|
|
9145
|
+
[],
|
|
9146
|
+
"relative paths are not accepted \u2014 pass an absolute artifact path (as printed by the capturing command) or a bare id"
|
|
9147
|
+
);
|
|
9148
|
+
}
|
|
9149
|
+
}
|
|
9150
|
+
async function resolveSnapRef(ref, options = {}) {
|
|
9151
|
+
if (isUrlRef(ref)) {
|
|
9152
|
+
if (!options.onUrl) {
|
|
9153
|
+
throw new ArtifactResolutionError(ref, [], "this command does not accept a URL target \u2014 pass a snapshot id or path instead");
|
|
9154
|
+
}
|
|
9155
|
+
const result = await options.onUrl(ref);
|
|
9156
|
+
return { kind: "snap", id: result.id, dir: assertUnderCaptureRoot(result.dir) };
|
|
9157
|
+
}
|
|
9158
|
+
if (path5.isAbsolute(ref)) return resolveRefFromPath(ref, SNAP_CONFIG);
|
|
9159
|
+
rejectRelativePath(ref);
|
|
9160
|
+
return resolveRefFromId(ref, SNAP_CONFIG);
|
|
9161
|
+
}
|
|
9162
|
+
function resolveRecRef(ref) {
|
|
9163
|
+
if (isUrlRef(ref)) {
|
|
9164
|
+
throw new ArtifactResolutionError(
|
|
9165
|
+
ref,
|
|
9166
|
+
[],
|
|
9167
|
+
"a recording ref cannot be a URL \u2014 record one first with `capture motion rec <url> --do <action>` or `--start`/`--stop`"
|
|
9168
|
+
);
|
|
9169
|
+
}
|
|
9170
|
+
if (path5.isAbsolute(ref)) return resolveRefFromPath(ref, REC_CONFIG);
|
|
9171
|
+
rejectRelativePath(ref);
|
|
9172
|
+
return resolveRefFromId(ref, REC_CONFIG);
|
|
9173
|
+
}
|
|
9174
|
+
function resolveTraceRef(ref) {
|
|
9175
|
+
if (isUrlRef(ref)) {
|
|
9176
|
+
throw new ArtifactResolutionError(ref, [], "a trace ref cannot be a URL \u2014 record one first with `capture perf trace <url>` or `--start`/`--stop`");
|
|
9177
|
+
}
|
|
9178
|
+
const resolved = path5.isAbsolute(ref) ? resolveRefFromPath(ref, TRACE_CONFIG) : (rejectRelativePath(ref), resolveRefFromId(ref, TRACE_CONFIG));
|
|
9179
|
+
let meta;
|
|
9180
|
+
try {
|
|
9181
|
+
meta = JSON.parse(readPrivateFile(path5.join(resolved.dir, "meta.json")).toString("utf8"));
|
|
9182
|
+
} catch (error4) {
|
|
9183
|
+
throw new ArtifactResolutionError(ref, [path5.join(resolved.dir, "meta.json")], `could not read trace metadata: ${error4 instanceof Error ? error4.message : String(error4)}`, TRACE_CONFIG.creatingCommand);
|
|
9184
|
+
}
|
|
9185
|
+
const completion = meta.completion;
|
|
9186
|
+
if (completion !== "complete" && completion !== "partial" && completion !== "orphaned") {
|
|
9187
|
+
throw new ArtifactResolutionError(ref, [path5.join(resolved.dir, "meta.json")], "trace metadata has no valid completion state", TRACE_CONFIG.creatingCommand);
|
|
9188
|
+
}
|
|
9189
|
+
const inventory = meta.files;
|
|
9190
|
+
const inventoryMalformed = !Array.isArray(inventory);
|
|
9191
|
+
const inventoryMismatch = !inventoryMalformed && inventory.some((entry) => {
|
|
9192
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return true;
|
|
9193
|
+
const item = entry;
|
|
9194
|
+
const name = item.name;
|
|
9195
|
+
const bytes = item.bytes;
|
|
9196
|
+
if (typeof name !== "string" || typeof bytes !== "number" || !Number.isSafeInteger(bytes) || bytes < 0 || name.includes(path5.sep)) return true;
|
|
9197
|
+
try {
|
|
9198
|
+
return fs5.statSync(path5.join(resolved.dir, name)).size !== bytes;
|
|
9199
|
+
} catch {
|
|
9200
|
+
return true;
|
|
9201
|
+
}
|
|
9202
|
+
});
|
|
9203
|
+
const truncatedReason = inventoryMalformed ? "artifact_inventory_missing_or_malformed" : inventoryMismatch ? "artifact_inventory_mismatch" : void 0;
|
|
9204
|
+
return { ...resolved, completion: truncatedReason ? "truncated" : completion, ...truncatedReason ? { reason: truncatedReason } : typeof meta.reason === "string" ? { reason: meta.reason } : {} };
|
|
9205
|
+
}
|
|
9206
|
+
function creatingCommandFor(filename) {
|
|
9207
|
+
return CREATING_COMMAND_BY_FILE[filename];
|
|
9208
|
+
}
|
|
9209
|
+
function artifactPath(ref, filename, opts = {}) {
|
|
9210
|
+
const filePath = assertUnderCaptureRoot(path5.join(ref.dir, filename));
|
|
9211
|
+
const mustExist = opts.mustExist ?? true;
|
|
9212
|
+
if (mustExist && !fs5.existsSync(filePath)) {
|
|
9213
|
+
throw new ArtifactResolutionError(
|
|
9214
|
+
ref.id,
|
|
9215
|
+
[filePath],
|
|
9216
|
+
`${filename} is not present in ${ref.kind === "snap" ? "snapshot" : ref.kind === "rec" ? "recording" : "trace"} ${ref.id}`,
|
|
9217
|
+
creatingCommandFor(filename)
|
|
9218
|
+
);
|
|
9219
|
+
}
|
|
9220
|
+
return filePath;
|
|
9221
|
+
}
|
|
9222
|
+
function artifactExists(ref, filename) {
|
|
9223
|
+
return fs5.existsSync(assertUnderCaptureRoot(path5.join(ref.dir, filename)));
|
|
9224
|
+
}
|
|
9225
|
+
function readJsonArtifactFile(ref, filename) {
|
|
9226
|
+
const filePath = artifactPath(ref, filename);
|
|
9227
|
+
let raw;
|
|
9228
|
+
try {
|
|
9229
|
+
raw = fs5.readFileSync(filePath, "utf-8");
|
|
9230
|
+
} catch (err) {
|
|
9231
|
+
throw new ArtifactResolutionError(
|
|
9232
|
+
ref.id,
|
|
9233
|
+
[filePath],
|
|
9234
|
+
`could not read ${filename}: ${err instanceof Error ? err.message : String(err)}`,
|
|
9235
|
+
creatingCommandFor(filename)
|
|
9236
|
+
);
|
|
9237
|
+
}
|
|
9238
|
+
try {
|
|
9239
|
+
return JSON.parse(raw);
|
|
9240
|
+
} catch (err) {
|
|
9241
|
+
throw new ArtifactResolutionError(
|
|
9242
|
+
ref.id,
|
|
9243
|
+
[filePath],
|
|
9244
|
+
`${filename} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
9245
|
+
creatingCommandFor(filename)
|
|
9246
|
+
);
|
|
9247
|
+
}
|
|
9248
|
+
}
|
|
9249
|
+
function readNdjsonArtifactFile(ref, filename) {
|
|
9250
|
+
const filePath = artifactPath(ref, filename);
|
|
9251
|
+
let raw;
|
|
9252
|
+
try {
|
|
9253
|
+
raw = fs5.readFileSync(filePath, "utf-8");
|
|
9254
|
+
} catch (err) {
|
|
9255
|
+
throw new ArtifactResolutionError(
|
|
9256
|
+
ref.id,
|
|
9257
|
+
[filePath],
|
|
9258
|
+
`could not read ${filename}: ${err instanceof Error ? err.message : String(err)}`,
|
|
9259
|
+
creatingCommandFor(filename)
|
|
9260
|
+
);
|
|
9261
|
+
}
|
|
9262
|
+
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
9263
|
+
return lines.map((line4, i) => {
|
|
9264
|
+
try {
|
|
9265
|
+
return JSON.parse(line4);
|
|
9266
|
+
} catch (err) {
|
|
9267
|
+
throw new ArtifactResolutionError(
|
|
9268
|
+
ref.id,
|
|
9269
|
+
[filePath],
|
|
9270
|
+
`${filename} line ${i + 1} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
9271
|
+
creatingCommandFor(filename)
|
|
9272
|
+
);
|
|
9273
|
+
}
|
|
9274
|
+
});
|
|
9275
|
+
}
|
|
9276
|
+
function assertKind(ref, kind, fnName) {
|
|
9277
|
+
if (ref.kind !== kind) {
|
|
9278
|
+
throw new TypeError(`${fnName} expects a ${kind} ref, got a ${ref.kind} ref (${ref.id})`);
|
|
9279
|
+
}
|
|
9280
|
+
}
|
|
9281
|
+
function readMeta(ref) {
|
|
9282
|
+
return readJsonArtifactFile(ref, "meta.json");
|
|
9283
|
+
}
|
|
9284
|
+
function readGeometry(ref) {
|
|
9285
|
+
assertKind(ref, "snap", "readGeometry");
|
|
9286
|
+
return readJsonArtifactFile(ref, "geometry.json");
|
|
9287
|
+
}
|
|
9288
|
+
function readStyles(ref) {
|
|
9289
|
+
assertKind(ref, "snap", "readStyles");
|
|
9290
|
+
return readJsonArtifactFile(ref, "styles.json");
|
|
9291
|
+
}
|
|
9292
|
+
function readHittest(ref) {
|
|
9293
|
+
assertKind(ref, "snap", "readHittest");
|
|
9294
|
+
return readJsonArtifactFile(ref, "hittest.json");
|
|
9295
|
+
}
|
|
9296
|
+
function readText(ref) {
|
|
9297
|
+
assertKind(ref, "snap", "readText");
|
|
9298
|
+
return readJsonArtifactFile(ref, "text.json");
|
|
9299
|
+
}
|
|
9300
|
+
function readForms(ref) {
|
|
9301
|
+
assertKind(ref, "snap", "readForms");
|
|
9302
|
+
return readJsonArtifactFile(ref, "forms.json");
|
|
9303
|
+
}
|
|
9304
|
+
function readAnimation(ref) {
|
|
9305
|
+
assertKind(ref, "snap", "readAnimation");
|
|
9306
|
+
return readJsonArtifactFile(ref, "animation.json");
|
|
9307
|
+
}
|
|
9308
|
+
function readAx(ref) {
|
|
9309
|
+
assertKind(ref, "snap", "readAx");
|
|
9310
|
+
return readJsonArtifactFile(ref, "ax.json");
|
|
9311
|
+
}
|
|
9312
|
+
function readQueries(ref) {
|
|
9313
|
+
assertKind(ref, "snap", "readQueries");
|
|
9314
|
+
return readJsonArtifactFile(ref, "queries.json");
|
|
9315
|
+
}
|
|
9316
|
+
function readFocus(ref) {
|
|
9317
|
+
assertKind(ref, "snap", "readFocus");
|
|
9318
|
+
return readJsonArtifactFile(ref, "focus.json");
|
|
9319
|
+
}
|
|
9320
|
+
function readScroll(ref) {
|
|
9321
|
+
assertKind(ref, "snap", "readScroll");
|
|
9322
|
+
return readJsonArtifactFile(ref, "scroll.json");
|
|
9323
|
+
}
|
|
9324
|
+
function readLayers(ref) {
|
|
9325
|
+
assertKind(ref, "snap", "readLayers");
|
|
9326
|
+
return readJsonArtifactFile(ref, "layers.json");
|
|
9327
|
+
}
|
|
9328
|
+
function readStates(ref) {
|
|
9329
|
+
assertKind(ref, "snap", "readStates");
|
|
9330
|
+
return readJsonArtifactFile(ref, "states.json");
|
|
9331
|
+
}
|
|
9332
|
+
function readPixels(ref) {
|
|
9333
|
+
assertKind(ref, "snap", "readPixels");
|
|
9334
|
+
return readJsonArtifactFile(ref, "pixels.json");
|
|
9335
|
+
}
|
|
9336
|
+
function readMedia(ref) {
|
|
9337
|
+
assertKind(ref, "snap", "readMedia");
|
|
9338
|
+
return readJsonArtifactFile(ref, "media.json");
|
|
9339
|
+
}
|
|
9340
|
+
function readRects(ref) {
|
|
9341
|
+
assertKind(ref, "rec", "readRects");
|
|
9342
|
+
return readNdjsonArtifactFile(ref, "rects.jsonl");
|
|
9343
|
+
}
|
|
9344
|
+
function readEvents(ref) {
|
|
9345
|
+
assertKind(ref, "rec", "readEvents");
|
|
9346
|
+
return readNdjsonArtifactFile(ref, "events.jsonl");
|
|
9347
|
+
}
|
|
9348
|
+
function readMarkers(ref) {
|
|
9349
|
+
assertKind(ref, "rec", "readMarkers");
|
|
9350
|
+
return readJsonArtifactFile(ref, "markers.json");
|
|
9351
|
+
}
|
|
9352
|
+
function unstableRegionsFor(ref) {
|
|
9353
|
+
const geometry = readGeometry(ref);
|
|
9354
|
+
return geometry.unstableRegions ?? [];
|
|
9355
|
+
}
|
|
9356
|
+
function rectsOverlap(a, b) {
|
|
9357
|
+
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
|
9358
|
+
}
|
|
9359
|
+
function annotateUnstableFacts(facts, regions) {
|
|
9360
|
+
return facts.map((fact4) => {
|
|
9361
|
+
const caveats = [];
|
|
9362
|
+
for (const region of regions) {
|
|
9363
|
+
const byElement = fact4.elementId !== void 0 && (region.elementIds?.includes(fact4.elementId) ?? false);
|
|
9364
|
+
const byRect = fact4.rect !== void 0 && region.rect !== void 0 && rectsOverlap(fact4.rect, region.rect);
|
|
9365
|
+
if (byElement || byRect) {
|
|
9366
|
+
caveats.push({ regionId: region.id, selector: region.selector, reason: region.reason });
|
|
9367
|
+
}
|
|
9368
|
+
}
|
|
9369
|
+
return { fact: fact4, caveats };
|
|
9370
|
+
});
|
|
9371
|
+
}
|
|
9372
|
+
var fs5, path5, ArtifactResolutionError, SNAP_CONFIG, REC_CONFIG, TRACE_CONFIG, CREATING_COMMAND_BY_FILE;
|
|
9373
|
+
var init_artifact = __esm({
|
|
9374
|
+
"src/output/artifact.ts"() {
|
|
9375
|
+
fs5 = __toESM(require("fs"));
|
|
9376
|
+
path5 = __toESM(require("path"));
|
|
9377
|
+
init_artifacts();
|
|
9378
|
+
init_session_context();
|
|
9379
|
+
ArtifactResolutionError = class extends Error {
|
|
9380
|
+
ref;
|
|
9381
|
+
searched;
|
|
9382
|
+
creatingCommand;
|
|
9383
|
+
constructor(ref, searched, detail, creatingCommand) {
|
|
9384
|
+
const parts = [`could not resolve ref ${JSON.stringify(ref)}: ${detail}`];
|
|
9385
|
+
if (searched.length) parts.push(`looked at: ${searched.join(", ")}`);
|
|
9386
|
+
if (creatingCommand) parts.push(`create it with: ${creatingCommand}`);
|
|
9387
|
+
super(parts.join(" \u2014 "));
|
|
9388
|
+
this.name = "ArtifactResolutionError";
|
|
9389
|
+
this.ref = ref;
|
|
9390
|
+
this.searched = searched;
|
|
9391
|
+
this.creatingCommand = creatingCommand;
|
|
9392
|
+
}
|
|
9393
|
+
};
|
|
9394
|
+
SNAP_CONFIG = {
|
|
9395
|
+
kind: "snap",
|
|
9396
|
+
idSegments: ["measure", "snaps"],
|
|
9397
|
+
creatingCommand: "capture measure snap",
|
|
9398
|
+
label: "snapshot"
|
|
9399
|
+
};
|
|
9400
|
+
REC_CONFIG = {
|
|
9401
|
+
kind: "rec",
|
|
9402
|
+
idSegments: ["motion", "recs"],
|
|
9403
|
+
creatingCommand: "capture motion rec",
|
|
9404
|
+
label: "recording"
|
|
9405
|
+
};
|
|
9406
|
+
TRACE_CONFIG = {
|
|
9407
|
+
kind: "trace",
|
|
9408
|
+
idSegments: ["perf", "traces"],
|
|
9409
|
+
creatingCommand: "capture perf trace",
|
|
9410
|
+
label: "trace"
|
|
9411
|
+
};
|
|
9412
|
+
CREATING_COMMAND_BY_FILE = {
|
|
9413
|
+
"geometry.json": "capture measure snap",
|
|
9414
|
+
"styles.json": "capture measure snap",
|
|
9415
|
+
"hittest.json": "capture measure snap",
|
|
9416
|
+
"text.json": "capture measure snap",
|
|
9417
|
+
"forms.json": "capture measure snap",
|
|
9418
|
+
"animation.json": "capture measure snap",
|
|
9419
|
+
"ax.json": "capture measure snap",
|
|
9420
|
+
"media.json": "capture measure snap",
|
|
9421
|
+
"queries.json": "capture measure snap",
|
|
9422
|
+
"focus.json": "capture measure snap",
|
|
9423
|
+
"scroll.json": "capture measure snap",
|
|
9424
|
+
"layers.json": "capture measure snap",
|
|
9425
|
+
"states.json": "capture measure snap --state <state>",
|
|
9426
|
+
"churn.json": "capture measure snap (written only when the page did not settle)",
|
|
9427
|
+
"pixels.json": "capture measure snap --pixels",
|
|
9428
|
+
"dom.html": "capture measure snap",
|
|
9429
|
+
"screenshot.png": "capture measure snap",
|
|
9430
|
+
"meta.json": "capture measure snap (or capture motion rec for a recording)",
|
|
9431
|
+
"rects.jsonl": "capture motion rec",
|
|
9432
|
+
"events.jsonl": "capture motion rec",
|
|
9433
|
+
"markers.json": "capture motion rec",
|
|
9434
|
+
"trace.json": "capture perf trace"
|
|
9435
|
+
};
|
|
9436
|
+
}
|
|
9437
|
+
});
|
|
9438
|
+
|
|
9098
9439
|
// src/cdp/leaf-grammar.ts
|
|
9099
9440
|
function isParseableUrl(value) {
|
|
9100
9441
|
try {
|
|
@@ -9413,7 +9754,12 @@ function validateCliInvocation(parsed) {
|
|
|
9413
9754
|
}
|
|
9414
9755
|
if (leaf === "launch" || leaf === "list") requireCount(values, 0, 0, `tab ${leaf}`);
|
|
9415
9756
|
else if (leaf === "quit") requireCount(values, 0, 1, "tab quit");
|
|
9416
|
-
else
|
|
9757
|
+
else if (leaf === "close" && parsed.target !== void 0) {
|
|
9758
|
+
requireCount(values, 0, 1, "tab close");
|
|
9759
|
+
if (values.length === 1 && values[0] !== parsed.target) {
|
|
9760
|
+
throw schemaInput("tab close", `<target>=${values[0]}, --target=${parsed.target}`, "one tab: the positional <target> or --target, not two different ids", "<target> or --target");
|
|
9761
|
+
}
|
|
9762
|
+
} else requireCount(values, 1, 1, `tab ${leaf}`);
|
|
9417
9763
|
if (leaf === "network" && values[0] !== "offline" && values[0] !== "online") {
|
|
9418
9764
|
throw schemaInput("tab network", values[0] ?? "(missing)", "offline or online", "<mode>");
|
|
9419
9765
|
}
|
|
@@ -9788,6 +10134,36 @@ function needsEndpointResolution(parsed) {
|
|
|
9788
10134
|
if (parsed.command === "tab" && (parsed.positional[0] === "launch" || parsed.positional[0] === "quit")) return false;
|
|
9789
10135
|
return true;
|
|
9790
10136
|
}
|
|
10137
|
+
function mayReachBrowser(parsed) {
|
|
10138
|
+
const [leaf, sub] = parsed.positional;
|
|
10139
|
+
switch (parsed.command) {
|
|
10140
|
+
case "tab":
|
|
10141
|
+
return leaf !== "list";
|
|
10142
|
+
case "motion":
|
|
10143
|
+
return leaf === "rec";
|
|
10144
|
+
case "perf":
|
|
10145
|
+
return leaf === "trace";
|
|
10146
|
+
case "heap":
|
|
10147
|
+
return leaf === "snapshot";
|
|
10148
|
+
case "measure": {
|
|
10149
|
+
if (leaf === "diff" || leaf === "explain" || leaf === "text" || leaf === "map" && sub === "paint") return false;
|
|
10150
|
+
if (leaf === "check" || leaf === "census" || leaf === "map") return parsed.url !== void 0 || parsed.positional.some(isUrlRef);
|
|
10151
|
+
return true;
|
|
10152
|
+
}
|
|
10153
|
+
default:
|
|
10154
|
+
return true;
|
|
10155
|
+
}
|
|
10156
|
+
}
|
|
10157
|
+
function refuseUnownedEndpoint(parsed, sessionStart) {
|
|
10158
|
+
if (!process.env.CRTR_NODE_ID?.trim() || sessionStart || !mayReachBrowser(parsed)) return;
|
|
10159
|
+
if (parsed.port !== void 0 || parsed.targetSource === "flag" || parsed.targetSource === "session") return;
|
|
10160
|
+
const command = leafCommand(parsed.command, parsed.positional);
|
|
10161
|
+
throw captureError(
|
|
10162
|
+
"precondition",
|
|
10163
|
+
"no_owned_browser",
|
|
10164
|
+
`\`capture ${command}\` was not run: this node (CRTR_NODE_ID) has no browser of its own. With no --port, no --target and no active session holding a browser, capture will not use CDP_PORT, CDP_TARGET or auto-discovery, because the browser it found could belong to another node. Do one of: (1) \`capture session start --url <url>\` to open and hold your own browser tab, or \`capture tab launch\` then \`capture session start --port <port>\`; (2) pass \`--port <port>\` (see \`capture tab list\`); (3) pass \`--target <tabId>\`.`
|
|
10165
|
+
);
|
|
10166
|
+
}
|
|
9791
10167
|
function resolveCliContext(parsed) {
|
|
9792
10168
|
if (!needsEndpointResolution(parsed)) return parsed;
|
|
9793
10169
|
const sessionStart = parsed.command === "session" && parsed.positional[0] === "start";
|
|
@@ -9803,6 +10179,7 @@ function resolveCliContext(parsed) {
|
|
|
9803
10179
|
parsed.portSource = "session";
|
|
9804
10180
|
}
|
|
9805
10181
|
}
|
|
10182
|
+
refuseUnownedEndpoint(parsed, sessionStart);
|
|
9806
10183
|
if (parsed.port === void 0 && process.env.CDP_PORT !== void 0) {
|
|
9807
10184
|
parsed.port = schemaInteger(leafCommand(parsed.command, parsed.positional), process.env.CDP_PORT, "CDP_PORT", 1, 65535);
|
|
9808
10185
|
parsed.portSource = "env";
|
|
@@ -9819,6 +10196,7 @@ var init_args = __esm({
|
|
|
9819
10196
|
"src/cdp/args.ts"() {
|
|
9820
10197
|
init_errors();
|
|
9821
10198
|
init_session_context();
|
|
10199
|
+
init_artifact();
|
|
9822
10200
|
init_leaf_grammar();
|
|
9823
10201
|
VALUE_FLAGS = /* @__PURE__ */ new Set([
|
|
9824
10202
|
"--port",
|
|
@@ -9904,7 +10282,7 @@ var init_gate_guard = __esm({
|
|
|
9904
10282
|
|
|
9905
10283
|
// src/session/coordinator.ts
|
|
9906
10284
|
function scopeLifecycleLockPath() {
|
|
9907
|
-
return
|
|
10285
|
+
return path6.join(CAPTURE_ROOT, `.session-lifecycle-${process.env.CRTR_NODE_ID ?? "default"}`);
|
|
9908
10286
|
}
|
|
9909
10287
|
async function withSessionScopeLifecycle(action) {
|
|
9910
10288
|
const lock = await acquirePrivateLock(scopeLifecycleLockPath(), {
|
|
@@ -9918,10 +10296,10 @@ async function withSessionScopeLifecycle(action) {
|
|
|
9918
10296
|
}
|
|
9919
10297
|
}
|
|
9920
10298
|
function statePath(sessionDir2) {
|
|
9921
|
-
return
|
|
10299
|
+
return path6.join(assertUnderCaptureRoot(sessionDir2), ".operations.json");
|
|
9922
10300
|
}
|
|
9923
10301
|
function lockPath(sessionDir2) {
|
|
9924
|
-
return
|
|
10302
|
+
return path6.join(assertUnderCaptureRoot(sessionDir2), ".operations.lock");
|
|
9925
10303
|
}
|
|
9926
10304
|
function isBirth(value) {
|
|
9927
10305
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
@@ -9980,7 +10358,7 @@ async function admitSessionOperation(sessionDir2) {
|
|
|
9980
10358
|
};
|
|
9981
10359
|
}
|
|
9982
10360
|
async function beginSessionStop(sessionDir2) {
|
|
9983
|
-
const stopLock = await acquirePrivateLock(
|
|
10361
|
+
const stopLock = await acquirePrivateLock(path6.join(assertUnderCaptureRoot(sessionDir2), ".stop.lock"), {
|
|
9984
10362
|
acquireTimeoutMs: 12e4,
|
|
9985
10363
|
leaseMs: 1e3
|
|
9986
10364
|
});
|
|
@@ -10020,7 +10398,7 @@ async function beginSessionStop(sessionDir2) {
|
|
|
10020
10398
|
};
|
|
10021
10399
|
}
|
|
10022
10400
|
async function withSessionLifecycle(sessionDir2, action, seams2 = {}) {
|
|
10023
|
-
const lock = await acquirePrivateLock(
|
|
10401
|
+
const lock = await acquirePrivateLock(path6.join(assertUnderCaptureRoot(sessionDir2), ".lifecycle.lock"), {
|
|
10024
10402
|
acquireTimeoutMs: seams2.acquireTimeoutMs ?? 3e4,
|
|
10025
10403
|
leaseMs: seams2.leaseMs ?? 3e4,
|
|
10026
10404
|
pidBirthProvider: seams2.pidBirthProvider,
|
|
@@ -10034,11 +10412,11 @@ async function withSessionLifecycle(sessionDir2, action, seams2 = {}) {
|
|
|
10034
10412
|
lock.release();
|
|
10035
10413
|
}
|
|
10036
10414
|
}
|
|
10037
|
-
var crypto3,
|
|
10415
|
+
var crypto3, path6;
|
|
10038
10416
|
var init_coordinator = __esm({
|
|
10039
10417
|
"src/session/coordinator.ts"() {
|
|
10040
10418
|
crypto3 = __toESM(require("node:crypto"));
|
|
10041
|
-
|
|
10419
|
+
path6 = __toESM(require("node:path"));
|
|
10042
10420
|
init_errors();
|
|
10043
10421
|
init_artifacts();
|
|
10044
10422
|
}
|
|
@@ -10566,7 +10944,7 @@ function validateHarAppendBatch(value, source) {
|
|
|
10566
10944
|
return { entries, incompleteLifecycles };
|
|
10567
10945
|
}
|
|
10568
10946
|
function captureVersion() {
|
|
10569
|
-
const version = "1.4.
|
|
10947
|
+
const version = "1.4.23";
|
|
10570
10948
|
return typeof version === "string" && version.length > 0 ? version : "development";
|
|
10571
10949
|
}
|
|
10572
10950
|
function token() {
|
|
@@ -10584,15 +10962,15 @@ function vStoreHeader(value, source) {
|
|
|
10584
10962
|
return { format: "capture-live-har-ndjson", version: 1, creator: { name: "capture", version } };
|
|
10585
10963
|
}
|
|
10586
10964
|
function harFilePath(id) {
|
|
10587
|
-
if (
|
|
10588
|
-
if (
|
|
10589
|
-
if (id.endsWith(".json") && id.includes(
|
|
10590
|
-
return assertUnderCaptureRoot(
|
|
10965
|
+
if (path7.isAbsolute(id)) return assertUnderCaptureRoot(id);
|
|
10966
|
+
if (path7.basename(id) === id) return assertUnderCaptureRoot(path7.resolve(CAPTURE_ROOT, id));
|
|
10967
|
+
if (id.endsWith(".json") && id.includes(path7.sep)) return assertUnderCaptureRoot(id);
|
|
10968
|
+
return assertUnderCaptureRoot(path7.resolve(id));
|
|
10591
10969
|
}
|
|
10592
10970
|
async function createHarRecording(sessionDir2 = CAPTURE_ROOT) {
|
|
10593
|
-
const sessionAbsolute =
|
|
10971
|
+
const sessionAbsolute = path7.resolve(sessionDir2);
|
|
10594
10972
|
assertUnderCaptureRoot(sessionAbsolute);
|
|
10595
|
-
const harDir =
|
|
10973
|
+
const harDir = path7.join(sessionAbsolute, ".har");
|
|
10596
10974
|
ensurePrivateDir(harDir);
|
|
10597
10975
|
const header = {
|
|
10598
10976
|
format: "capture-live-har-ndjson",
|
|
@@ -10602,7 +10980,7 @@ async function createHarRecording(sessionDir2 = CAPTURE_ROOT) {
|
|
|
10602
10980
|
const headerLine = `${JSON.stringify(header)}
|
|
10603
10981
|
`;
|
|
10604
10982
|
for (; ; ) {
|
|
10605
|
-
const candidate =
|
|
10983
|
+
const candidate = path7.join(harDir, `${token()}.json`);
|
|
10606
10984
|
try {
|
|
10607
10985
|
createPrivateFile(candidate, headerLine);
|
|
10608
10986
|
} catch (error4) {
|
|
@@ -10665,39 +11043,39 @@ async function appendToHarRecording(id, batch) {
|
|
|
10665
11043
|
async function deleteHarRecording(id) {
|
|
10666
11044
|
unlinkPrivateFile(harFilePath(id));
|
|
10667
11045
|
}
|
|
10668
|
-
var import_node_crypto,
|
|
11046
|
+
var import_node_crypto, path7, MAX_BODY_BYTES, HAR_DIR;
|
|
10669
11047
|
var init_har_manager = __esm({
|
|
10670
11048
|
"src/har-manager.ts"() {
|
|
10671
11049
|
import_node_crypto = __toESM(require("node:crypto"));
|
|
10672
|
-
|
|
11050
|
+
path7 = __toESM(require("path"));
|
|
10673
11051
|
init_artifacts();
|
|
10674
11052
|
MAX_BODY_BYTES = 262144;
|
|
10675
|
-
HAR_DIR =
|
|
11053
|
+
HAR_DIR = path7.join(CAPTURE_ROOT, ".har");
|
|
10676
11054
|
}
|
|
10677
11055
|
});
|
|
10678
11056
|
|
|
10679
11057
|
// src/cdp/bridge/spawn.ts
|
|
10680
11058
|
function bridgeSocketPath(sessionDir2) {
|
|
10681
|
-
return
|
|
11059
|
+
return path8.join(sessionDir2, "bridge.sock");
|
|
10682
11060
|
}
|
|
10683
11061
|
function collectorSocketDir() {
|
|
10684
11062
|
const dir = "/tmp/capture-sockets";
|
|
10685
11063
|
try {
|
|
10686
|
-
|
|
11064
|
+
fs6.mkdirSync(dir, { mode: 448 });
|
|
10687
11065
|
} catch (error4) {
|
|
10688
11066
|
if (error4.code !== "EEXIST") throw error4;
|
|
10689
11067
|
}
|
|
10690
|
-
const stat =
|
|
11068
|
+
const stat = fs6.lstatSync(dir);
|
|
10691
11069
|
if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error(`collector socket directory is not a real directory: ${dir}`);
|
|
10692
11070
|
if (typeof process.getuid === "function" && stat.uid !== process.getuid()) throw new Error(`collector socket directory is not owned by this user: ${dir}`);
|
|
10693
|
-
|
|
11071
|
+
fs6.chmodSync(dir, 448);
|
|
10694
11072
|
return dir;
|
|
10695
11073
|
}
|
|
10696
11074
|
function shortSocketName(scopeDir) {
|
|
10697
|
-
return crypto5.createHash("sha1").update(
|
|
11075
|
+
return crypto5.createHash("sha1").update(path8.resolve(scopeDir)).digest("hex").slice(0, 16);
|
|
10698
11076
|
}
|
|
10699
11077
|
function collectorHostSocketPath(sessionDir2) {
|
|
10700
|
-
return
|
|
11078
|
+
return path8.join(collectorSocketDir(), `host-${shortSocketName(sessionDir2)}.sock`);
|
|
10701
11079
|
}
|
|
10702
11080
|
async function startBridge(sessionDir2, port, timeoutMs = 5e3) {
|
|
10703
11081
|
const socketPath = bridgeSocketPath(sessionDir2);
|
|
@@ -10713,7 +11091,7 @@ async function startBridge(sessionDir2, port, timeoutMs = 5e3) {
|
|
|
10713
11091
|
throw new Error("Failed to spawn CDP bridge process.");
|
|
10714
11092
|
}
|
|
10715
11093
|
const start2 = Date.now();
|
|
10716
|
-
while (!
|
|
11094
|
+
while (!fs6.existsSync(socketPath)) {
|
|
10717
11095
|
if (Date.now() - start2 > timeoutMs) {
|
|
10718
11096
|
stopBridge(pid, socketPath);
|
|
10719
11097
|
throw new Error(
|
|
@@ -10729,7 +11107,7 @@ async function startCollectorHost(socketPath, port, targetId, sessionDir2, timeo
|
|
|
10729
11107
|
child.unref();
|
|
10730
11108
|
if (!child.pid) throw new Error("Failed to spawn collector host process.");
|
|
10731
11109
|
const started = Date.now();
|
|
10732
|
-
while (!
|
|
11110
|
+
while (!fs6.existsSync(socketPath)) {
|
|
10733
11111
|
if (Date.now() - started > timeoutMs) {
|
|
10734
11112
|
stopBridge(child.pid, socketPath);
|
|
10735
11113
|
throw new Error(`Collector host (pid ${child.pid}) did not come up within ${timeoutMs}ms.`);
|
|
@@ -10747,18 +11125,18 @@ function stopBridge(pid, socketPath) {
|
|
|
10747
11125
|
}
|
|
10748
11126
|
if (socketPath) {
|
|
10749
11127
|
try {
|
|
10750
|
-
if (
|
|
11128
|
+
if (fs6.lstatSync(socketPath).isSocket()) fs6.unlinkSync(socketPath);
|
|
10751
11129
|
} catch {
|
|
10752
11130
|
}
|
|
10753
11131
|
}
|
|
10754
11132
|
}
|
|
10755
|
-
var import_child_process2, crypto5,
|
|
11133
|
+
var import_child_process2, crypto5, fs6, path8;
|
|
10756
11134
|
var init_spawn = __esm({
|
|
10757
11135
|
"src/cdp/bridge/spawn.ts"() {
|
|
10758
11136
|
import_child_process2 = require("child_process");
|
|
10759
11137
|
crypto5 = __toESM(require("crypto"));
|
|
10760
|
-
|
|
10761
|
-
|
|
11138
|
+
fs6 = __toESM(require("fs"));
|
|
11139
|
+
path8 = __toESM(require("path"));
|
|
10762
11140
|
}
|
|
10763
11141
|
});
|
|
10764
11142
|
|
|
@@ -10778,7 +11156,7 @@ function socketDir(create) {
|
|
|
10778
11156
|
}
|
|
10779
11157
|
function socketPathForToken(token2, createDir) {
|
|
10780
11158
|
if (!LOG_TAILER_SOCKET_TOKEN.test(token2)) throw new Error("invalid log tailer socket token");
|
|
10781
|
-
return
|
|
11159
|
+
return path9.join(socketDir(createDir), `${token2}.sock`);
|
|
10782
11160
|
}
|
|
10783
11161
|
function requireRegisteredLogTailer(value) {
|
|
10784
11162
|
const record5 = parseRegisteredLogTailer(value);
|
|
@@ -10799,23 +11177,23 @@ function ownership(record5, provider) {
|
|
|
10799
11177
|
return observed.status === "found" && sameBirth(observed.identity, record5.birth) ? "same" : "gone";
|
|
10800
11178
|
}
|
|
10801
11179
|
function socketIdentity(socketPath) {
|
|
10802
|
-
const stat =
|
|
11180
|
+
const stat = fs7.lstatSync(socketPath, { bigint: true });
|
|
10803
11181
|
if (!stat.isSocket()) throw new Error(`log tailer control path is not a socket: ${socketPath}`);
|
|
10804
11182
|
return { dev: stat.dev.toString(), ino: stat.ino.toString() };
|
|
10805
11183
|
}
|
|
10806
11184
|
function unlinkRecordedSocket(record5) {
|
|
10807
11185
|
let current;
|
|
10808
11186
|
try {
|
|
10809
|
-
current =
|
|
11187
|
+
current = fs7.lstatSync(record5.socketPath, { bigint: true });
|
|
10810
11188
|
} catch (error4) {
|
|
10811
11189
|
if (error4.code === "ENOENT") return;
|
|
10812
11190
|
throw error4;
|
|
10813
11191
|
}
|
|
10814
11192
|
if (!current.isSocket() || current.dev.toString() !== record5.socketDev || current.ino.toString() !== record5.socketIno) return;
|
|
10815
|
-
|
|
11193
|
+
fs7.unlinkSync(record5.socketPath);
|
|
10816
11194
|
}
|
|
10817
11195
|
function closeOwnedFd(fd) {
|
|
10818
|
-
if (fd !== void 0)
|
|
11196
|
+
if (fd !== void 0) fs7.closeSync(fd);
|
|
10819
11197
|
return void 0;
|
|
10820
11198
|
}
|
|
10821
11199
|
function awaitChildExit(child, timeoutMs) {
|
|
@@ -10902,8 +11280,8 @@ function awaitReadiness(child, timeoutMs) {
|
|
|
10902
11280
|
});
|
|
10903
11281
|
}
|
|
10904
11282
|
async function startSessionLogTailer(options) {
|
|
10905
|
-
const logsDir = ensurePrivateDir(
|
|
10906
|
-
const destPath =
|
|
11283
|
+
const logsDir = ensurePrivateDir(path9.join(options.sessionDir, "logs"));
|
|
11284
|
+
const destPath = path9.join(logsDir, `${options.name}.log`);
|
|
10907
11285
|
const socketToken = crypto6.randomBytes(8).toString("hex");
|
|
10908
11286
|
const socketPath = socketPathForToken(socketToken, true);
|
|
10909
11287
|
const nonce = crypto6.randomBytes(24).toString("hex");
|
|
@@ -11128,7 +11506,7 @@ function nonceMatches(expected, candidate) {
|
|
|
11128
11506
|
}
|
|
11129
11507
|
function writeReadiness(message) {
|
|
11130
11508
|
try {
|
|
11131
|
-
|
|
11509
|
+
fs7.writeSync(READINESS_FD, message);
|
|
11132
11510
|
return true;
|
|
11133
11511
|
} catch {
|
|
11134
11512
|
return false;
|
|
@@ -11258,7 +11636,7 @@ async function runLogTailer(argv) {
|
|
|
11258
11636
|
const owned = ownedSocket;
|
|
11259
11637
|
orphanCheck = setInterval(() => {
|
|
11260
11638
|
try {
|
|
11261
|
-
const current =
|
|
11639
|
+
const current = fs7.lstatSync(ownedSocketPath, { bigint: true });
|
|
11262
11640
|
if (current.isSocket() && current.dev.toString() === owned.dev && current.ino.toString() === owned.ino) return;
|
|
11263
11641
|
} catch (error4) {
|
|
11264
11642
|
if (error4.code !== "ENOENT") return;
|
|
@@ -11279,7 +11657,7 @@ async function runLogTailer(argv) {
|
|
|
11279
11657
|
});
|
|
11280
11658
|
reader.on("line", (line4) => {
|
|
11281
11659
|
try {
|
|
11282
|
-
|
|
11660
|
+
fs7.writeSync(1, `${(/* @__PURE__ */ new Date()).toISOString()} ${line4}
|
|
11283
11661
|
`);
|
|
11284
11662
|
} catch {
|
|
11285
11663
|
requestStop?.("fatal");
|
|
@@ -11296,7 +11674,7 @@ async function runLogTailer(argv) {
|
|
|
11296
11674
|
if (!writeReadiness("ready\n")) throw new Error("parent closed the readiness channel");
|
|
11297
11675
|
ready = true;
|
|
11298
11676
|
try {
|
|
11299
|
-
|
|
11677
|
+
fs7.closeSync(READINESS_FD);
|
|
11300
11678
|
} catch {
|
|
11301
11679
|
}
|
|
11302
11680
|
confirmDeadline = setTimeout(() => {
|
|
@@ -11331,7 +11709,7 @@ async function runLogTailer(argv) {
|
|
|
11331
11709
|
if (socketPath && ownedSocket) {
|
|
11332
11710
|
try {
|
|
11333
11711
|
const current = socketIdentity(socketPath);
|
|
11334
|
-
if (current.dev === ownedSocket.dev && current.ino === ownedSocket.ino)
|
|
11712
|
+
if (current.dev === ownedSocket.dev && current.ino === ownedSocket.ino) fs7.unlinkSync(socketPath);
|
|
11335
11713
|
} catch (error4) {
|
|
11336
11714
|
if (error4.code !== "ENOENT") exitCode = 1;
|
|
11337
11715
|
}
|
|
@@ -11339,14 +11717,14 @@ async function runLogTailer(argv) {
|
|
|
11339
11717
|
process.exitCode = exitCode;
|
|
11340
11718
|
}
|
|
11341
11719
|
}
|
|
11342
|
-
var import_node_child_process3, crypto6,
|
|
11720
|
+
var import_node_child_process3, crypto6, fs7, net2, path9, readline, READINESS_FD, WORKER_MS, CONTROL_MESSAGE_LIMIT, WORKER_CHILD_EXIT_TIMEOUT_MS, productionWorld, world;
|
|
11343
11721
|
var init_log_tailer = __esm({
|
|
11344
11722
|
"src/session/log-tailer.ts"() {
|
|
11345
11723
|
import_node_child_process3 = require("node:child_process");
|
|
11346
11724
|
crypto6 = __toESM(require("node:crypto"));
|
|
11347
|
-
|
|
11725
|
+
fs7 = __toESM(require("node:fs"));
|
|
11348
11726
|
net2 = __toESM(require("node:net"));
|
|
11349
|
-
|
|
11727
|
+
path9 = __toESM(require("node:path"));
|
|
11350
11728
|
readline = __toESM(require("node:readline"));
|
|
11351
11729
|
init_errors();
|
|
11352
11730
|
init_artifacts();
|
|
@@ -11368,16 +11746,16 @@ var init_log_tailer = __esm({
|
|
|
11368
11746
|
|
|
11369
11747
|
// src/cdp/host/collectors/heap.ts
|
|
11370
11748
|
function reconstructHeapSnapshot(dir) {
|
|
11371
|
-
const snapshot =
|
|
11372
|
-
if (!
|
|
11373
|
-
const bytes =
|
|
11749
|
+
const snapshot = path10.join(dir, "snapshot.heapsnapshot");
|
|
11750
|
+
if (!fs8.existsSync(snapshot)) return { summary: { bytes: 0 }, files: [] };
|
|
11751
|
+
const bytes = fs8.statSync(snapshot).size;
|
|
11374
11752
|
return { summary: { bytes }, files: [{ name: "snapshot.heapsnapshot", bytes }] };
|
|
11375
11753
|
}
|
|
11376
|
-
var
|
|
11754
|
+
var fs8, path10, HeapCollector;
|
|
11377
11755
|
var init_heap = __esm({
|
|
11378
11756
|
"src/cdp/host/collectors/heap.ts"() {
|
|
11379
|
-
|
|
11380
|
-
|
|
11757
|
+
fs8 = __toESM(require("node:fs"));
|
|
11758
|
+
path10 = __toESM(require("node:path"));
|
|
11381
11759
|
HeapCollector = class {
|
|
11382
11760
|
kind = "heap";
|
|
11383
11761
|
claims = ["heap-snapshot"];
|
|
@@ -11566,10 +11944,10 @@ function matchRule(rules, request) {
|
|
|
11566
11944
|
function headerEntries(headers2) {
|
|
11567
11945
|
return Object.entries(headers2).map(([name, value]) => ({ name, value }));
|
|
11568
11946
|
}
|
|
11569
|
-
var
|
|
11947
|
+
var path11, MAX_BODY_BYTES2, RESOURCE_TYPES, FAIL_REASONS, InterceptCollector;
|
|
11570
11948
|
var init_intercept = __esm({
|
|
11571
11949
|
"src/cdp/host/collectors/intercept.ts"() {
|
|
11572
|
-
|
|
11950
|
+
path11 = __toESM(require("node:path"));
|
|
11573
11951
|
init_artifacts();
|
|
11574
11952
|
MAX_BODY_BYTES2 = 10 * 1024 * 1024;
|
|
11575
11953
|
RESOURCE_TYPES = /* @__PURE__ */ new Set(["Document", "Stylesheet", "Image", "Media", "Font", "Script", "TextTrack", "XHR", "Fetch", "Prefetch", "EventSource", "WebSocket", "Manifest", "SignedExchange", "Ping", "CSPViolationReport", "Preflight", "Other"]);
|
|
@@ -11602,8 +11980,8 @@ var init_intercept = __esm({
|
|
|
11602
11980
|
if (!config3) throw new Error("intercept collector has no rule configuration");
|
|
11603
11981
|
this.context = context;
|
|
11604
11982
|
this.ruleMatches = Array.from({ length: config3.rules.length }, () => 0);
|
|
11605
|
-
writePrivateFile(
|
|
11606
|
-
writePrivateFile(
|
|
11983
|
+
writePrivateFile(path11.join(context.dir, "rules.json"), config3.source);
|
|
11984
|
+
writePrivateFile(path11.join(context.dir, "interceptions.jsonl"), "");
|
|
11607
11985
|
context.client.on("Fetch.requestPaused", this.onPaused);
|
|
11608
11986
|
try {
|
|
11609
11987
|
await context.client.send("Fetch.enable", { patterns: [{ urlPattern: "*", requestStage: "Request" }] });
|
|
@@ -11811,10 +12189,10 @@ async function runBridgeServer(socketPath, port) {
|
|
|
11811
12189
|
installProcessCleanup(cleanup, client);
|
|
11812
12190
|
}
|
|
11813
12191
|
function prepareSocketPath(socketPath) {
|
|
11814
|
-
|
|
12192
|
+
fs9.mkdirSync(path12.dirname(socketPath), { recursive: true });
|
|
11815
12193
|
try {
|
|
11816
|
-
if (!
|
|
11817
|
-
|
|
12194
|
+
if (!fs9.lstatSync(socketPath).isSocket()) throw new Error(`socket path is not a Unix socket: ${socketPath}`);
|
|
12195
|
+
fs9.unlinkSync(socketPath);
|
|
11818
12196
|
} catch (error4) {
|
|
11819
12197
|
if (error4.code !== "ENOENT") throw error4;
|
|
11820
12198
|
}
|
|
@@ -11845,7 +12223,7 @@ function closeNdjsonSocket(server2, socketPath) {
|
|
|
11845
12223
|
} catch {
|
|
11846
12224
|
}
|
|
11847
12225
|
try {
|
|
11848
|
-
if (
|
|
12226
|
+
if (fs9.lstatSync(socketPath).isSocket()) fs9.unlinkSync(socketPath);
|
|
11849
12227
|
} catch {
|
|
11850
12228
|
}
|
|
11851
12229
|
}
|
|
@@ -11868,12 +12246,12 @@ async function resolvePort(port) {
|
|
|
11868
12246
|
const { detectCdpPort: detectCdpPort2 } = await Promise.resolve().then(() => (init_detect(), detect_exports));
|
|
11869
12247
|
return detectCdpPort2();
|
|
11870
12248
|
}
|
|
11871
|
-
var
|
|
12249
|
+
var fs9, net3, path12, EventBroker;
|
|
11872
12250
|
var init_server = __esm({
|
|
11873
12251
|
"src/cdp/bridge/server.ts"() {
|
|
11874
|
-
|
|
12252
|
+
fs9 = __toESM(require("fs"));
|
|
11875
12253
|
net3 = __toESM(require("net"));
|
|
11876
|
-
|
|
12254
|
+
path12 = __toESM(require("path"));
|
|
11877
12255
|
init_targets();
|
|
11878
12256
|
EventBroker = class {
|
|
11879
12257
|
constructor(client) {
|
|
@@ -12668,7 +13046,7 @@ function wallTime(value) {
|
|
|
12668
13046
|
}
|
|
12669
13047
|
}
|
|
12670
13048
|
function captureVersion2() {
|
|
12671
|
-
const version = "1.4.
|
|
13049
|
+
const version = "1.4.23";
|
|
12672
13050
|
return typeof version === "string" && version.length > 0 ? version : "development";
|
|
12673
13051
|
}
|
|
12674
13052
|
function deepFreeze(value) {
|
|
@@ -13424,11 +13802,11 @@ function buildTakeRectElementsExpression(nonce, frameIndex) {
|
|
|
13424
13802
|
function buildTakeResizeTargetsExpression(nonce, seq) {
|
|
13425
13803
|
return `(function(){var k='__captureRecorder_'+${JSON.stringify(nonce)};var h=window[k];return h&&h.takeResizeTargets?h.takeResizeTargets(${JSON.stringify(seq)}):[];})()`;
|
|
13426
13804
|
}
|
|
13427
|
-
var crypto7,
|
|
13805
|
+
var crypto7, path13, RECORDER_BINDING_NAME, OBSERVER_INSTALLED_SENTINEL, TRACE_CATEGORIES, SCREENCAST_OPTIONS, MAX_BINDING_PAYLOAD_BYTES, BINDING_RATE_LIMIT_PER_SECOND, MAX_RECT_ELEMENTS, MAX_RECT_GEOMETRY_CANDIDATES, MAX_RECT_TAG_LENGTH, MAX_RECT_STRING_LENGTH, MAX_RECTS_SERIALIZED_BYTES, MAX_RECT_IDENTITY_RESOLUTIONS, MAX_TRACE_EVENTS_PER_BATCH, MAX_TRACE_SERIALIZED_BYTES, BINDING_FIELD_SANITIZERS, RecorderSession, MotionCollector;
|
|
13428
13806
|
var init_motion = __esm({
|
|
13429
13807
|
"src/cdp/host/collectors/motion.ts"() {
|
|
13430
13808
|
crypto7 = __toESM(require("crypto"));
|
|
13431
|
-
|
|
13809
|
+
path13 = __toESM(require("path"));
|
|
13432
13810
|
init_domains();
|
|
13433
13811
|
init_timing();
|
|
13434
13812
|
init_server();
|
|
@@ -13538,9 +13916,9 @@ var init_motion = __esm({
|
|
|
13538
13916
|
constructor(opts) {
|
|
13539
13917
|
this.client = opts.client;
|
|
13540
13918
|
this.recDir = ensurePrivateDir(opts.recDir);
|
|
13541
|
-
this.framesDir = ensurePrivateDir(
|
|
13542
|
-
this.eventsPath =
|
|
13543
|
-
this.rectsPath =
|
|
13919
|
+
this.framesDir = ensurePrivateDir(path13.join(this.recDir, "frames"));
|
|
13920
|
+
this.eventsPath = path13.join(this.recDir, "events.jsonl");
|
|
13921
|
+
this.rectsPath = path13.join(this.recDir, "rects.jsonl");
|
|
13544
13922
|
this.events = new EventBroker(this.client);
|
|
13545
13923
|
}
|
|
13546
13924
|
async start() {
|
|
@@ -14001,7 +14379,7 @@ var init_motion = __esm({
|
|
|
14001
14379
|
this.updateBaselinesPending();
|
|
14002
14380
|
}
|
|
14003
14381
|
const frameName = `frame-${String(frameIndex).padStart(6, "0")}.png`;
|
|
14004
|
-
writeBinaryPrivate(
|
|
14382
|
+
writeBinaryPrivate(path13.join(this.framesDir, frameName), Buffer.from(params.data, "base64"));
|
|
14005
14383
|
try {
|
|
14006
14384
|
const sample = await this.sampleRects(frameIndex);
|
|
14007
14385
|
const elements = this.sanitizeRectSample(sample.facts, sample.backendNodeIds);
|
|
@@ -14401,10 +14779,10 @@ var init_motion = __esm({
|
|
|
14401
14779
|
if (config3.viewport) {
|
|
14402
14780
|
const { width, height } = config3.viewport;
|
|
14403
14781
|
if (!Number.isSafeInteger(width) || !Number.isSafeInteger(height) || width <= 0 || height <= 0) throw new Error("motion viewport must contain positive integer width and height");
|
|
14404
|
-
writeJsonPrivate(
|
|
14782
|
+
writeJsonPrivate(path13.join(context.dir, "viewport-override.json"), { phase: "attempting", targetId: context.targetId, retainOnStop: true });
|
|
14405
14783
|
await context.client.send("Emulation.setDeviceMetricsOverride", { width, height, deviceScaleFactor: 1, mobile: false });
|
|
14406
14784
|
this.viewportApplied = true;
|
|
14407
|
-
writeJsonPrivate(
|
|
14785
|
+
writeJsonPrivate(path13.join(context.dir, "viewport-override.json"), { phase: "applied", targetId: context.targetId, retainOnStop: true });
|
|
14408
14786
|
}
|
|
14409
14787
|
this.har = new HARRecorder(context.client, (batch) => appendToHarRecording(config3.harId, batch));
|
|
14410
14788
|
await this.har.start();
|
|
@@ -14417,9 +14795,9 @@ var init_motion = __esm({
|
|
|
14417
14795
|
try {
|
|
14418
14796
|
await context.client.send("Emulation.clearDeviceMetricsOverride");
|
|
14419
14797
|
this.viewportApplied = false;
|
|
14420
|
-
removeArtifactTree(
|
|
14798
|
+
removeArtifactTree(path13.join(context.dir, "viewport-override.json"));
|
|
14421
14799
|
} catch (cleanupError) {
|
|
14422
|
-
writeJsonPrivate(
|
|
14800
|
+
writeJsonPrivate(path13.join(context.dir, "viewport-override.json"), {
|
|
14423
14801
|
phase: "restore-failed",
|
|
14424
14802
|
targetId: context.targetId,
|
|
14425
14803
|
retainOnStop: true,
|
|
@@ -14463,13 +14841,13 @@ var init_motion = __esm({
|
|
|
14463
14841
|
if (this.viewportApplied && cause.trigger !== "explicit") {
|
|
14464
14842
|
try {
|
|
14465
14843
|
await this.context.client.send("Emulation.clearDeviceMetricsOverride");
|
|
14466
|
-
removeArtifactTree(
|
|
14844
|
+
removeArtifactTree(path13.join(this.context.dir, "viewport-override.json"));
|
|
14467
14845
|
viewportRestored = true;
|
|
14468
14846
|
} catch {
|
|
14469
14847
|
viewportRestored = false;
|
|
14470
14848
|
}
|
|
14471
14849
|
}
|
|
14472
|
-
writeJsonPrivate(
|
|
14850
|
+
writeJsonPrivate(path13.join(this.context.dir, "markers.json"), stopped.markers);
|
|
14473
14851
|
return { summary: { frames: stopped.frameCount, durationMs: stopped.durationMs, eventCount: stopped.eventCount, markers: stopped.markers, state: stopped.frameCount > 0 ? "finalized" : "partial", viewportRestored, viewportRetained: this.viewportApplied && cause.trigger === "explicit" }, files: [] };
|
|
14474
14852
|
}
|
|
14475
14853
|
onDispatch(notice) {
|
|
@@ -14588,26 +14966,26 @@ var init_trace = __esm({
|
|
|
14588
14966
|
|
|
14589
14967
|
// src/cdp/host/kinds.ts
|
|
14590
14968
|
function motionReconstruct(dir) {
|
|
14591
|
-
const framesDir =
|
|
14592
|
-
const frames2 =
|
|
14969
|
+
const framesDir = path14.join(dir, "frames");
|
|
14970
|
+
const frames2 = fs10.existsSync(framesDir) ? fs10.readdirSync(framesDir).filter((name) => name.endsWith(".png")).length : 0;
|
|
14593
14971
|
const bytes = (name) => {
|
|
14594
14972
|
try {
|
|
14595
|
-
return
|
|
14973
|
+
return fs10.statSync(path14.join(dir, name)).size;
|
|
14596
14974
|
} catch {
|
|
14597
14975
|
return 0;
|
|
14598
14976
|
}
|
|
14599
14977
|
};
|
|
14600
|
-
const files = ["events.jsonl", "rects.jsonl", "markers.json"].filter((name) =>
|
|
14978
|
+
const files = ["events.jsonl", "rects.jsonl", "markers.json"].filter((name) => fs10.existsSync(path14.join(dir, name))).map((name) => ({ name, bytes: bytes(name) }));
|
|
14601
14979
|
return { summary: { frames: frames2, state: "orphaned-finalized" }, files };
|
|
14602
14980
|
}
|
|
14603
14981
|
function collectorKind(kind) {
|
|
14604
14982
|
return COLLECTOR_KINDS[kind];
|
|
14605
14983
|
}
|
|
14606
|
-
var
|
|
14984
|
+
var fs10, path14, motion, trace, heap, intercept, COLLECTOR_KINDS;
|
|
14607
14985
|
var init_kinds = __esm({
|
|
14608
14986
|
"src/cdp/host/kinds.ts"() {
|
|
14609
|
-
|
|
14610
|
-
|
|
14987
|
+
fs10 = __toESM(require("node:fs"));
|
|
14988
|
+
path14 = __toESM(require("node:path"));
|
|
14611
14989
|
init_heap();
|
|
14612
14990
|
init_intercept();
|
|
14613
14991
|
init_motion();
|
|
@@ -14641,8 +15019,8 @@ var init_kinds = __esm({
|
|
|
14641
15019
|
return new TraceCollector();
|
|
14642
15020
|
},
|
|
14643
15021
|
reconstruct(dir) {
|
|
14644
|
-
const file =
|
|
14645
|
-
const bytes =
|
|
15022
|
+
const file = path14.join(dir, "trace.json");
|
|
15023
|
+
const bytes = fs10.existsSync(file) ? fs10.statSync(file).size : 0;
|
|
14646
15024
|
return { summary: { events: 0, windowMs: 0, navigations: 0, categories: "devtools-default" }, files: bytes ? [{ name: "trace.json", bytes }] : [] };
|
|
14647
15025
|
}
|
|
14648
15026
|
};
|
|
@@ -14672,12 +15050,12 @@ var init_kinds = __esm({
|
|
|
14672
15050
|
reconstruct(dir) {
|
|
14673
15051
|
const bytes = (name) => {
|
|
14674
15052
|
try {
|
|
14675
|
-
return
|
|
15053
|
+
return fs10.statSync(path14.join(dir, name)).size;
|
|
14676
15054
|
} catch {
|
|
14677
15055
|
return 0;
|
|
14678
15056
|
}
|
|
14679
15057
|
};
|
|
14680
|
-
const files = ["rules.json", "interceptions.jsonl"].filter((name) =>
|
|
15058
|
+
const files = ["rules.json", "interceptions.jsonl"].filter((name) => fs10.existsSync(path14.join(dir, name))).map((name) => ({ name, bytes: bytes(name) }));
|
|
14681
15059
|
return { summary: { state: "orphaned-finalized" }, files };
|
|
14682
15060
|
}
|
|
14683
15061
|
};
|
|
@@ -14692,7 +15070,7 @@ var init_kinds = __esm({
|
|
|
14692
15070
|
|
|
14693
15071
|
// src/cdp/host/handle.ts
|
|
14694
15072
|
function collectorHostPath(sessionDir2) {
|
|
14695
|
-
return
|
|
15073
|
+
return path15.join(assertUnderCaptureRoot(sessionDir2), ".collector-host.json");
|
|
14696
15074
|
}
|
|
14697
15075
|
function parseHandle(raw, sessionDir2) {
|
|
14698
15076
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return null;
|
|
@@ -14716,7 +15094,7 @@ function scanCollectorHost(sessionDir2) {
|
|
|
14716
15094
|
if (read.status === "unknown") return { classification: "unknown", handle, path: file };
|
|
14717
15095
|
if (read.status === "found" && sameBirth(read.identity, handle.birth)) {
|
|
14718
15096
|
try {
|
|
14719
|
-
if (!
|
|
15097
|
+
if (!fs11.lstatSync(handle.socketPath).isSocket()) return { classification: "malformed", handle: null, path: file };
|
|
14720
15098
|
} catch {
|
|
14721
15099
|
return { classification: "malformed", handle: null, path: file };
|
|
14722
15100
|
}
|
|
@@ -14724,11 +15102,11 @@ function scanCollectorHost(sessionDir2) {
|
|
|
14724
15102
|
}
|
|
14725
15103
|
return { classification: "dead", handle, path: file };
|
|
14726
15104
|
}
|
|
14727
|
-
var
|
|
15105
|
+
var fs11, path15;
|
|
14728
15106
|
var init_handle = __esm({
|
|
14729
15107
|
"src/cdp/host/handle.ts"() {
|
|
14730
|
-
|
|
14731
|
-
|
|
15108
|
+
fs11 = __toESM(require("node:fs"));
|
|
15109
|
+
path15 = __toESM(require("node:path"));
|
|
14732
15110
|
init_spawn();
|
|
14733
15111
|
init_artifacts();
|
|
14734
15112
|
init_artifacts();
|
|
@@ -14741,7 +15119,7 @@ function isCollectorKind(value) {
|
|
|
14741
15119
|
}
|
|
14742
15120
|
function readCollecting(dir) {
|
|
14743
15121
|
try {
|
|
14744
|
-
const raw = JSON.parse(readPrivateFile(
|
|
15122
|
+
const raw = JSON.parse(readPrivateFile(path16.join(dir, "collecting.json")).toString("utf8"));
|
|
14745
15123
|
if (typeof raw.id !== "string" || !isCollectorKind(raw.kind) || typeof raw.startedAt !== "string") return null;
|
|
14746
15124
|
return { id: raw.id, kind: raw.kind, startedAt: raw.startedAt };
|
|
14747
15125
|
} catch {
|
|
@@ -14753,12 +15131,12 @@ function collectingDirectories(root) {
|
|
|
14753
15131
|
const walk2 = (dir) => {
|
|
14754
15132
|
let entries;
|
|
14755
15133
|
try {
|
|
14756
|
-
entries =
|
|
15134
|
+
entries = fs12.readdirSync(dir, { withFileTypes: true });
|
|
14757
15135
|
} catch {
|
|
14758
15136
|
return;
|
|
14759
15137
|
}
|
|
14760
15138
|
if (entries.some((entry) => entry.isFile() && entry.name === "collecting.json")) dirs.push(dir);
|
|
14761
|
-
for (const entry of entries) if (entry.isDirectory()) walk2(
|
|
15139
|
+
for (const entry of entries) if (entry.isDirectory()) walk2(path16.join(dir, entry.name));
|
|
14762
15140
|
};
|
|
14763
15141
|
walk2(root);
|
|
14764
15142
|
return dirs;
|
|
@@ -14771,7 +15149,7 @@ function reapOrphanedCollectors(sessionDir2) {
|
|
|
14771
15149
|
try {
|
|
14772
15150
|
const reconstructed = collectorKind(collecting.kind).reconstruct(dir);
|
|
14773
15151
|
const summary = reconstructed.summary && typeof reconstructed.summary === "object" && !Array.isArray(reconstructed.summary) ? reconstructed.summary : { value: reconstructed.summary };
|
|
14774
|
-
writeJsonPrivate(
|
|
15152
|
+
writeJsonPrivate(path16.join(dir, "meta.json"), {
|
|
14775
15153
|
id: collecting.id,
|
|
14776
15154
|
kind: collecting.kind,
|
|
14777
15155
|
completion: "orphaned",
|
|
@@ -14782,7 +15160,7 @@ function reapOrphanedCollectors(sessionDir2) {
|
|
|
14782
15160
|
summary,
|
|
14783
15161
|
...summary
|
|
14784
15162
|
});
|
|
14785
|
-
unlinkPrivateFile(
|
|
15163
|
+
unlinkPrivateFile(path16.join(dir, "collecting.json"));
|
|
14786
15164
|
outcomes.push({ status: "reaped", id: collecting.id, kind: collecting.kind, dir });
|
|
14787
15165
|
} catch (error4) {
|
|
14788
15166
|
outcomes.push({ status: "terminal", id: collecting.id, kind: collecting.kind, dir, error: error4 instanceof Error ? error4.message : String(error4) });
|
|
@@ -14828,11 +15206,11 @@ async function stopAndReapCollectorHostAtSessionStop(sessionDir2) {
|
|
|
14828
15206
|
return terminal(error4 instanceof Error ? error4.message : String(error4));
|
|
14829
15207
|
}
|
|
14830
15208
|
}
|
|
14831
|
-
var
|
|
15209
|
+
var fs12, path16;
|
|
14832
15210
|
var init_lifecycle = __esm({
|
|
14833
15211
|
"src/cdp/host/lifecycle.ts"() {
|
|
14834
|
-
|
|
14835
|
-
|
|
15212
|
+
fs12 = __toESM(require("node:fs"));
|
|
15213
|
+
path16 = __toESM(require("node:path"));
|
|
14836
15214
|
init_spawn();
|
|
14837
15215
|
init_artifacts();
|
|
14838
15216
|
init_kinds();
|
|
@@ -14987,20 +15365,20 @@ function readBundleManifest(bundlePath) {
|
|
|
14987
15365
|
return parsed;
|
|
14988
15366
|
}
|
|
14989
15367
|
function sessionDir(id, artifactRoot = CAPTURE_ROOT) {
|
|
14990
|
-
return
|
|
15368
|
+
return path17.join(artifactRoot, id);
|
|
14991
15369
|
}
|
|
14992
15370
|
function isSessionStopped(session) {
|
|
14993
|
-
return Boolean(session.stoppedAt) ||
|
|
15371
|
+
return Boolean(session.stoppedAt) || fs13.existsSync(path17.join(session.dir, "bundle.json"));
|
|
14994
15372
|
}
|
|
14995
15373
|
function createOneshotSession(kind, artifactDir) {
|
|
14996
15374
|
const id = `oneshot-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
14997
15375
|
const dir = sessionDir(id, artifactDir === void 0 ? CAPTURE_ROOT : registerArtifactRoot(artifactDir));
|
|
14998
|
-
const artifactsDir = kind === "measure" ?
|
|
15376
|
+
const artifactsDir = kind === "measure" ? path17.join(dir, "measure", "snaps") : kind === "motion" ? path17.join(dir, "motion", "recs") : path17.join(dir, "page");
|
|
14999
15377
|
ensurePrivateDir(artifactsDir);
|
|
15000
15378
|
return { id, dir, kind, artifactsDir };
|
|
15001
15379
|
}
|
|
15002
15380
|
function readSnapMeta(snapDir, fallbackId) {
|
|
15003
|
-
const meta = JSON.parse(
|
|
15381
|
+
const meta = JSON.parse(fs13.readFileSync(path17.join(snapDir, "meta.json"), "utf-8"));
|
|
15004
15382
|
return {
|
|
15005
15383
|
id: meta.id ?? fallbackId,
|
|
15006
15384
|
path: snapDir,
|
|
@@ -15011,7 +15389,7 @@ function readSnapMeta(snapDir, fallbackId) {
|
|
|
15011
15389
|
};
|
|
15012
15390
|
}
|
|
15013
15391
|
function readRecMeta(recDir, fallbackId) {
|
|
15014
|
-
const meta = JSON.parse(
|
|
15392
|
+
const meta = JSON.parse(fs13.readFileSync(path17.join(recDir, "meta.json"), "utf-8"));
|
|
15015
15393
|
return {
|
|
15016
15394
|
id: meta.id ?? fallbackId,
|
|
15017
15395
|
path: recDir,
|
|
@@ -15023,40 +15401,40 @@ function readRecMeta(recDir, fallbackId) {
|
|
|
15023
15401
|
};
|
|
15024
15402
|
}
|
|
15025
15403
|
function collectSnaps(dir) {
|
|
15026
|
-
const snapsRoot =
|
|
15027
|
-
if (!
|
|
15028
|
-
return
|
|
15404
|
+
const snapsRoot = path17.join(dir, "measure", "snaps");
|
|
15405
|
+
if (!fs13.existsSync(snapsRoot)) return [];
|
|
15406
|
+
return fs13.readdirSync(snapsRoot).filter((name) => fs13.existsSync(path17.join(snapsRoot, name, "meta.json"))).map((name) => readSnapMeta(path17.join(snapsRoot, name), name));
|
|
15029
15407
|
}
|
|
15030
15408
|
function collectRecs(dir) {
|
|
15031
|
-
const recsRoot =
|
|
15032
|
-
if (!
|
|
15033
|
-
return
|
|
15409
|
+
const recsRoot = path17.join(dir, "motion", "recs");
|
|
15410
|
+
if (!fs13.existsSync(recsRoot)) return [];
|
|
15411
|
+
return fs13.readdirSync(recsRoot).filter((name) => fs13.existsSync(path17.join(recsRoot, name, "meta.json"))).map((name) => readRecMeta(path17.join(recsRoot, name), name));
|
|
15034
15412
|
}
|
|
15035
15413
|
function collectMocks(dir) {
|
|
15036
|
-
const mocksRoot =
|
|
15037
|
-
if (!
|
|
15038
|
-
return
|
|
15039
|
-
const mockDir =
|
|
15040
|
-
const metaPath =
|
|
15041
|
-
if (!
|
|
15042
|
-
const meta = JSON.parse(
|
|
15414
|
+
const mocksRoot = path17.join(dir, "network", "mocks");
|
|
15415
|
+
if (!fs13.existsSync(mocksRoot)) return [];
|
|
15416
|
+
return fs13.readdirSync(mocksRoot).flatMap((name) => {
|
|
15417
|
+
const mockDir = path17.join(mocksRoot, name);
|
|
15418
|
+
const metaPath = path17.join(mockDir, "meta.json");
|
|
15419
|
+
if (!fs13.existsSync(metaPath)) return [];
|
|
15420
|
+
const meta = JSON.parse(fs13.readFileSync(metaPath, "utf8"));
|
|
15043
15421
|
return [{ id: typeof meta.id === "string" ? meta.id : name, path: mockDir, completion: typeof meta.completion === "string" ? meta.completion : "partial", rules: typeof meta.rules === "number" ? meta.rules : 0, paused: typeof meta.paused === "number" ? meta.paused : 0, matched: typeof meta.matched === "number" ? meta.matched : 0, releasedUnmatched: typeof meta.releasedUnmatched === "number" ? meta.releasedUnmatched : 0 }];
|
|
15044
15422
|
});
|
|
15045
15423
|
}
|
|
15046
15424
|
function readLighthouseReportMeta(reportDir, fallbackId) {
|
|
15047
|
-
const meta = JSON.parse(
|
|
15425
|
+
const meta = JSON.parse(fs13.readFileSync(path17.join(reportDir, "meta.json"), "utf-8"));
|
|
15048
15426
|
if (typeof meta.url !== "string" || typeof meta.finalUrl !== "string" || meta.preset !== "mobile" && meta.preset !== "desktop" || !Array.isArray(meta.categories) || !meta.categories.every((category) => typeof category === "string") || meta.lighthouse !== null && typeof meta.lighthouse !== "string" || meta.axe !== null && typeof meta.axe !== "string") {
|
|
15049
15427
|
throw captureError("artifact", "invalid_lighthouse_report_metadata", `Lighthouse report metadata at ${reportDir} is invalid.`);
|
|
15050
15428
|
}
|
|
15051
15429
|
return { id: typeof meta.id === "string" ? meta.id : fallbackId, path: reportDir, url: meta.url, finalUrl: meta.finalUrl, preset: meta.preset, categories: meta.categories, lighthouse: meta.lighthouse, axe: meta.axe };
|
|
15052
15430
|
}
|
|
15053
15431
|
function collectLighthouseReports(dir) {
|
|
15054
|
-
const reportsRoot =
|
|
15055
|
-
if (!
|
|
15056
|
-
return
|
|
15432
|
+
const reportsRoot = path17.join(dir, "lighthouse", "reports");
|
|
15433
|
+
if (!fs13.existsSync(reportsRoot)) return [];
|
|
15434
|
+
return fs13.readdirSync(reportsRoot).filter((name) => fs13.existsSync(path17.join(reportsRoot, name, "meta.json"))).map((name) => readLighthouseReportMeta(path17.join(reportsRoot, name), name));
|
|
15057
15435
|
}
|
|
15058
15436
|
function sessionMetaPath2(id, artifactRoot = CAPTURE_ROOT) {
|
|
15059
|
-
return
|
|
15437
|
+
return path17.join(sessionDir(id, artifactRoot), ".session.json");
|
|
15060
15438
|
}
|
|
15061
15439
|
function tryReadSession(id, artifactRoot = CAPTURE_ROOT) {
|
|
15062
15440
|
const metaPath = sessionMetaPath2(id, artifactRoot);
|
|
@@ -15178,7 +15556,7 @@ async function start(parsed) {
|
|
|
15178
15556
|
let selectedBrowser = null;
|
|
15179
15557
|
let endpointSelectionReason = null;
|
|
15180
15558
|
try {
|
|
15181
|
-
ensurePrivateDir(
|
|
15559
|
+
ensurePrivateDir(path17.join(dir, "shots"));
|
|
15182
15560
|
acquired.push({ label: "artifact tree", release: () => removeArtifactTree(dir) });
|
|
15183
15561
|
harId = await startWorld.createHar(dir);
|
|
15184
15562
|
const acquiredHarId = harId;
|
|
@@ -15318,8 +15696,8 @@ async function logTail(parsed) {
|
|
|
15318
15696
|
process.exitCode = 1;
|
|
15319
15697
|
return;
|
|
15320
15698
|
}
|
|
15321
|
-
const source =
|
|
15322
|
-
const name = parsed.name ??
|
|
15699
|
+
const source = path17.resolve(sourcePath);
|
|
15700
|
+
const name = parsed.name ?? path17.basename(source, path17.extname(source));
|
|
15323
15701
|
const labelReason = rejectLogLabel(name);
|
|
15324
15702
|
if (labelReason) {
|
|
15325
15703
|
const labelHint = parsed.name === void 0 && labelReason === `exceeds ${MAX_LOG_LABEL_BYTES} bytes` ? " Pass `--name <short>` to choose a shorter destination label." : "";
|
|
@@ -15331,7 +15709,7 @@ async function logTail(parsed) {
|
|
|
15331
15709
|
process.exitCode = 1;
|
|
15332
15710
|
return;
|
|
15333
15711
|
}
|
|
15334
|
-
if (!
|
|
15712
|
+
if (!fs13.existsSync(source)) {
|
|
15335
15713
|
emitResult({
|
|
15336
15714
|
tag: "error",
|
|
15337
15715
|
attrs: { command: "session log", code: "log_file_not_found" },
|
|
@@ -15415,9 +15793,9 @@ async function logTail(parsed) {
|
|
|
15415
15793
|
}
|
|
15416
15794
|
}
|
|
15417
15795
|
async function locateSessionHar(session) {
|
|
15418
|
-
const stopped =
|
|
15796
|
+
const stopped = fs13.existsSync(path17.join(session.dir, "bundle.json"));
|
|
15419
15797
|
if (stopped) {
|
|
15420
|
-
const harPath =
|
|
15798
|
+
const harPath = path17.join(session.dir, "har.json");
|
|
15421
15799
|
let raw;
|
|
15422
15800
|
try {
|
|
15423
15801
|
raw = readPrivateFile(harPath).toString("utf-8");
|
|
@@ -15661,7 +16039,7 @@ function exportHarBody(id, located, parsed) {
|
|
|
15661
16039
|
return true;
|
|
15662
16040
|
}
|
|
15663
16041
|
try {
|
|
15664
|
-
|
|
16042
|
+
fs13.writeFileSync(parsed.out, bytes);
|
|
15665
16043
|
} catch (cause) {
|
|
15666
16044
|
emitResult({ tag: "error", attrs: { command: "session har", code: "body_write_failed" }, summary: fact`The selected response body was not written to ${parsed.out}: ${cause instanceof Error ? cause.message : String(cause)}` }, { json: parsed.json });
|
|
15667
16045
|
process.exitCode = 1;
|
|
@@ -15825,7 +16203,7 @@ function bundleRows(manifest) {
|
|
|
15825
16203
|
function emitStoppedFromManifest(id, sessionDir2, manifest, parsed) {
|
|
15826
16204
|
emitResult({
|
|
15827
16205
|
tag: "session-stopped",
|
|
15828
|
-
attrs: { id, path:
|
|
16206
|
+
attrs: { id, path: path17.join(sessionDir2, "bundle.json") },
|
|
15829
16207
|
summary: fact`Session ${id} stopped after ${manifest.duration}ms; bundle manifest written.`,
|
|
15830
16208
|
sections: [lineList(bundleRows(manifest))],
|
|
15831
16209
|
followUp: fact`capture session view ${id}`
|
|
@@ -15866,7 +16244,7 @@ async function stop(parsed) {
|
|
|
15866
16244
|
let committed = false;
|
|
15867
16245
|
try {
|
|
15868
16246
|
session = readSession(id);
|
|
15869
|
-
const bundlePath =
|
|
16247
|
+
const bundlePath = path17.join(session.dir, "bundle.json");
|
|
15870
16248
|
try {
|
|
15871
16249
|
const manifest2 = readBundleManifest(bundlePath);
|
|
15872
16250
|
if (session.harId) {
|
|
@@ -15895,19 +16273,19 @@ async function stop(parsed) {
|
|
|
15895
16273
|
if (hostTeardown.status === "terminal") {
|
|
15896
16274
|
throw new Error(`collector host teardown failed: ${hostTeardown.error}`);
|
|
15897
16275
|
}
|
|
15898
|
-
const shotsDir =
|
|
15899
|
-
const shots =
|
|
16276
|
+
const shotsDir = path17.join(session.dir, "shots");
|
|
16277
|
+
const shots = fs13.existsSync(shotsDir) ? fs13.readdirSync(shotsDir).filter((name) => name.endsWith(".png") || name.endsWith(".jpg")).map((name) => ({ name, path: path17.join(shotsDir, name) })) : [];
|
|
15900
16278
|
let har2 = null;
|
|
15901
16279
|
if (session.harId) {
|
|
15902
16280
|
const harData = await readHarRecording(session.harId);
|
|
15903
|
-
const harPath =
|
|
16281
|
+
const harPath = path17.join(session.dir, "har.json");
|
|
15904
16282
|
writeJsonPrivate(harPath, harData);
|
|
15905
16283
|
har2 = { id: session.harId, path: harPath, entryCount: harData.log.entries.length };
|
|
15906
16284
|
}
|
|
15907
|
-
const logsDir =
|
|
15908
|
-
const logs =
|
|
15909
|
-
const filePath =
|
|
15910
|
-
const content =
|
|
16285
|
+
const logsDir = path17.join(session.dir, "logs");
|
|
16286
|
+
const logs = fs13.existsSync(logsDir) ? fs13.readdirSync(logsDir).filter((name) => name.endsWith(".log")).map((name) => {
|
|
16287
|
+
const filePath = path17.join(logsDir, name);
|
|
16288
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
15911
16289
|
return { name, path: filePath, lines: content ? content.split("\n").filter(Boolean).length : 0 };
|
|
15912
16290
|
}) : [];
|
|
15913
16291
|
const snaps = collectSnaps(session.dir);
|
|
@@ -15916,7 +16294,7 @@ async function stop(parsed) {
|
|
|
15916
16294
|
const reports = collectLighthouseReports(session.dir);
|
|
15917
16295
|
const knownDirs = /* @__PURE__ */ new Set(["shots", "logs", "lighthouse", "measure", "motion", "network", ".har", ".stop.lock", ".operations.lock"]);
|
|
15918
16296
|
const knownFiles = /* @__PURE__ */ new Set([".session.json", ".operations.json", "har.json", "bundle.json", "bridge.sock"]);
|
|
15919
|
-
const other =
|
|
16297
|
+
const other = fs13.readdirSync(session.dir).filter((name) => !knownDirs.has(name) && !knownFiles.has(name)).map((name) => ({ name, path: path17.join(session.dir, name) }));
|
|
15920
16298
|
const manifest = {
|
|
15921
16299
|
id: session.sessionId,
|
|
15922
16300
|
startedAt: session.startedAt ?? "",
|
|
@@ -15968,7 +16346,7 @@ function list(parsed) {
|
|
|
15968
16346
|
return;
|
|
15969
16347
|
}
|
|
15970
16348
|
if (rejectSurplusPositionals(parsed, "list", 0, "capture session list")) return;
|
|
15971
|
-
const reads = registeredArtifactRoots().flatMap((artifactRoot) =>
|
|
16349
|
+
const reads = registeredArtifactRoots().flatMap((artifactRoot) => fs13.existsSync(artifactRoot) ? fs13.readdirSync(artifactRoot).filter((d) => fs13.existsSync(sessionMetaPath2(d, artifactRoot))).flatMap((d) => {
|
|
15972
16350
|
try {
|
|
15973
16351
|
return [tryReadSession(d, artifactRoot)];
|
|
15974
16352
|
} catch {
|
|
@@ -15978,7 +16356,7 @@ function list(parsed) {
|
|
|
15978
16356
|
const sessions = reads.flatMap((read) => {
|
|
15979
16357
|
if (!read.ok) return [];
|
|
15980
16358
|
const session = read.session;
|
|
15981
|
-
const hasBundled =
|
|
16359
|
+
const hasBundled = fs13.existsSync(path17.join(session.dir, "bundle.json"));
|
|
15982
16360
|
return [{ id: session.sessionId, startedAt: session.startedAt ?? "", url: session.url ?? null, status: hasBundled ? "stopped" : "active" }];
|
|
15983
16361
|
});
|
|
15984
16362
|
const unreadable = reads.flatMap((read) => read.ok ? [] : [read]);
|
|
@@ -16056,7 +16434,7 @@ function view(parsed) {
|
|
|
16056
16434
|
process.exitCode = 1;
|
|
16057
16435
|
return;
|
|
16058
16436
|
}
|
|
16059
|
-
const bundlePath =
|
|
16437
|
+
const bundlePath = path17.join(session.dir, "bundle.json");
|
|
16060
16438
|
let manifest;
|
|
16061
16439
|
try {
|
|
16062
16440
|
manifest = readBundleManifest(bundlePath);
|
|
@@ -16139,11 +16517,11 @@ async function sessionMain(parsed, _args) {
|
|
|
16139
16517
|
return;
|
|
16140
16518
|
}
|
|
16141
16519
|
}
|
|
16142
|
-
var
|
|
16520
|
+
var fs13, path17, VIEW_FILTERS, SECTION_LABELS, SESSION_TAB_ATTACH_TIMEOUT_MS, COMMAND_BLOCK, START_USAGE, STOP_USAGE, LIST_USAGE, VIEW_USAGE, DEFAULT_HAR_ROWS, DEFAULT_FULL_HAR_ROWS, HAR_USAGE, LOG_USAGE, productionStartWorld, startWorld;
|
|
16143
16521
|
var init_commands = __esm({
|
|
16144
16522
|
"src/session/commands.ts"() {
|
|
16145
|
-
|
|
16146
|
-
|
|
16523
|
+
fs13 = __toESM(require("fs"));
|
|
16524
|
+
path17 = __toESM(require("path"));
|
|
16147
16525
|
init_har_manager();
|
|
16148
16526
|
init_session_context();
|
|
16149
16527
|
init_spawn();
|
|
@@ -16502,7 +16880,7 @@ async function startCollectors(parsed, client) {
|
|
|
16502
16880
|
let harRecorder;
|
|
16503
16881
|
if (parsed.har && !routed) {
|
|
16504
16882
|
const harPath = harFilePath(parsed.har);
|
|
16505
|
-
if (!
|
|
16883
|
+
if (!fs14.existsSync(harPath)) {
|
|
16506
16884
|
throw captureError(
|
|
16507
16885
|
"precondition",
|
|
16508
16886
|
"har_missing",
|
|
@@ -16584,10 +16962,10 @@ async function withPageAction(parsed, opts, fn) {
|
|
|
16584
16962
|
client.close();
|
|
16585
16963
|
}
|
|
16586
16964
|
}
|
|
16587
|
-
var
|
|
16965
|
+
var fs14, import_node_perf_hooks2, seams;
|
|
16588
16966
|
var init_connection = __esm({
|
|
16589
16967
|
"src/cdp/connection.ts"() {
|
|
16590
|
-
|
|
16968
|
+
fs14 = __toESM(require("fs"));
|
|
16591
16969
|
import_node_perf_hooks2 = require("node:perf_hooks");
|
|
16592
16970
|
init_client();
|
|
16593
16971
|
init_detect();
|
|
@@ -17075,6 +17453,7 @@ async function dispatchResolvedClick(client, resolved, opts) {
|
|
|
17075
17453
|
}
|
|
17076
17454
|
if (hitTest.backendNodeId !== backendNodeId2 || opts.includeHitTestReceiver) hitTestReceiverBackendNodeId = hitTest.backendNodeId;
|
|
17077
17455
|
}
|
|
17456
|
+
await presentFrameBeforeInput(client);
|
|
17078
17457
|
const pressParams = { type: "mousePressed", x: dispatchX, y: dispatchY, button: "left", clickCount: 1 };
|
|
17079
17458
|
if (opts.mark !== void 0 && client.sendMarked) {
|
|
17080
17459
|
await client.sendMarked("Input.dispatchMouseEvent", pressParams, opts.mark);
|
|
@@ -17091,6 +17470,12 @@ async function dispatchResolvedClick(client, resolved, opts) {
|
|
|
17091
17470
|
...hitTestReceiverBackendNodeId === void 0 ? {} : { hitTestReceiverBackendNodeId }
|
|
17092
17471
|
};
|
|
17093
17472
|
}
|
|
17473
|
+
async function presentFrameBeforeInput(client) {
|
|
17474
|
+
await client.send("Page.captureScreenshot", {
|
|
17475
|
+
format: "png",
|
|
17476
|
+
clip: { x: 0, y: 0, width: 1, height: 1, scale: 1 }
|
|
17477
|
+
});
|
|
17478
|
+
}
|
|
17094
17479
|
async function typeText(client, text2) {
|
|
17095
17480
|
await client.send("Input.insertText", { text: text2 });
|
|
17096
17481
|
}
|
|
@@ -228530,22 +228915,22 @@ var init_exec_expression = __esm({
|
|
|
228530
228915
|
// src/vault/paths.ts
|
|
228531
228916
|
function vaultLibsDir() {
|
|
228532
228917
|
const candidates = [
|
|
228533
|
-
|
|
228918
|
+
path18.resolve(__dirname, "..", "vault", "libs"),
|
|
228534
228919
|
// built bin: bin/../vault/libs
|
|
228535
|
-
|
|
228920
|
+
path18.resolve(__dirname, "..", "..", "vault", "libs")
|
|
228536
228921
|
// tsx dev: src/vault/../../vault/libs
|
|
228537
228922
|
];
|
|
228538
228923
|
const hit = candidates.find(
|
|
228539
|
-
(p) =>
|
|
228924
|
+
(p) => fs15.existsSync(path18.join(p, "_runtime", "index.ts"))
|
|
228540
228925
|
);
|
|
228541
228926
|
if (!hit) throw new Error(DEV_ONLY_MSG);
|
|
228542
228927
|
return hit;
|
|
228543
228928
|
}
|
|
228544
228929
|
function vaultRepoRoot() {
|
|
228545
|
-
return
|
|
228930
|
+
return path18.dirname(vaultLibsDir());
|
|
228546
228931
|
}
|
|
228547
228932
|
function listLibs() {
|
|
228548
|
-
return
|
|
228933
|
+
return fs15.readdirSync(vaultLibsDir(), { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("_")).map((e) => e.name).sort();
|
|
228549
228934
|
}
|
|
228550
228935
|
function unknownLibMsg(name) {
|
|
228551
228936
|
return `Unknown lib "${name}". Available: ${listLibs().join(", ")}`;
|
|
@@ -228558,11 +228943,11 @@ async function loadEsbuild() {
|
|
|
228558
228943
|
throw new Error(DEV_ONLY_MSG);
|
|
228559
228944
|
});
|
|
228560
228945
|
}
|
|
228561
|
-
var
|
|
228946
|
+
var fs15, path18, DEV_ONLY_MSG, VALID_LIB_NAME;
|
|
228562
228947
|
var init_paths = __esm({
|
|
228563
228948
|
"src/vault/paths.ts"() {
|
|
228564
|
-
|
|
228565
|
-
|
|
228949
|
+
fs15 = __toESM(require("fs"));
|
|
228950
|
+
path18 = __toESM(require("path"));
|
|
228566
228951
|
DEV_ONLY_MSG = "This is a dev-only feature of capture \u2014 run it from a capture checkout\n(vault/ source + `pnpm install`). Not available in the published package.";
|
|
228567
228952
|
VALID_LIB_NAME = /^[A-Za-z0-9_.-]+$/;
|
|
228568
228953
|
}
|
|
@@ -228589,7 +228974,7 @@ function preflightLibs(imports) {
|
|
|
228589
228974
|
let m;
|
|
228590
228975
|
while ((m = LIB_SPECIFIER_RE.exec(imports)) !== null) {
|
|
228591
228976
|
const name = m[2];
|
|
228592
|
-
if (!isValidLibName(name) || !
|
|
228977
|
+
if (!isValidLibName(name) || !fs16.existsSync(path19.join(libs, name, "index.ts"))) {
|
|
228593
228978
|
throw new Error(unknownLibMsg(name));
|
|
228594
228979
|
}
|
|
228595
228980
|
}
|
|
@@ -228605,7 +228990,7 @@ function buildEntry(code) {
|
|
|
228605
228990
|
}
|
|
228606
228991
|
function vaultResolver() {
|
|
228607
228992
|
const libs = vaultLibsDir();
|
|
228608
|
-
const runtime =
|
|
228993
|
+
const runtime = path19.join(libs, "_runtime", "index.ts");
|
|
228609
228994
|
return {
|
|
228610
228995
|
name: "vault",
|
|
228611
228996
|
setup(build) {
|
|
@@ -228617,8 +229002,8 @@ function vaultResolver() {
|
|
|
228617
229002
|
if (!isValidLibName(name)) {
|
|
228618
229003
|
return { errors: [{ text: unknownLibMsg(name) }] };
|
|
228619
229004
|
}
|
|
228620
|
-
const entry =
|
|
228621
|
-
return
|
|
229005
|
+
const entry = path19.join(libs, name, "index.ts");
|
|
229006
|
+
return fs16.existsSync(entry) ? { path: entry } : { errors: [{ text: unknownLibMsg(name) }] };
|
|
228622
229007
|
});
|
|
228623
229008
|
}
|
|
228624
229009
|
};
|
|
@@ -228687,11 +229072,11 @@ async function bundleExec(code) {
|
|
|
228687
229072
|
}
|
|
228688
229073
|
return applyReturnInsert(result.outputFiles[0].text);
|
|
228689
229074
|
}
|
|
228690
|
-
var
|
|
229075
|
+
var fs16, path19, SENTINEL, IMPORT_STMT_RE, LIB_SPECIFIER_RE;
|
|
228691
229076
|
var init_bundle = __esm({
|
|
228692
229077
|
"src/vault/bundle.ts"() {
|
|
228693
|
-
|
|
228694
|
-
|
|
229078
|
+
fs16 = __toESM(require("fs"));
|
|
229079
|
+
path19 = __toESM(require("path"));
|
|
228695
229080
|
init_paths();
|
|
228696
229081
|
init_exec_expression();
|
|
228697
229082
|
SENTINEL = "__CAPTURE_RESULT";
|
|
@@ -228711,10 +229096,23 @@ function emitExecError(parsed, code, summary, followUp) {
|
|
|
228711
229096
|
function spillWholeResult(payload, artifactDir) {
|
|
228712
229097
|
const name = `exec-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}.json`;
|
|
228713
229098
|
const session = deps3.getActiveSession();
|
|
228714
|
-
const filePath = session ?
|
|
229099
|
+
const filePath = session ? path20.join(session.dir, "page", name) : path20.join(deps3.createOneshotSession("page", artifactDir).artifactsDir, name);
|
|
228715
229100
|
writePrivateFile(filePath, payload);
|
|
228716
229101
|
return filePath;
|
|
228717
229102
|
}
|
|
229103
|
+
function describePageException(details) {
|
|
229104
|
+
const exception = details.exception;
|
|
229105
|
+
if (!exception) return details.text ?? "Unknown error";
|
|
229106
|
+
if (exception.subtype === "error" && exception.description) return exception.description;
|
|
229107
|
+
if (exception.type === "undefined") return "undefined";
|
|
229108
|
+
if ("value" in exception) return JSON.stringify(exception.value);
|
|
229109
|
+
const properties = exception.preview?.properties;
|
|
229110
|
+
if (exception.type === "object" && properties) {
|
|
229111
|
+
const fields = properties.map((p) => `${p.name}: ${p.value ?? "?"}`).join(", ");
|
|
229112
|
+
return `${exception.className ?? "Object"} {${fields}${exception.preview?.overflow ? ", \u2026" : ""}}`;
|
|
229113
|
+
}
|
|
229114
|
+
return exception.description ?? details.text ?? "Unknown error";
|
|
229115
|
+
}
|
|
228718
229116
|
function isRequestTimeout(error4) {
|
|
228719
229117
|
return error4 instanceof Error && /CDP request timeout \(\d+ms\): Runtime\.evaluate|collector-host CDP call "Runtime\.evaluate" failed: CDP request timeout/.test(error4.message);
|
|
228720
229118
|
}
|
|
@@ -228792,7 +229190,7 @@ async function cmdPageExec(parsed, _args) {
|
|
|
228792
229190
|
);
|
|
228793
229191
|
}
|
|
228794
229192
|
try {
|
|
228795
|
-
code =
|
|
229193
|
+
code = fs17.readFileSync(parsed.file, "utf-8");
|
|
228796
229194
|
} catch (err) {
|
|
228797
229195
|
return emitExecError(
|
|
228798
229196
|
parsed,
|
|
@@ -228860,7 +229258,7 @@ async function cmdPageExec(parsed, _args) {
|
|
|
228860
229258
|
);
|
|
228861
229259
|
}
|
|
228862
229260
|
if (evalResult.exceptionDetails) {
|
|
228863
|
-
const description = evalResult.exceptionDetails
|
|
229261
|
+
const description = describePageException(evalResult.exceptionDetails);
|
|
228864
229262
|
return emitExecError(
|
|
228865
229263
|
parsed,
|
|
228866
229264
|
"exec_exception",
|
|
@@ -228890,11 +229288,11 @@ async function cmdPageExec(parsed, _args) {
|
|
|
228890
229288
|
{ json: parsed.json }
|
|
228891
229289
|
);
|
|
228892
229290
|
}
|
|
228893
|
-
var
|
|
229291
|
+
var fs17, path20, GENEROUS_RESULT_CAP, DEFAULT_SETTLE_MS2, DEFAULT_EVALUATION_TIMEOUT_MS, TERMINATE_TIMEOUT_MS, USAGE5, deps3, ExecDeadlineError;
|
|
228894
229292
|
var init_exec = __esm({
|
|
228895
229293
|
"src/cdp/commands/page/exec.ts"() {
|
|
228896
|
-
|
|
228897
|
-
|
|
229294
|
+
fs17 = __toESM(require("fs"));
|
|
229295
|
+
path20 = __toESM(require("path"));
|
|
228898
229296
|
init_connection();
|
|
228899
229297
|
init_errors();
|
|
228900
229298
|
init_exec_expression();
|
|
@@ -229006,7 +229404,7 @@ async function resolveOutPath(parsed) {
|
|
|
229006
229404
|
if (parsed.out) return parsed.out;
|
|
229007
229405
|
const sessionPath = await deps4.nextStepPath("shot", "manual");
|
|
229008
229406
|
if (sessionPath) return sessionPath;
|
|
229009
|
-
return
|
|
229407
|
+
return path21.join(deps4.createOneshotSession("page", parsed.artifactDir).artifactsDir, "shot.png");
|
|
229010
229408
|
}
|
|
229011
229409
|
function round6(value) {
|
|
229012
229410
|
return Math.round(value * 1e6) / 1e6;
|
|
@@ -229244,10 +229642,10 @@ async function cmdPageShot(parsed, _args) {
|
|
|
229244
229642
|
}
|
|
229245
229643
|
emitResult(buildScreenshotResult({ ...result, emulation: parsed.fullPage ? "full-page" : viewport2 ? "viewport" : "none", viewport: viewport2, colorScheme }), { json: parsed.json });
|
|
229246
229644
|
}
|
|
229247
|
-
var
|
|
229645
|
+
var path21, USAGE6, deps4, PNG_SIGNATURE, LEGIBILITY_SCALE_THRESHOLD;
|
|
229248
229646
|
var init_shot = __esm({
|
|
229249
229647
|
"src/cdp/commands/page/shot.ts"() {
|
|
229250
|
-
|
|
229648
|
+
path21 = __toESM(require("path"));
|
|
229251
229649
|
init_connection();
|
|
229252
229650
|
init_screenshot();
|
|
229253
229651
|
init_viewport();
|
|
@@ -230199,9 +230597,9 @@ async function cmdTabClose(parsed, _args) {
|
|
|
230199
230597
|
console.log(USAGE13);
|
|
230200
230598
|
return;
|
|
230201
230599
|
}
|
|
230202
|
-
const target = parsed.positional[0];
|
|
230600
|
+
const target = parsed.positional[0] ?? (parsed.targetSource === "flag" ? parsed.target : void 0);
|
|
230203
230601
|
if (!target) {
|
|
230204
|
-
throw invalidInput("received: no target; expected: capture tab close <target> [--port <port>].", "missing_argument");
|
|
230602
|
+
throw invalidInput("received: no target; expected: capture tab close <target> (or --target <id>) [--port <port>].", "missing_argument");
|
|
230205
230603
|
}
|
|
230206
230604
|
if (target.length < 8) {
|
|
230207
230605
|
throw invalidInput(`received: target ${target}; expected: a full target id or an unambiguous prefix of at least 8 characters.`, "target_prefix_too_short");
|
|
@@ -230267,6 +230665,7 @@ var init_close = __esm({
|
|
|
230267
230665
|
|
|
230268
230666
|
input:
|
|
230269
230667
|
<target> required \u2014 full tab target id or an unambiguous 8-character prefix
|
|
230668
|
+
--target <id> same as <target>; only an explicit flag counts, never the session's tab or CDP_TARGET
|
|
230270
230669
|
--port <port> CDP endpoint (default: the auto-discovered preferred endpoint)
|
|
230271
230670
|
|
|
230272
230671
|
output: <tab-closed port=\u2026 target=\u2026> \u2014 the closed tab's full target id and last observed URL.
|
|
@@ -230471,7 +230870,7 @@ async function cmdTabNetwork(parsed, _args) {
|
|
|
230471
230870
|
`session ${session.sessionId} has no target to emulate on; open one with \`capture session start --hold --url <url>\` or \`capture tab reset <url>\`.`
|
|
230472
230871
|
);
|
|
230473
230872
|
}
|
|
230474
|
-
if (!session.bridgeSocket || !
|
|
230873
|
+
if (!session.bridgeSocket || !fs18.existsSync(session.bridgeSocket)) {
|
|
230475
230874
|
throw captureError(
|
|
230476
230875
|
"precondition",
|
|
230477
230876
|
"no_held_bridge",
|
|
@@ -230535,10 +230934,10 @@ async function cmdTabNetwork(parsed, _args) {
|
|
|
230535
230934
|
}
|
|
230536
230935
|
emitResult(buildNetworkResult(mode, targetId), { json: parsed.json });
|
|
230537
230936
|
}
|
|
230538
|
-
var
|
|
230937
|
+
var fs18, USAGE15;
|
|
230539
230938
|
var init_network = __esm({
|
|
230540
230939
|
"src/cdp/commands/tab/network.ts"() {
|
|
230541
|
-
|
|
230940
|
+
fs18 = __toESM(require("node:fs"));
|
|
230542
230941
|
init_errors();
|
|
230543
230942
|
init_session_context();
|
|
230544
230943
|
init_coordinator();
|
|
@@ -230649,12 +231048,12 @@ var init_lifecycle2 = __esm({
|
|
|
230649
231048
|
|
|
230650
231049
|
// src/cdp/commands/tab/mock/start.ts
|
|
230651
231050
|
function stagedRulesPath() {
|
|
230652
|
-
return
|
|
231051
|
+
return path22.join(CAPTURE_ROOT, ".mock-inputs", `rules-${crypto8.randomBytes(12).toString("hex")}.json`);
|
|
230653
231052
|
}
|
|
230654
231053
|
function sourceFor(pathname) {
|
|
230655
231054
|
let source;
|
|
230656
231055
|
try {
|
|
230657
|
-
source =
|
|
231056
|
+
source = fs19.readFileSync(pathname);
|
|
230658
231057
|
} catch (error4) {
|
|
230659
231058
|
throw captureError("artifact", "mock_rules_unreadable", `could not read mock rules at ${pathname}: ${error4 instanceof Error ? error4.message : String(error4)}`);
|
|
230660
231059
|
}
|
|
@@ -230698,12 +231097,12 @@ async function cmdTabMockStart(parsed) {
|
|
|
230698
231097
|
}
|
|
230699
231098
|
}
|
|
230700
231099
|
}
|
|
230701
|
-
var crypto8,
|
|
231100
|
+
var crypto8, fs19, path22, HELP;
|
|
230702
231101
|
var init_start = __esm({
|
|
230703
231102
|
"src/cdp/commands/tab/mock/start.ts"() {
|
|
230704
231103
|
crypto8 = __toESM(require("node:crypto"));
|
|
230705
|
-
|
|
230706
|
-
|
|
231104
|
+
fs19 = __toESM(require("node:fs"));
|
|
231105
|
+
path22 = __toESM(require("node:path"));
|
|
230707
231106
|
init_errors();
|
|
230708
231107
|
init_artifacts();
|
|
230709
231108
|
init_render();
|
|
@@ -230864,13 +231263,13 @@ function isAgentVisible(doc) {
|
|
|
230864
231263
|
return AGENT_VISIBLE_VISIBILITIES.has(doc.visibility);
|
|
230865
231264
|
}
|
|
230866
231265
|
function cacheDir() {
|
|
230867
|
-
return
|
|
231266
|
+
return path23.join(vaultRepoRoot(), ".cache", "docs");
|
|
230868
231267
|
}
|
|
230869
231268
|
function schemasPathFor(svc) {
|
|
230870
|
-
return
|
|
231269
|
+
return path23.join(vaultLibsDir(), svc, "schemas.ts");
|
|
230871
231270
|
}
|
|
230872
231271
|
function srcSha(svc) {
|
|
230873
|
-
return (0, import_crypto.createHash)("sha256").update(
|
|
231272
|
+
return (0, import_crypto.createHash)("sha256").update(fs20.readFileSync(schemasPathFor(svc), "utf8")).digest("hex");
|
|
230874
231273
|
}
|
|
230875
231274
|
function toJsonSchema(zodSchema) {
|
|
230876
231275
|
const s = zodSchema;
|
|
@@ -230923,14 +231322,14 @@ async function buildDoc(svc) {
|
|
|
230923
231322
|
return doc;
|
|
230924
231323
|
}
|
|
230925
231324
|
async function getDoc(name) {
|
|
230926
|
-
if (!isValidLibName(name) || !
|
|
231325
|
+
if (!isValidLibName(name) || !fs20.existsSync(schemasPathFor(name))) {
|
|
230927
231326
|
throw new Error(unknownLibMsg(name));
|
|
230928
231327
|
}
|
|
230929
231328
|
const sha = srcSha(name);
|
|
230930
|
-
const cacheFile =
|
|
230931
|
-
if (
|
|
231329
|
+
const cacheFile = path23.join(cacheDir(), `${name}.json`);
|
|
231330
|
+
if (fs20.existsSync(cacheFile)) {
|
|
230932
231331
|
try {
|
|
230933
|
-
const cached = JSON.parse(
|
|
231332
|
+
const cached = JSON.parse(fs20.readFileSync(cacheFile, "utf8"));
|
|
230934
231333
|
if (cached._srcSha === sha) {
|
|
230935
231334
|
delete cached._srcSha;
|
|
230936
231335
|
return cached;
|
|
@@ -230939,8 +231338,8 @@ async function getDoc(name) {
|
|
|
230939
231338
|
}
|
|
230940
231339
|
}
|
|
230941
231340
|
const doc = await buildDoc(name);
|
|
230942
|
-
|
|
230943
|
-
|
|
231341
|
+
fs20.mkdirSync(cacheDir(), { recursive: true });
|
|
231342
|
+
fs20.writeFileSync(
|
|
230944
231343
|
cacheFile,
|
|
230945
231344
|
JSON.stringify({ ...doc, _srcSha: sha }, null, 2)
|
|
230946
231345
|
);
|
|
@@ -230962,11 +231361,11 @@ async function listDocs() {
|
|
|
230962
231361
|
}
|
|
230963
231362
|
return out;
|
|
230964
231363
|
}
|
|
230965
|
-
var
|
|
231364
|
+
var fs20, path23, import_crypto, AGENT_VISIBLE_VISIBILITIES, cjsRequire;
|
|
230966
231365
|
var init_docs = __esm({
|
|
230967
231366
|
"src/vault/docs.ts"() {
|
|
230968
|
-
|
|
230969
|
-
|
|
231367
|
+
fs20 = __toESM(require("fs"));
|
|
231368
|
+
path23 = __toESM(require("path"));
|
|
230970
231369
|
import_crypto = require("crypto");
|
|
230971
231370
|
init_paths();
|
|
230972
231371
|
AGENT_VISIBLE_VISIBILITIES = /* @__PURE__ */ new Set(["public", "chat"]);
|
|
@@ -231274,10 +231673,10 @@ async function cmdLib(parsed, _args) {
|
|
|
231274
231673
|
throw e;
|
|
231275
231674
|
}
|
|
231276
231675
|
}
|
|
231277
|
-
var
|
|
231676
|
+
var path24, COMMAND_BLOCK4, LIB_USAGE, LEAF_USAGE, FUNCTION_NAME_EXACT, FUNCTION_NAME_PREFIX, FUNCTION_NAME_SUBSTRING, SERVICE_NAME_MATCH, FUNCTION_DESC_SUBSTRING, SERVICE_DESC_SUBSTRING, svcName, cap, srcPathFor;
|
|
231278
231677
|
var init_lib = __esm({
|
|
231279
231678
|
"src/cdp/commands/lib.ts"() {
|
|
231280
|
-
|
|
231679
|
+
path24 = __toESM(require("path"));
|
|
231281
231680
|
init_errors();
|
|
231282
231681
|
init_render();
|
|
231283
231682
|
init_paths();
|
|
@@ -231323,7 +231722,7 @@ Effects: local reads only; no CDP connection. Dev checkout required.`
|
|
|
231323
231722
|
SERVICE_DESC_SUBSTRING = 10;
|
|
231324
231723
|
svcName = (doc) => doc.library.replace(/^@vallum\//, "");
|
|
231325
231724
|
cap = (value, maxLength) => value.length > maxLength ? `${value.slice(0, maxLength - 1)}\u2026` : value;
|
|
231326
|
-
srcPathFor = (name) =>
|
|
231725
|
+
srcPathFor = (name) => path24.join(vaultLibsDir(), name, "index.ts");
|
|
231327
231726
|
}
|
|
231328
231727
|
});
|
|
231329
231728
|
|
|
@@ -231407,7 +231806,7 @@ async function runBrowserScope(method, params, parsed, timeoutMs, deps23 = DEFAU
|
|
|
231407
231806
|
const flagTarget = parsed.targetSource === "flag" ? parsed.target : void 0;
|
|
231408
231807
|
const session = getActiveSession();
|
|
231409
231808
|
const bridgeSocket = session?.bridgeSocket;
|
|
231410
|
-
const heldBridgeActive = Boolean(bridgeSocket &&
|
|
231809
|
+
const heldBridgeActive = Boolean(bridgeSocket && fs21.existsSync(bridgeSocket));
|
|
231411
231810
|
if (parsed.portSource !== "flag" && bridgeSocket && heldBridgeActive) {
|
|
231412
231811
|
let resp;
|
|
231413
231812
|
try {
|
|
@@ -231535,10 +231934,10 @@ function waitForEventOnce(client, eventName, timeoutMs) {
|
|
|
231535
231934
|
});
|
|
231536
231935
|
});
|
|
231537
231936
|
}
|
|
231538
|
-
var
|
|
231937
|
+
var fs21, DEFAULT_TIMEOUT_MS, GENEROUS_RESULT_CAP2, COMMAND_BLOCK5, HELP3, DEFAULT_BROWSER_DEPS, TAB_SCOPE_RECOVERY;
|
|
231539
231938
|
var init_cdp = __esm({
|
|
231540
231939
|
"src/cdp/commands/cdp.ts"() {
|
|
231541
|
-
|
|
231940
|
+
fs21 = __toESM(require("fs"));
|
|
231542
231941
|
init_errors();
|
|
231543
231942
|
init_session_context();
|
|
231544
231943
|
init_connection();
|
|
@@ -231578,12 +231977,12 @@ Effects:
|
|
|
231578
231977
|
});
|
|
231579
231978
|
|
|
231580
231979
|
// src/cdp/host/core.ts
|
|
231581
|
-
var crypto9,
|
|
231980
|
+
var crypto9, fs22, path25, import_node_perf_hooks3, CollectorHost;
|
|
231582
231981
|
var init_core = __esm({
|
|
231583
231982
|
"src/cdp/host/core.ts"() {
|
|
231584
231983
|
crypto9 = __toESM(require("node:crypto"));
|
|
231585
|
-
|
|
231586
|
-
|
|
231984
|
+
fs22 = __toESM(require("node:fs"));
|
|
231985
|
+
path25 = __toESM(require("node:path"));
|
|
231587
231986
|
import_node_perf_hooks3 = require("node:perf_hooks");
|
|
231588
231987
|
init_artifacts();
|
|
231589
231988
|
init_artifacts();
|
|
@@ -231657,7 +232056,7 @@ var init_core = __esm({
|
|
|
231657
232056
|
this.refuseClaims(collector.claims);
|
|
231658
232057
|
const id = `${entry.idPrefix}-${crypto9.randomBytes(5).toString("hex")}`;
|
|
231659
232058
|
this.starting.set(id, collector.claims);
|
|
231660
|
-
const dir =
|
|
232059
|
+
const dir = path25.join(this.sessionDir, ...entry.idSegments, id);
|
|
231661
232060
|
try {
|
|
231662
232061
|
ensurePrivateDir(dir);
|
|
231663
232062
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -231669,13 +232068,13 @@ var init_core = __esm({
|
|
|
231669
232068
|
id,
|
|
231670
232069
|
targetId: this.identity.targetId,
|
|
231671
232070
|
config: config3,
|
|
231672
|
-
appendRecord: (file, record5) => appendNdjsonPrivate(
|
|
231673
|
-
openChunkFile: (file) => openPrivateChunkWriter(
|
|
232071
|
+
appendRecord: (file, record5) => appendNdjsonPrivate(path25.join(dir, file), record5),
|
|
232072
|
+
openChunkFile: (file) => openPrivateChunkWriter(path25.join(dir, file)),
|
|
231674
232073
|
noteLoss: (reason, detail) => {
|
|
231675
232074
|
live.losses.push({ reason, detail });
|
|
231676
232075
|
}
|
|
231677
232076
|
};
|
|
231678
|
-
writeJsonPrivate(
|
|
232077
|
+
writeJsonPrivate(path25.join(dir, "collecting.json"), { kind, id, startedAt, hostPid: this.identity.pid, hostBirth: this.identity.birth });
|
|
231679
232078
|
await collector.start(context);
|
|
231680
232079
|
this.starting.delete(id);
|
|
231681
232080
|
this.live.set(id, live);
|
|
@@ -231697,10 +232096,10 @@ var init_core = __esm({
|
|
|
231697
232096
|
finalizedFiles(dir) {
|
|
231698
232097
|
const files = [];
|
|
231699
232098
|
const walk2 = (relative2) => {
|
|
231700
|
-
for (const entry of
|
|
231701
|
-
const name =
|
|
232099
|
+
for (const entry of fs22.readdirSync(path25.join(dir, relative2), { withFileTypes: true })) {
|
|
232100
|
+
const name = path25.join(relative2, entry.name);
|
|
231702
232101
|
if (entry.isDirectory()) walk2(name);
|
|
231703
|
-
else if (entry.isFile()) files.push({ name, bytes: readPrivateFile(
|
|
232102
|
+
else if (entry.isFile()) files.push({ name, bytes: readPrivateFile(path25.join(dir, name)).length });
|
|
231704
232103
|
}
|
|
231705
232104
|
};
|
|
231706
232105
|
walk2("");
|
|
@@ -231712,12 +232111,12 @@ var init_core = __esm({
|
|
|
231712
232111
|
}
|
|
231713
232112
|
async drain(live, cause) {
|
|
231714
232113
|
const outcome = await live.collector.drain(cause);
|
|
231715
|
-
unlinkPrivateFile(
|
|
232114
|
+
unlinkPrivateFile(path25.join(live.row.dir, "collecting.json"));
|
|
231716
232115
|
const files = this.finalizedFiles(live.row.dir);
|
|
231717
232116
|
const loss = live.losses[0];
|
|
231718
232117
|
const completion = loss || !cause.clientUsable ? "partial" : "complete";
|
|
231719
232118
|
const summary = outcome.summary && typeof outcome.summary === "object" && !Array.isArray(outcome.summary) ? outcome.summary : { value: outcome.summary };
|
|
231720
|
-
writeJsonPrivate(
|
|
232119
|
+
writeJsonPrivate(path25.join(live.row.dir, "meta.json"), {
|
|
231721
232120
|
id: live.row.id,
|
|
231722
232121
|
kind: live.row.kind,
|
|
231723
232122
|
completion,
|
|
@@ -231818,7 +232217,7 @@ async function runCollectorHost(options) {
|
|
|
231818
232217
|
if (session.targetId !== options.targetId) throw new Error("collector host target does not match session state");
|
|
231819
232218
|
await applyActiveSessionNetworkConditions(client, session, options.targetId);
|
|
231820
232219
|
let server2;
|
|
231821
|
-
const handlePath =
|
|
232220
|
+
const handlePath = path26.join(options.sessionDir, ".collector-host.json");
|
|
231822
232221
|
const publish = (snapshot) => writeJsonPrivate(handlePath, {
|
|
231823
232222
|
pid: process.pid,
|
|
231824
232223
|
birth: birth.identity,
|
|
@@ -231915,11 +232314,11 @@ async function runCollectorHost(options) {
|
|
|
231915
232314
|
cleanup();
|
|
231916
232315
|
}, client);
|
|
231917
232316
|
}
|
|
231918
|
-
var crypto10,
|
|
232317
|
+
var crypto10, path26;
|
|
231919
232318
|
var init_server2 = __esm({
|
|
231920
232319
|
"src/cdp/host/server.ts"() {
|
|
231921
232320
|
crypto10 = __toESM(require("node:crypto"));
|
|
231922
|
-
|
|
232321
|
+
path26 = __toESM(require("node:path"));
|
|
231923
232322
|
init_client();
|
|
231924
232323
|
init_targets();
|
|
231925
232324
|
init_server();
|
|
@@ -238167,8 +238566,8 @@ function round32(value) {
|
|
|
238167
238566
|
return Math.round(value * 1e3) / 1e3;
|
|
238168
238567
|
}
|
|
238169
238568
|
async function captureStateRaster(ctx, client, state, id, borderRect2) {
|
|
238170
|
-
const baselinePath =
|
|
238171
|
-
if (!
|
|
238569
|
+
const baselinePath = path27.join(ctx.dir, "screenshot.png");
|
|
238570
|
+
if (!fs23.existsSync(baselinePath)) return void 0;
|
|
238172
238571
|
const response = await client.send("Page.captureScreenshot", { format: "png" });
|
|
238173
238572
|
const statePng = Buffer.from(response.data, "base64");
|
|
238174
238573
|
const imageName = `states/${sanitizeToken(state) || "state"}-${id}.png`;
|
|
@@ -238182,7 +238581,7 @@ async function captureStateRaster(ctx, client, state, id, borderRect2) {
|
|
|
238182
238581
|
const scaleY = available ? stateImage.height / h : 1;
|
|
238183
238582
|
const paddingCssPx = ctx.stateDiffPaddingCssPx ?? DEFAULT_STATE_DIFF_PADDING_CSS_PX;
|
|
238184
238583
|
const raster = { screenshot: imageName, viewportScale: { available, innerWidth: available ? w : 0, innerHeight: available ? h : 0, scaleX: round32(scaleX), scaleY: round32(scaleY), ...available ? {} : { unavailableReason: "viewport-read-unavailable" } }, diffCrop: { paddingCssPx, borderRect: borderRect2 } };
|
|
238185
|
-
const baseline = import_pngjs3.PNG.sync.read(
|
|
238584
|
+
const baseline = import_pngjs3.PNG.sync.read(fs23.readFileSync(baselinePath));
|
|
238186
238585
|
if (baseline.width !== stateImage.width || baseline.height !== stateImage.height) return { ...raster, diffUnavailableReason: "dimension-mismatch" };
|
|
238187
238586
|
const x0 = Math.max(0, Math.floor((borderRect2.x - paddingCssPx) * scaleX));
|
|
238188
238587
|
const y0 = Math.max(0, Math.floor((borderRect2.y - paddingCssPx) * scaleY));
|
|
@@ -238405,11 +238804,11 @@ async function captureOneElement(ctx, client, selector, index, nodeId, identity3
|
|
|
238405
238804
|
...raster ? { raster } : {}
|
|
238406
238805
|
};
|
|
238407
238806
|
}
|
|
238408
|
-
var
|
|
238807
|
+
var fs23, path27, import_pngjs3, MAX_SELECTOR_MATCHES, MAX_AUTO_ELEMENTS, MAX_STRING_LEN, MAX_AFFECTED_ELEMENTS, DEFAULT_STATE_DIFF_PADDING_CSS_PX, STATE_CAPTURE_SETTLE_FRAMES, CONCRETE_STATES, CONCRETE_STATE_SET, INTERACTIVE_SELECTOR, ELIGIBLE_SELECTORS, PSEUDO_CLASS_MAP, STYLE_PROPS, collectStates;
|
|
238409
238808
|
var init_states = __esm({
|
|
238410
238809
|
"src/cdp/measure/collectors/states.ts"() {
|
|
238411
|
-
|
|
238412
|
-
|
|
238810
|
+
fs23 = __toESM(require("node:fs"));
|
|
238811
|
+
path27 = __toESM(require("node:path"));
|
|
238413
238812
|
import_pngjs3 = __toESM(require_png());
|
|
238414
238813
|
init_pixelmatch();
|
|
238415
238814
|
init_domains();
|
|
@@ -238835,9 +239234,9 @@ document.querySelectorAll('img, video, canvas, svg, iframe').length;`;
|
|
|
238835
239234
|
|
|
238836
239235
|
// src/cdp/measure/snapshot.ts
|
|
238837
239236
|
function resolveScopedArtifactPath(dir, filename) {
|
|
238838
|
-
const target =
|
|
238839
|
-
const rel =
|
|
238840
|
-
const escapesDir = rel === ".." || rel.startsWith(`..${
|
|
239237
|
+
const target = path28.resolve(dir, filename);
|
|
239238
|
+
const rel = path28.relative(dir, target);
|
|
239239
|
+
const escapesDir = rel === ".." || rel.startsWith(`..${path28.sep}`) || path28.isAbsolute(rel);
|
|
238841
239240
|
if (escapesDir) {
|
|
238842
239241
|
throw new Error(`Refusing to write snapshot artifact "${filename}" outside its snap dir ${dir}`);
|
|
238843
239242
|
}
|
|
@@ -238934,7 +239333,7 @@ function boundedClient(client, phase, partialPath, onTimeout, requestTimeoutCapM
|
|
|
238934
239333
|
async function captureSnapshotSubstrate(options) {
|
|
238935
239334
|
const client = options.target.client;
|
|
238936
239335
|
const dir = ensurePrivateDir(options.path);
|
|
238937
|
-
const snapId = options.snapId ??
|
|
239336
|
+
const snapId = options.snapId ?? path28.basename(dir);
|
|
238938
239337
|
const settleTimeoutMs = options.settleTimeout ?? DEFAULT_SETTLE_TIMEOUT_MS;
|
|
238939
239338
|
const quietThresholdMs = options.quietThresholdMs ?? DEFAULT_QUIET_THRESHOLD_MS;
|
|
238940
239339
|
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
@@ -238996,10 +239395,10 @@ async function captureSnapshotSubstrate(options) {
|
|
|
238996
239395
|
const animationEvidence = await collectAnimationEvidence(phaseClient("settle-evidence"));
|
|
238997
239396
|
const grouped = groupChurnEvidence(churnEvidenceRaw, animationEvidence, settleResult.elapsedMs, settleTimeoutMs);
|
|
238998
239397
|
unstableRegions = grouped.unstableRegions;
|
|
238999
|
-
writeJsonPrivate(
|
|
239398
|
+
writeJsonPrivate(path28.join(dir, "churn.json"), grouped.report);
|
|
239000
239399
|
artifacts.push("churn.json");
|
|
239001
239400
|
if (!captured) {
|
|
239002
|
-
writeJsonPrivate(
|
|
239401
|
+
writeJsonPrivate(path28.join(dir, "animation.json"), animationEvidence);
|
|
239003
239402
|
artifacts.push("animation.json");
|
|
239004
239403
|
}
|
|
239005
239404
|
}
|
|
@@ -239051,7 +239450,7 @@ async function captureSnapshotSubstrate(options) {
|
|
|
239051
239450
|
};
|
|
239052
239451
|
for (const collector of baseline) collectorOutcomes.push(await runCollector(collector));
|
|
239053
239452
|
const screenshotResponse = await phaseClient("baseline-screenshot").send("Page.captureScreenshot", { format: "png" });
|
|
239054
|
-
writeBinaryPrivate(
|
|
239453
|
+
writeBinaryPrivate(path28.join(dir, "screenshot.png"), Buffer.from(screenshotResponse.data, "base64"));
|
|
239055
239454
|
artifacts.push("screenshot.png");
|
|
239056
239455
|
let domHtmlValue;
|
|
239057
239456
|
let domHtmlUnavailableReason;
|
|
@@ -239071,7 +239470,7 @@ async function captureSnapshotSubstrate(options) {
|
|
|
239071
239470
|
if (domHtmlValue === void 0) {
|
|
239072
239471
|
domHtmlFact = { available: false, unavailableReason: domHtmlUnavailableReason };
|
|
239073
239472
|
} else {
|
|
239074
|
-
writePrivateFile(
|
|
239473
|
+
writePrivateFile(path28.join(dir, "dom.html"), domHtmlValue);
|
|
239075
239474
|
artifacts.push("dom.html");
|
|
239076
239475
|
domHtmlFact = { available: true };
|
|
239077
239476
|
}
|
|
@@ -239118,7 +239517,7 @@ async function captureSnapshotSubstrate(options) {
|
|
|
239118
239517
|
...domHtmlFact ? { domHtml: domHtmlFact } : {},
|
|
239119
239518
|
...captured ? { collectors: collectorOutcomes } : {}
|
|
239120
239519
|
};
|
|
239121
|
-
writeJsonPrivate(
|
|
239520
|
+
writeJsonPrivate(path28.join(dir, "meta.json"), meta);
|
|
239122
239521
|
artifacts.push("meta.json");
|
|
239123
239522
|
return {
|
|
239124
239523
|
id: snapId,
|
|
@@ -239137,7 +239536,7 @@ async function captureSnapshotSubstrate(options) {
|
|
|
239137
239536
|
} catch (error4) {
|
|
239138
239537
|
if (error4 instanceof SnapshotCaptureTimeout) {
|
|
239139
239538
|
try {
|
|
239140
|
-
writeJsonPrivate(
|
|
239539
|
+
writeJsonPrivate(path28.join(dir, "capture-timeout.json"), {
|
|
239141
239540
|
schemaVersion: 1,
|
|
239142
239541
|
id: snapId,
|
|
239143
239542
|
status: "timeout",
|
|
@@ -239157,10 +239556,10 @@ async function captureSnapshotSubstrate(options) {
|
|
|
239157
239556
|
await restoreAnimationsOnce();
|
|
239158
239557
|
}
|
|
239159
239558
|
}
|
|
239160
|
-
var
|
|
239559
|
+
var path28, COLLECTORS, COLLECTOR_NAMES, SNAPSHOT_REQUEST_TIMEOUT_MS, SCROLL_COLLECTOR_REQUEST_TIMEOUT_MS, SnapshotCaptureTimeout;
|
|
239161
239560
|
var init_snapshot = __esm({
|
|
239162
239561
|
"src/cdp/measure/snapshot.ts"() {
|
|
239163
|
-
|
|
239562
|
+
path28 = __toESM(require("path"));
|
|
239164
239563
|
init_artifacts();
|
|
239165
239564
|
init_domains();
|
|
239166
239565
|
init_settle();
|
|
@@ -239212,347 +239611,6 @@ var init_snapshot = __esm({
|
|
|
239212
239611
|
}
|
|
239213
239612
|
});
|
|
239214
239613
|
|
|
239215
|
-
// src/output/artifact.ts
|
|
239216
|
-
function isUrlRef(ref) {
|
|
239217
|
-
return /^[a-zA-Z][a-zA-Z0-9+.-]*:\/\//.test(ref);
|
|
239218
|
-
}
|
|
239219
|
-
function stripTrailingSep(p) {
|
|
239220
|
-
return p.length > 1 && (p.endsWith("/") || p.endsWith(path28.sep)) ? p.slice(0, -1) : p;
|
|
239221
|
-
}
|
|
239222
|
-
function resolveRefFromPath(ref, config3) {
|
|
239223
|
-
const resolved = assertUnderCaptureRoot(stripTrailingSep(ref));
|
|
239224
|
-
const metaPath = path28.join(resolved, "meta.json");
|
|
239225
|
-
if (!fs23.existsSync(metaPath)) {
|
|
239226
|
-
throw new ArtifactResolutionError(
|
|
239227
|
-
ref,
|
|
239228
|
-
[resolved],
|
|
239229
|
-
`no ${config3.label} found at this path (missing meta.json)`,
|
|
239230
|
-
config3.creatingCommand
|
|
239231
|
-
);
|
|
239232
|
-
}
|
|
239233
|
-
return { kind: config3.kind, id: path28.basename(resolved), dir: resolved };
|
|
239234
|
-
}
|
|
239235
|
-
function resolveRefFromId(ref, config3) {
|
|
239236
|
-
const active = getActiveSession();
|
|
239237
|
-
if (!active) {
|
|
239238
|
-
throw new ArtifactResolutionError(
|
|
239239
|
-
ref,
|
|
239240
|
-
[],
|
|
239241
|
-
`no active capture session \u2014 a bare id resolves against the active session's ${config3.idSegments.join("/")} directory`,
|
|
239242
|
-
`capture session start (then re-run), or pass the absolute ${config3.label} path printed by ${config3.creatingCommand}`
|
|
239243
|
-
);
|
|
239244
|
-
}
|
|
239245
|
-
const dir = path28.join(active.dir, ...config3.idSegments, ref);
|
|
239246
|
-
const resolved = assertUnderCaptureRoot(dir);
|
|
239247
|
-
const metaPath = path28.join(resolved, "meta.json");
|
|
239248
|
-
if (!fs23.existsSync(metaPath)) {
|
|
239249
|
-
throw new ArtifactResolutionError(
|
|
239250
|
-
ref,
|
|
239251
|
-
[resolved],
|
|
239252
|
-
`no ${config3.label} named ${JSON.stringify(ref)} found in the active session (${active.sessionId})`,
|
|
239253
|
-
config3.creatingCommand
|
|
239254
|
-
);
|
|
239255
|
-
}
|
|
239256
|
-
return { kind: config3.kind, id: ref, dir: resolved };
|
|
239257
|
-
}
|
|
239258
|
-
function rejectRelativePath(ref) {
|
|
239259
|
-
if (!path28.isAbsolute(ref) && (ref.includes("/") || ref.includes(path28.sep))) {
|
|
239260
|
-
throw new ArtifactResolutionError(
|
|
239261
|
-
ref,
|
|
239262
|
-
[],
|
|
239263
|
-
"relative paths are not accepted \u2014 pass an absolute artifact path (as printed by the capturing command) or a bare id"
|
|
239264
|
-
);
|
|
239265
|
-
}
|
|
239266
|
-
}
|
|
239267
|
-
async function resolveSnapRef(ref, options = {}) {
|
|
239268
|
-
if (isUrlRef(ref)) {
|
|
239269
|
-
if (!options.onUrl) {
|
|
239270
|
-
throw new ArtifactResolutionError(ref, [], "this command does not accept a URL target \u2014 pass a snapshot id or path instead");
|
|
239271
|
-
}
|
|
239272
|
-
const result = await options.onUrl(ref);
|
|
239273
|
-
return { kind: "snap", id: result.id, dir: assertUnderCaptureRoot(result.dir) };
|
|
239274
|
-
}
|
|
239275
|
-
if (path28.isAbsolute(ref)) return resolveRefFromPath(ref, SNAP_CONFIG);
|
|
239276
|
-
rejectRelativePath(ref);
|
|
239277
|
-
return resolveRefFromId(ref, SNAP_CONFIG);
|
|
239278
|
-
}
|
|
239279
|
-
function resolveRecRef(ref) {
|
|
239280
|
-
if (isUrlRef(ref)) {
|
|
239281
|
-
throw new ArtifactResolutionError(
|
|
239282
|
-
ref,
|
|
239283
|
-
[],
|
|
239284
|
-
"a recording ref cannot be a URL \u2014 record one first with `capture motion rec <url> --do <action>` or `--start`/`--stop`"
|
|
239285
|
-
);
|
|
239286
|
-
}
|
|
239287
|
-
if (path28.isAbsolute(ref)) return resolveRefFromPath(ref, REC_CONFIG);
|
|
239288
|
-
rejectRelativePath(ref);
|
|
239289
|
-
return resolveRefFromId(ref, REC_CONFIG);
|
|
239290
|
-
}
|
|
239291
|
-
function resolveTraceRef(ref) {
|
|
239292
|
-
if (isUrlRef(ref)) {
|
|
239293
|
-
throw new ArtifactResolutionError(ref, [], "a trace ref cannot be a URL \u2014 record one first with `capture perf trace <url>` or `--start`/`--stop`");
|
|
239294
|
-
}
|
|
239295
|
-
const resolved = path28.isAbsolute(ref) ? resolveRefFromPath(ref, TRACE_CONFIG) : (rejectRelativePath(ref), resolveRefFromId(ref, TRACE_CONFIG));
|
|
239296
|
-
let meta;
|
|
239297
|
-
try {
|
|
239298
|
-
meta = JSON.parse(readPrivateFile(path28.join(resolved.dir, "meta.json")).toString("utf8"));
|
|
239299
|
-
} catch (error4) {
|
|
239300
|
-
throw new ArtifactResolutionError(ref, [path28.join(resolved.dir, "meta.json")], `could not read trace metadata: ${error4 instanceof Error ? error4.message : String(error4)}`, TRACE_CONFIG.creatingCommand);
|
|
239301
|
-
}
|
|
239302
|
-
const completion = meta.completion;
|
|
239303
|
-
if (completion !== "complete" && completion !== "partial" && completion !== "orphaned") {
|
|
239304
|
-
throw new ArtifactResolutionError(ref, [path28.join(resolved.dir, "meta.json")], "trace metadata has no valid completion state", TRACE_CONFIG.creatingCommand);
|
|
239305
|
-
}
|
|
239306
|
-
const inventory = meta.files;
|
|
239307
|
-
const inventoryMalformed = !Array.isArray(inventory);
|
|
239308
|
-
const inventoryMismatch = !inventoryMalformed && inventory.some((entry) => {
|
|
239309
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return true;
|
|
239310
|
-
const item = entry;
|
|
239311
|
-
const name = item.name;
|
|
239312
|
-
const bytes = item.bytes;
|
|
239313
|
-
if (typeof name !== "string" || typeof bytes !== "number" || !Number.isSafeInteger(bytes) || bytes < 0 || name.includes(path28.sep)) return true;
|
|
239314
|
-
try {
|
|
239315
|
-
return fs23.statSync(path28.join(resolved.dir, name)).size !== bytes;
|
|
239316
|
-
} catch {
|
|
239317
|
-
return true;
|
|
239318
|
-
}
|
|
239319
|
-
});
|
|
239320
|
-
const truncatedReason = inventoryMalformed ? "artifact_inventory_missing_or_malformed" : inventoryMismatch ? "artifact_inventory_mismatch" : void 0;
|
|
239321
|
-
return { ...resolved, completion: truncatedReason ? "truncated" : completion, ...truncatedReason ? { reason: truncatedReason } : typeof meta.reason === "string" ? { reason: meta.reason } : {} };
|
|
239322
|
-
}
|
|
239323
|
-
function creatingCommandFor(filename) {
|
|
239324
|
-
return CREATING_COMMAND_BY_FILE[filename];
|
|
239325
|
-
}
|
|
239326
|
-
function artifactPath(ref, filename, opts = {}) {
|
|
239327
|
-
const filePath = assertUnderCaptureRoot(path28.join(ref.dir, filename));
|
|
239328
|
-
const mustExist = opts.mustExist ?? true;
|
|
239329
|
-
if (mustExist && !fs23.existsSync(filePath)) {
|
|
239330
|
-
throw new ArtifactResolutionError(
|
|
239331
|
-
ref.id,
|
|
239332
|
-
[filePath],
|
|
239333
|
-
`${filename} is not present in ${ref.kind === "snap" ? "snapshot" : ref.kind === "rec" ? "recording" : "trace"} ${ref.id}`,
|
|
239334
|
-
creatingCommandFor(filename)
|
|
239335
|
-
);
|
|
239336
|
-
}
|
|
239337
|
-
return filePath;
|
|
239338
|
-
}
|
|
239339
|
-
function artifactExists(ref, filename) {
|
|
239340
|
-
return fs23.existsSync(assertUnderCaptureRoot(path28.join(ref.dir, filename)));
|
|
239341
|
-
}
|
|
239342
|
-
function readJsonArtifactFile(ref, filename) {
|
|
239343
|
-
const filePath = artifactPath(ref, filename);
|
|
239344
|
-
let raw;
|
|
239345
|
-
try {
|
|
239346
|
-
raw = fs23.readFileSync(filePath, "utf-8");
|
|
239347
|
-
} catch (err) {
|
|
239348
|
-
throw new ArtifactResolutionError(
|
|
239349
|
-
ref.id,
|
|
239350
|
-
[filePath],
|
|
239351
|
-
`could not read ${filename}: ${err instanceof Error ? err.message : String(err)}`,
|
|
239352
|
-
creatingCommandFor(filename)
|
|
239353
|
-
);
|
|
239354
|
-
}
|
|
239355
|
-
try {
|
|
239356
|
-
return JSON.parse(raw);
|
|
239357
|
-
} catch (err) {
|
|
239358
|
-
throw new ArtifactResolutionError(
|
|
239359
|
-
ref.id,
|
|
239360
|
-
[filePath],
|
|
239361
|
-
`${filename} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
239362
|
-
creatingCommandFor(filename)
|
|
239363
|
-
);
|
|
239364
|
-
}
|
|
239365
|
-
}
|
|
239366
|
-
function readNdjsonArtifactFile(ref, filename) {
|
|
239367
|
-
const filePath = artifactPath(ref, filename);
|
|
239368
|
-
let raw;
|
|
239369
|
-
try {
|
|
239370
|
-
raw = fs23.readFileSync(filePath, "utf-8");
|
|
239371
|
-
} catch (err) {
|
|
239372
|
-
throw new ArtifactResolutionError(
|
|
239373
|
-
ref.id,
|
|
239374
|
-
[filePath],
|
|
239375
|
-
`could not read ${filename}: ${err instanceof Error ? err.message : String(err)}`,
|
|
239376
|
-
creatingCommandFor(filename)
|
|
239377
|
-
);
|
|
239378
|
-
}
|
|
239379
|
-
const lines = raw.split("\n").filter((l) => l.trim().length > 0);
|
|
239380
|
-
return lines.map((line4, i) => {
|
|
239381
|
-
try {
|
|
239382
|
-
return JSON.parse(line4);
|
|
239383
|
-
} catch (err) {
|
|
239384
|
-
throw new ArtifactResolutionError(
|
|
239385
|
-
ref.id,
|
|
239386
|
-
[filePath],
|
|
239387
|
-
`${filename} line ${i + 1} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
|
239388
|
-
creatingCommandFor(filename)
|
|
239389
|
-
);
|
|
239390
|
-
}
|
|
239391
|
-
});
|
|
239392
|
-
}
|
|
239393
|
-
function assertKind(ref, kind, fnName) {
|
|
239394
|
-
if (ref.kind !== kind) {
|
|
239395
|
-
throw new TypeError(`${fnName} expects a ${kind} ref, got a ${ref.kind} ref (${ref.id})`);
|
|
239396
|
-
}
|
|
239397
|
-
}
|
|
239398
|
-
function readMeta(ref) {
|
|
239399
|
-
return readJsonArtifactFile(ref, "meta.json");
|
|
239400
|
-
}
|
|
239401
|
-
function readGeometry(ref) {
|
|
239402
|
-
assertKind(ref, "snap", "readGeometry");
|
|
239403
|
-
return readJsonArtifactFile(ref, "geometry.json");
|
|
239404
|
-
}
|
|
239405
|
-
function readStyles(ref) {
|
|
239406
|
-
assertKind(ref, "snap", "readStyles");
|
|
239407
|
-
return readJsonArtifactFile(ref, "styles.json");
|
|
239408
|
-
}
|
|
239409
|
-
function readHittest(ref) {
|
|
239410
|
-
assertKind(ref, "snap", "readHittest");
|
|
239411
|
-
return readJsonArtifactFile(ref, "hittest.json");
|
|
239412
|
-
}
|
|
239413
|
-
function readText(ref) {
|
|
239414
|
-
assertKind(ref, "snap", "readText");
|
|
239415
|
-
return readJsonArtifactFile(ref, "text.json");
|
|
239416
|
-
}
|
|
239417
|
-
function readForms(ref) {
|
|
239418
|
-
assertKind(ref, "snap", "readForms");
|
|
239419
|
-
return readJsonArtifactFile(ref, "forms.json");
|
|
239420
|
-
}
|
|
239421
|
-
function readAnimation(ref) {
|
|
239422
|
-
assertKind(ref, "snap", "readAnimation");
|
|
239423
|
-
return readJsonArtifactFile(ref, "animation.json");
|
|
239424
|
-
}
|
|
239425
|
-
function readAx(ref) {
|
|
239426
|
-
assertKind(ref, "snap", "readAx");
|
|
239427
|
-
return readJsonArtifactFile(ref, "ax.json");
|
|
239428
|
-
}
|
|
239429
|
-
function readQueries(ref) {
|
|
239430
|
-
assertKind(ref, "snap", "readQueries");
|
|
239431
|
-
return readJsonArtifactFile(ref, "queries.json");
|
|
239432
|
-
}
|
|
239433
|
-
function readFocus(ref) {
|
|
239434
|
-
assertKind(ref, "snap", "readFocus");
|
|
239435
|
-
return readJsonArtifactFile(ref, "focus.json");
|
|
239436
|
-
}
|
|
239437
|
-
function readScroll(ref) {
|
|
239438
|
-
assertKind(ref, "snap", "readScroll");
|
|
239439
|
-
return readJsonArtifactFile(ref, "scroll.json");
|
|
239440
|
-
}
|
|
239441
|
-
function readLayers(ref) {
|
|
239442
|
-
assertKind(ref, "snap", "readLayers");
|
|
239443
|
-
return readJsonArtifactFile(ref, "layers.json");
|
|
239444
|
-
}
|
|
239445
|
-
function readStates(ref) {
|
|
239446
|
-
assertKind(ref, "snap", "readStates");
|
|
239447
|
-
return readJsonArtifactFile(ref, "states.json");
|
|
239448
|
-
}
|
|
239449
|
-
function readPixels(ref) {
|
|
239450
|
-
assertKind(ref, "snap", "readPixels");
|
|
239451
|
-
return readJsonArtifactFile(ref, "pixels.json");
|
|
239452
|
-
}
|
|
239453
|
-
function readMedia(ref) {
|
|
239454
|
-
assertKind(ref, "snap", "readMedia");
|
|
239455
|
-
return readJsonArtifactFile(ref, "media.json");
|
|
239456
|
-
}
|
|
239457
|
-
function readRects(ref) {
|
|
239458
|
-
assertKind(ref, "rec", "readRects");
|
|
239459
|
-
return readNdjsonArtifactFile(ref, "rects.jsonl");
|
|
239460
|
-
}
|
|
239461
|
-
function readEvents(ref) {
|
|
239462
|
-
assertKind(ref, "rec", "readEvents");
|
|
239463
|
-
return readNdjsonArtifactFile(ref, "events.jsonl");
|
|
239464
|
-
}
|
|
239465
|
-
function readMarkers(ref) {
|
|
239466
|
-
assertKind(ref, "rec", "readMarkers");
|
|
239467
|
-
return readJsonArtifactFile(ref, "markers.json");
|
|
239468
|
-
}
|
|
239469
|
-
function unstableRegionsFor(ref) {
|
|
239470
|
-
const geometry = readGeometry(ref);
|
|
239471
|
-
return geometry.unstableRegions ?? [];
|
|
239472
|
-
}
|
|
239473
|
-
function rectsOverlap(a, b) {
|
|
239474
|
-
return a.x < b.x + b.w && a.x + a.w > b.x && a.y < b.y + b.h && a.y + a.h > b.y;
|
|
239475
|
-
}
|
|
239476
|
-
function annotateUnstableFacts(facts, regions) {
|
|
239477
|
-
return facts.map((fact4) => {
|
|
239478
|
-
const caveats = [];
|
|
239479
|
-
for (const region of regions) {
|
|
239480
|
-
const byElement = fact4.elementId !== void 0 && (region.elementIds?.includes(fact4.elementId) ?? false);
|
|
239481
|
-
const byRect = fact4.rect !== void 0 && region.rect !== void 0 && rectsOverlap(fact4.rect, region.rect);
|
|
239482
|
-
if (byElement || byRect) {
|
|
239483
|
-
caveats.push({ regionId: region.id, selector: region.selector, reason: region.reason });
|
|
239484
|
-
}
|
|
239485
|
-
}
|
|
239486
|
-
return { fact: fact4, caveats };
|
|
239487
|
-
});
|
|
239488
|
-
}
|
|
239489
|
-
var fs23, path28, ArtifactResolutionError, SNAP_CONFIG, REC_CONFIG, TRACE_CONFIG, CREATING_COMMAND_BY_FILE;
|
|
239490
|
-
var init_artifact = __esm({
|
|
239491
|
-
"src/output/artifact.ts"() {
|
|
239492
|
-
fs23 = __toESM(require("fs"));
|
|
239493
|
-
path28 = __toESM(require("path"));
|
|
239494
|
-
init_artifacts();
|
|
239495
|
-
init_session_context();
|
|
239496
|
-
ArtifactResolutionError = class extends Error {
|
|
239497
|
-
ref;
|
|
239498
|
-
searched;
|
|
239499
|
-
creatingCommand;
|
|
239500
|
-
constructor(ref, searched, detail, creatingCommand) {
|
|
239501
|
-
const parts = [`could not resolve ref ${JSON.stringify(ref)}: ${detail}`];
|
|
239502
|
-
if (searched.length) parts.push(`looked at: ${searched.join(", ")}`);
|
|
239503
|
-
if (creatingCommand) parts.push(`create it with: ${creatingCommand}`);
|
|
239504
|
-
super(parts.join(" \u2014 "));
|
|
239505
|
-
this.name = "ArtifactResolutionError";
|
|
239506
|
-
this.ref = ref;
|
|
239507
|
-
this.searched = searched;
|
|
239508
|
-
this.creatingCommand = creatingCommand;
|
|
239509
|
-
}
|
|
239510
|
-
};
|
|
239511
|
-
SNAP_CONFIG = {
|
|
239512
|
-
kind: "snap",
|
|
239513
|
-
idSegments: ["measure", "snaps"],
|
|
239514
|
-
creatingCommand: "capture measure snap",
|
|
239515
|
-
label: "snapshot"
|
|
239516
|
-
};
|
|
239517
|
-
REC_CONFIG = {
|
|
239518
|
-
kind: "rec",
|
|
239519
|
-
idSegments: ["motion", "recs"],
|
|
239520
|
-
creatingCommand: "capture motion rec",
|
|
239521
|
-
label: "recording"
|
|
239522
|
-
};
|
|
239523
|
-
TRACE_CONFIG = {
|
|
239524
|
-
kind: "trace",
|
|
239525
|
-
idSegments: ["perf", "traces"],
|
|
239526
|
-
creatingCommand: "capture perf trace",
|
|
239527
|
-
label: "trace"
|
|
239528
|
-
};
|
|
239529
|
-
CREATING_COMMAND_BY_FILE = {
|
|
239530
|
-
"geometry.json": "capture measure snap",
|
|
239531
|
-
"styles.json": "capture measure snap",
|
|
239532
|
-
"hittest.json": "capture measure snap",
|
|
239533
|
-
"text.json": "capture measure snap",
|
|
239534
|
-
"forms.json": "capture measure snap",
|
|
239535
|
-
"animation.json": "capture measure snap",
|
|
239536
|
-
"ax.json": "capture measure snap",
|
|
239537
|
-
"media.json": "capture measure snap",
|
|
239538
|
-
"queries.json": "capture measure snap",
|
|
239539
|
-
"focus.json": "capture measure snap",
|
|
239540
|
-
"scroll.json": "capture measure snap",
|
|
239541
|
-
"layers.json": "capture measure snap",
|
|
239542
|
-
"states.json": "capture measure snap --state <state>",
|
|
239543
|
-
"churn.json": "capture measure snap (written only when the page did not settle)",
|
|
239544
|
-
"pixels.json": "capture measure snap --pixels",
|
|
239545
|
-
"dom.html": "capture measure snap",
|
|
239546
|
-
"screenshot.png": "capture measure snap",
|
|
239547
|
-
"meta.json": "capture measure snap (or capture motion rec for a recording)",
|
|
239548
|
-
"rects.jsonl": "capture motion rec",
|
|
239549
|
-
"events.jsonl": "capture motion rec",
|
|
239550
|
-
"markers.json": "capture motion rec",
|
|
239551
|
-
"trace.json": "capture perf trace"
|
|
239552
|
-
};
|
|
239553
|
-
}
|
|
239554
|
-
});
|
|
239555
|
-
|
|
239556
239614
|
// src/cdp/commands/measure/snap.ts
|
|
239557
239615
|
function generateSnapId() {
|
|
239558
239616
|
return `snap-${Date.now().toString(36)}-${(0, import_crypto2.randomBytes)(4).toString("hex")}`;
|
|
@@ -267455,10 +267513,10 @@ Selecting a noun: session, page, and tab address the live browser; measure, moti
|
|
|
267455
267513
|
|
|
267456
267514
|
I/O contract: flags and positionals on input; one rendered prose block on stdout. --json mirrors the same result as JSON, but the rendered block is the contract. stderr carries in-flight diagnostics only. --artifact-dir <path> selects the root for a session bundle (\`session start\`) or a sessionless artifact-producing leaf's one-shot bundle; leaf help states when it writes one. --out always names one caller-owned file, never a bundle directory.
|
|
267457
267515
|
|
|
267458
|
-
A CDP-enabled browser must be running; \`capture tab list\` is the probe, and \`capture tab launch\` starts one capture owns and reaps when nothing is (never hand-roll a detached browser \u2014 nothing reaps that). Capture never signals a browser it did not start, so attaching to your own with --port is unchanged. CDP_PORT / CDP_TARGET pin the browser + tab for target-selecting commands \u2014 precedence: explicit flag > active session > env. \`session start\` adopts only an explicit --target.`;
|
|
267516
|
+
A CDP-enabled browser must be running; \`capture tab list\` is the probe, and \`capture tab launch\` starts one capture owns and reaps when nothing is (never hand-roll a detached browser \u2014 nothing reaps that). Capture never signals a browser it did not start, so attaching to your own with --port is unchanged. CDP_PORT / CDP_TARGET pin the browser + tab for target-selecting commands \u2014 precedence: explicit flag > active session > env. \`session start\` adopts only an explicit --target. When CRTR_NODE_ID is set (a crtr agent node), a browser command with no --port, no --target and no active session of that node is refused instead of falling back to CDP_PORT, CDP_TARGET or localhost discovery, because the browser found could belong to another node: run \`capture session start --url <url>\`, or pass --port or --target. \`capture tab list\` and commands that only read a recorded artifact are not refused.`;
|
|
267459
267517
|
}
|
|
267460
267518
|
function printVersion() {
|
|
267461
|
-
const declared = "1.4.
|
|
267519
|
+
const declared = "1.4.23";
|
|
267462
267520
|
if (declared) {
|
|
267463
267521
|
console.log(declared);
|
|
267464
267522
|
return;
|