Some checks failed
Main Confidence / confidence (push) Failing after 45s
## Summary - introduce surface-aware compressed governance outcomes and reuse the shared truth/explanation seams for operator-first summaries - apply the compressed outcome hierarchy across baseline, evidence, review, review-pack, canonical review/evidence, and artifact-oriented operation-run surfaces - expand spec 214 fixtures and Pest coverage, and fix tenant-panel route assertions by generating explicit tenant-panel URLs in the affected Filament tests ## Validation - `cd apps/platform && ./vendor/bin/sail bin pint --dirty --format agent` - focused governance compression suite from `specs/214-governance-outcome-compression/quickstart.md` passed (`68` tests, `445` assertions) - `cd apps/platform && ./vendor/bin/sail artisan test --compact tests/Feature/Filament/InventoryItemResourceTest.php tests/Feature/Filament/BackupSetUiEnforcementTest.php tests/Feature/Filament/RestoreRunUiEnforcementTest.php` passed (`18` tests, `81` assertions) Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #253
656 lines
23 KiB
Plaintext
656 lines
23 KiB
Plaintext
"use strict";
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __export = (target, all) => {
|
|
for (var name in all)
|
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
var tracing_exports = {};
|
|
__export(tracing_exports, {
|
|
Tracing: () => Tracing
|
|
});
|
|
module.exports = __toCommonJS(tracing_exports);
|
|
var import_fs = __toESM(require("fs"));
|
|
var import_os = __toESM(require("os"));
|
|
var import_path = __toESM(require("path"));
|
|
var import_snapshotter = require("./snapshotter");
|
|
var import_protocolMetainfo = require("../../../utils/isomorphic/protocolMetainfo");
|
|
var import_assert = require("../../../utils/isomorphic/assert");
|
|
var import_time = require("../../../utils/isomorphic/time");
|
|
var import_manualPromise = require("../../../utils/isomorphic/manualPromise");
|
|
var import_eventsHelper = require("../../utils/eventsHelper");
|
|
var import_crypto = require("../../utils/crypto");
|
|
var import_userAgent = require("../../utils/userAgent");
|
|
var import_artifact = require("../../artifact");
|
|
var import_browserContext = require("../../browserContext");
|
|
var import_dispatcher = require("../../dispatchers/dispatcher");
|
|
var import_errors = require("../../errors");
|
|
var import_fileUtils = require("../../utils/fileUtils");
|
|
var import_harTracer = require("../../har/harTracer");
|
|
var import_instrumentation = require("../../instrumentation");
|
|
var import_progress = require("../../progress");
|
|
const version = 8;
|
|
class Tracing extends import_instrumentation.SdkObject {
|
|
constructor(context, tracesDir) {
|
|
super(context, "tracing");
|
|
this._fs = new import_fileUtils.SerializedFS();
|
|
this._screencastListeners = [];
|
|
this._pageTracingRecorders = /* @__PURE__ */ new Map();
|
|
this._eventListeners = [];
|
|
this._isStopping = false;
|
|
this._allResources = /* @__PURE__ */ new Set();
|
|
this._pendingHarEntries = /* @__PURE__ */ new Set();
|
|
this._context = context;
|
|
this._precreatedTracesDir = tracesDir;
|
|
this._harTracer = new import_harTracer.HarTracer(context, null, this, {
|
|
content: "attach",
|
|
includeTraceInfo: true,
|
|
recordRequestOverrides: false,
|
|
waitForContentOnStop: false
|
|
});
|
|
const testIdAttributeName = "selectors" in context ? context.selectors().testIdAttributeName() : void 0;
|
|
this._contextCreatedEvent = {
|
|
version,
|
|
type: "context-options",
|
|
origin: "library",
|
|
browserName: "",
|
|
playwrightVersion: (0, import_userAgent.getPlaywrightVersion)(),
|
|
options: {},
|
|
platform: process.platform,
|
|
wallTime: 0,
|
|
monotonicTime: 0,
|
|
sdkLanguage: this._sdkLanguage(),
|
|
testIdAttributeName,
|
|
contextId: context.guid
|
|
};
|
|
if (context instanceof import_browserContext.BrowserContext) {
|
|
this._snapshotter = new import_snapshotter.Snapshotter(context, this);
|
|
(0, import_assert.assert)(tracesDir, "tracesDir must be specified for BrowserContext");
|
|
this._contextCreatedEvent.browserName = context._browser.options.name;
|
|
this._contextCreatedEvent.channel = context._browser.options.channel;
|
|
this._contextCreatedEvent.options = context._options;
|
|
}
|
|
}
|
|
_sdkLanguage() {
|
|
return this._context instanceof import_browserContext.BrowserContext ? this._context._browser.sdkLanguage() : this._context.attribution.playwright.options.sdkLanguage;
|
|
}
|
|
async resetForReuse(progress) {
|
|
await this.stopChunk(progress, { mode: "discard" }).catch(() => {
|
|
});
|
|
await this.stop(progress);
|
|
if (this._snapshotter)
|
|
await progress.race(this._snapshotter.resetForReuse());
|
|
}
|
|
start(options) {
|
|
if (this._isStopping)
|
|
throw new Error("Cannot start tracing while stopping");
|
|
if (this._state)
|
|
throw new Error("Tracing has been already started");
|
|
this._contextCreatedEvent.sdkLanguage = this._sdkLanguage();
|
|
const traceName = options.name || (0, import_crypto.createGuid)();
|
|
const tracesDir = this._createTracesDirIfNeeded();
|
|
this._state = {
|
|
options,
|
|
traceName,
|
|
tracesDir,
|
|
traceFile: import_path.default.join(tracesDir, traceName + ".trace"),
|
|
networkFile: import_path.default.join(tracesDir, traceName + ".network"),
|
|
resourcesDir: import_path.default.join(tracesDir, "resources"),
|
|
chunkOrdinal: 0,
|
|
traceSha1s: /* @__PURE__ */ new Set(),
|
|
networkSha1s: /* @__PURE__ */ new Set(),
|
|
recording: false,
|
|
callIds: /* @__PURE__ */ new Set(),
|
|
groupStack: []
|
|
};
|
|
this._fs.mkdir(this._state.resourcesDir);
|
|
this._fs.writeFile(this._state.networkFile, "");
|
|
if (options.snapshots)
|
|
this._harTracer.start({ omitScripts: !options.live });
|
|
}
|
|
async startChunk(progress, options = {}) {
|
|
if (this._state && this._state.recording)
|
|
await this.stopChunk(progress, { mode: "discard" });
|
|
if (!this._state)
|
|
throw new Error("Must start tracing before starting a new chunk");
|
|
if (this._isStopping)
|
|
throw new Error("Cannot start a trace chunk while stopping");
|
|
this._state.recording = true;
|
|
this._state.callIds.clear();
|
|
const preserveNetworkResources = this._context instanceof import_browserContext.BrowserContext;
|
|
if (options.name && options.name !== this._state.traceName)
|
|
this._changeTraceName(this._state, options.name, preserveNetworkResources);
|
|
else
|
|
this._allocateNewTraceFile(this._state);
|
|
if (!preserveNetworkResources)
|
|
this._fs.writeFile(this._state.networkFile, "");
|
|
this._fs.mkdir(import_path.default.dirname(this._state.traceFile));
|
|
const event = {
|
|
...this._contextCreatedEvent,
|
|
title: options.title,
|
|
wallTime: Date.now(),
|
|
monotonicTime: (0, import_time.monotonicTime)()
|
|
};
|
|
this._appendTraceEvent(event);
|
|
this._context.instrumentation.addListener(this, this._context);
|
|
this._eventListeners.push(
|
|
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Console, this._onConsoleMessage.bind(this)),
|
|
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.PageError, this._onPageError.bind(this))
|
|
);
|
|
if (this._state.options.screenshots)
|
|
this._startScreencast();
|
|
if (this._state.options.snapshots)
|
|
await this._snapshotter?.start();
|
|
return { traceName: this._state.traceName };
|
|
}
|
|
_currentGroupId() {
|
|
return this._state?.groupStack.length ? this._state.groupStack[this._state.groupStack.length - 1] : void 0;
|
|
}
|
|
group(name, location, metadata) {
|
|
if (!this._state)
|
|
return;
|
|
const stackFrames = [];
|
|
const { file, line, column } = location ?? metadata.location ?? {};
|
|
if (file) {
|
|
stackFrames.push({
|
|
file,
|
|
line: line ?? 0,
|
|
column: column ?? 0
|
|
});
|
|
}
|
|
const event = {
|
|
type: "before",
|
|
callId: metadata.id,
|
|
startTime: metadata.startTime,
|
|
title: name,
|
|
class: "Tracing",
|
|
method: "tracingGroup",
|
|
params: {},
|
|
stepId: metadata.stepId,
|
|
stack: stackFrames
|
|
};
|
|
if (this._currentGroupId())
|
|
event.parentId = this._currentGroupId();
|
|
this._state.groupStack.push(event.callId);
|
|
this._appendTraceEvent(event);
|
|
}
|
|
groupEnd() {
|
|
if (!this._state)
|
|
return;
|
|
const callId = this._state.groupStack.pop();
|
|
if (!callId)
|
|
return;
|
|
const event = {
|
|
type: "after",
|
|
callId,
|
|
endTime: (0, import_time.monotonicTime)()
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
_startScreencast() {
|
|
if (!(this._context instanceof import_browserContext.BrowserContext))
|
|
return;
|
|
for (const page of this._context.pages())
|
|
this._startScreencastInPage(page);
|
|
this._screencastListeners.push(
|
|
import_eventsHelper.eventsHelper.addEventListener(this._context, import_browserContext.BrowserContext.Events.Page, this._startScreencastInPage.bind(this))
|
|
);
|
|
}
|
|
_stopScreencast() {
|
|
import_eventsHelper.eventsHelper.removeEventListeners(this._screencastListeners);
|
|
for (const recorder of this._pageTracingRecorders.values())
|
|
recorder.dispose();
|
|
this._pageTracingRecorders.clear();
|
|
}
|
|
_allocateNewTraceFile(state) {
|
|
const suffix = state.chunkOrdinal ? `-chunk${state.chunkOrdinal}` : ``;
|
|
state.chunkOrdinal++;
|
|
state.traceFile = import_path.default.join(state.tracesDir, `${state.traceName}${suffix}.trace`);
|
|
}
|
|
_changeTraceName(state, name, preserveNetworkResources) {
|
|
state.traceName = name;
|
|
state.chunkOrdinal = 0;
|
|
this._allocateNewTraceFile(state);
|
|
const newNetworkFile = import_path.default.join(state.tracesDir, name + ".network");
|
|
if (preserveNetworkResources)
|
|
this._fs.copyFile(state.networkFile, newNetworkFile);
|
|
state.networkFile = newNetworkFile;
|
|
}
|
|
async stop(progress) {
|
|
if (!this._state)
|
|
return;
|
|
if (this._isStopping)
|
|
throw new Error(`Tracing is already stopping`);
|
|
if (this._state.recording)
|
|
throw new Error(`Must stop trace file before stopping tracing`);
|
|
this._closeAllGroups();
|
|
this._harTracer.stop();
|
|
this.flushHarEntries();
|
|
const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
|
|
await promise.finally(() => {
|
|
this._state = void 0;
|
|
});
|
|
}
|
|
async deleteTmpTracesDir() {
|
|
if (this._tracesTmpDir)
|
|
await (0, import_fileUtils.removeFolders)([this._tracesTmpDir]);
|
|
}
|
|
_createTracesDirIfNeeded() {
|
|
if (this._precreatedTracesDir)
|
|
return this._precreatedTracesDir;
|
|
this._tracesTmpDir = import_fs.default.mkdtempSync(import_path.default.join(import_os.default.tmpdir(), "playwright-tracing-"));
|
|
return this._tracesTmpDir;
|
|
}
|
|
abort() {
|
|
this._snapshotter?.dispose();
|
|
this._harTracer.stop();
|
|
}
|
|
async flush() {
|
|
this.abort();
|
|
await this._fs.syncAndGetError();
|
|
}
|
|
_closeAllGroups() {
|
|
while (this._currentGroupId())
|
|
this.groupEnd();
|
|
}
|
|
async stopChunk(progress, params) {
|
|
if (this._isStopping)
|
|
throw new Error(`Tracing is already stopping`);
|
|
this._isStopping = true;
|
|
if (!this._state || !this._state.recording) {
|
|
this._isStopping = false;
|
|
if (params.mode !== "discard")
|
|
throw new Error(`Must start tracing before stopping`);
|
|
return {};
|
|
}
|
|
this._closeAllGroups();
|
|
this._context.instrumentation.removeListener(this);
|
|
import_eventsHelper.eventsHelper.removeEventListeners(this._eventListeners);
|
|
if (this._state.options.screenshots)
|
|
this._stopScreencast();
|
|
if (this._state.options.snapshots)
|
|
this._snapshotter?.stop();
|
|
this.flushHarEntries();
|
|
const newNetworkFile = import_path.default.join(this._state.tracesDir, this._state.traceName + `-pwnetcopy-${this._state.chunkOrdinal}.network`);
|
|
const entries = [];
|
|
entries.push({ name: "trace.trace", value: this._state.traceFile });
|
|
entries.push({ name: "trace.network", value: newNetworkFile });
|
|
for (const sha1 of /* @__PURE__ */ new Set([...this._state.traceSha1s, ...this._state.networkSha1s]))
|
|
entries.push({ name: import_path.default.join("resources", sha1), value: import_path.default.join(this._state.resourcesDir, sha1) });
|
|
this._state.traceSha1s = /* @__PURE__ */ new Set();
|
|
if (params.mode === "discard") {
|
|
this._isStopping = false;
|
|
this._state.recording = false;
|
|
return {};
|
|
}
|
|
this._fs.copyFile(this._state.networkFile, newNetworkFile);
|
|
const zipFileName = this._state.traceFile + ".zip";
|
|
if (params.mode === "archive")
|
|
this._fs.zip(entries, zipFileName);
|
|
const promise = progress ? progress.race(this._fs.syncAndGetError()) : this._fs.syncAndGetError();
|
|
const error = await promise.catch((e) => e);
|
|
this._isStopping = false;
|
|
if (this._state)
|
|
this._state.recording = false;
|
|
if (error) {
|
|
if (!(0, import_progress.isAbortError)(error) && this._context instanceof import_browserContext.BrowserContext && !this._context._browser.isConnected())
|
|
return {};
|
|
throw error;
|
|
}
|
|
if (params.mode === "entries")
|
|
return { entries };
|
|
const artifact = new import_artifact.Artifact(this._context, zipFileName);
|
|
artifact.reportFinished();
|
|
return { artifact };
|
|
}
|
|
async _captureSnapshot(snapshotName, sdkObject, metadata) {
|
|
if (!snapshotName || !sdkObject.attribution.page)
|
|
return;
|
|
await this._snapshotter?.captureSnapshot(sdkObject.attribution.page, metadata.id, snapshotName).catch(() => {
|
|
});
|
|
}
|
|
_shouldCaptureSnapshot(sdkObject, metadata, phase) {
|
|
if (!sdkObject.attribution.page || !this._snapshotter?.started())
|
|
return;
|
|
const metainfo = (0, import_protocolMetainfo.getMetainfo)(metadata);
|
|
if (!metainfo?.snapshot)
|
|
return false;
|
|
switch (phase) {
|
|
case "before":
|
|
return !metainfo.input || !!metainfo.isAutoWaiting;
|
|
case "input":
|
|
return !!metainfo.input;
|
|
case "after":
|
|
return true;
|
|
}
|
|
}
|
|
onBeforeCall(sdkObject, metadata, parentId) {
|
|
const event = createBeforeActionTraceEvent(metadata, parentId ?? this._currentGroupId());
|
|
if (!event)
|
|
return Promise.resolve();
|
|
this._temporarilyDisableThrottling(sdkObject.attribution.page);
|
|
if (this._shouldCaptureSnapshot(sdkObject, metadata, "before"))
|
|
event.beforeSnapshot = `before@${metadata.id}`;
|
|
this._state?.callIds.add(metadata.id);
|
|
this._appendTraceEvent(event);
|
|
return this._captureSnapshot(event.beforeSnapshot, sdkObject, metadata);
|
|
}
|
|
onBeforeInputAction(sdkObject, metadata) {
|
|
if (!this._state?.callIds.has(metadata.id))
|
|
return Promise.resolve();
|
|
const event = createInputActionTraceEvent(metadata);
|
|
if (!event)
|
|
return Promise.resolve();
|
|
this._temporarilyDisableThrottling(sdkObject.attribution.page);
|
|
if (this._shouldCaptureSnapshot(sdkObject, metadata, "input"))
|
|
event.inputSnapshot = `input@${metadata.id}`;
|
|
this._appendTraceEvent(event);
|
|
return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata);
|
|
}
|
|
onCallLog(sdkObject, metadata, logName, message) {
|
|
if (!this._state?.callIds.has(metadata.id))
|
|
return;
|
|
if (metadata.internal)
|
|
return;
|
|
if (logName !== "api")
|
|
return;
|
|
const event = createActionLogTraceEvent(metadata, message);
|
|
if (event)
|
|
this._appendTraceEvent(event);
|
|
}
|
|
onAfterCall(sdkObject, metadata) {
|
|
if (!this._state?.callIds.has(metadata.id))
|
|
return Promise.resolve();
|
|
this._state?.callIds.delete(metadata.id);
|
|
const event = createAfterActionTraceEvent(metadata);
|
|
if (!event)
|
|
return Promise.resolve();
|
|
this._temporarilyDisableThrottling(sdkObject.attribution.page);
|
|
if (this._shouldCaptureSnapshot(sdkObject, metadata, "after"))
|
|
event.afterSnapshot = `after@${metadata.id}`;
|
|
this._appendTraceEvent(event);
|
|
return this._captureSnapshot(event.afterSnapshot, sdkObject, metadata);
|
|
}
|
|
onEntryStarted(entry) {
|
|
this._pendingHarEntries.add(entry);
|
|
}
|
|
onEntryFinished(entry) {
|
|
this._pendingHarEntries.delete(entry);
|
|
const event = { type: "resource-snapshot", snapshot: entry };
|
|
const visited = visitTraceEvent(event, this._state.networkSha1s);
|
|
this._fs.appendFile(
|
|
this._state.networkFile,
|
|
JSON.stringify(visited) + "\n",
|
|
true
|
|
/* flush */
|
|
);
|
|
}
|
|
flushHarEntries() {
|
|
const harLines = [];
|
|
for (const entry of this._pendingHarEntries) {
|
|
const event = { type: "resource-snapshot", snapshot: entry };
|
|
const visited = visitTraceEvent(event, this._state.networkSha1s);
|
|
harLines.push(JSON.stringify(visited));
|
|
}
|
|
this._pendingHarEntries.clear();
|
|
if (harLines.length)
|
|
this._fs.appendFile(
|
|
this._state.networkFile,
|
|
harLines.join("\n") + "\n",
|
|
true
|
|
/* flush */
|
|
);
|
|
}
|
|
onContentBlob(sha1, buffer) {
|
|
this._appendResource(sha1, buffer);
|
|
}
|
|
onSnapshotterBlob(blob) {
|
|
this._appendResource(blob.sha1, blob.buffer);
|
|
}
|
|
onFrameSnapshot(snapshot) {
|
|
this._appendTraceEvent({ type: "frame-snapshot", snapshot });
|
|
}
|
|
_onConsoleMessage(message) {
|
|
const event = {
|
|
type: "console",
|
|
messageType: message.type(),
|
|
text: message.text(),
|
|
args: message.args().map((a) => ({ preview: a.toString(), value: a.rawValue() })),
|
|
location: message.location(),
|
|
time: (0, import_time.monotonicTime)(),
|
|
pageId: message.page()?.guid
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
onDialog(dialog) {
|
|
const event = {
|
|
type: "event",
|
|
time: (0, import_time.monotonicTime)(),
|
|
class: "BrowserContext",
|
|
method: "dialog",
|
|
params: { pageId: dialog.page().guid, type: dialog.type(), message: dialog.message(), defaultValue: dialog.defaultValue() }
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
onDownload(page, download) {
|
|
const event = {
|
|
type: "event",
|
|
time: (0, import_time.monotonicTime)(),
|
|
class: "BrowserContext",
|
|
method: "download",
|
|
params: { pageId: page.guid, url: download.url, suggestedFilename: download.suggestedFilename() }
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
onPageOpen(page) {
|
|
const event = {
|
|
type: "event",
|
|
time: (0, import_time.monotonicTime)(),
|
|
class: "BrowserContext",
|
|
method: "page",
|
|
params: { pageId: page.guid, openerPageId: page.opener()?.guid }
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
onPageClose(page) {
|
|
const event = {
|
|
type: "event",
|
|
time: (0, import_time.monotonicTime)(),
|
|
class: "BrowserContext",
|
|
method: "pageClosed",
|
|
params: { pageId: page.guid }
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
_onPageError(error, page) {
|
|
const event = {
|
|
type: "event",
|
|
time: (0, import_time.monotonicTime)(),
|
|
class: "BrowserContext",
|
|
method: "pageError",
|
|
params: { error: (0, import_errors.serializeError)(error) },
|
|
pageId: page.guid
|
|
};
|
|
this._appendTraceEvent(event);
|
|
}
|
|
_temporarilyDisableThrottling(page) {
|
|
if (page)
|
|
this._pageTracingRecorders.get(page)?.temporarilyDisableThrottling();
|
|
}
|
|
_startScreencastInPage(page) {
|
|
const prefix = page.guid;
|
|
const onFrame = (params) => {
|
|
const suffix = Date.now();
|
|
const sha1 = `${prefix}-${suffix}.jpeg`;
|
|
const event = {
|
|
type: "screencast-frame",
|
|
pageId: page.guid,
|
|
sha1,
|
|
width: params.viewportWidth,
|
|
height: params.viewportHeight,
|
|
timestamp: (0, import_time.monotonicTime)(),
|
|
frameSwapWallTime: params.frameSwapWallTime
|
|
};
|
|
this._appendResource(sha1, params.buffer);
|
|
this._appendTraceEvent(event);
|
|
};
|
|
this._pageTracingRecorders.set(page, new ScreencastTracingRecorder(page.screencast, onFrame));
|
|
}
|
|
_appendTraceEvent(event) {
|
|
const visited = visitTraceEvent(event, this._state.traceSha1s);
|
|
const flush = this._state.options.live || event.type !== "event" && event.type !== "console" && event.type !== "log";
|
|
this._fs.appendFile(this._state.traceFile, JSON.stringify(visited) + "\n", flush);
|
|
}
|
|
_appendResource(sha1, buffer) {
|
|
if (this._allResources.has(sha1))
|
|
return;
|
|
this._allResources.add(sha1);
|
|
const resourcePath = import_path.default.join(this._state.resourcesDir, sha1);
|
|
this._fs.writeFile(
|
|
resourcePath,
|
|
buffer,
|
|
true
|
|
/* skipIfExists */
|
|
);
|
|
}
|
|
}
|
|
function visitTraceEvent(object, sha1s) {
|
|
if (Array.isArray(object))
|
|
return object.map((o) => visitTraceEvent(o, sha1s));
|
|
if (object instanceof import_dispatcher.Dispatcher)
|
|
return `<${object._type}>`;
|
|
if (object instanceof Buffer)
|
|
return `<Buffer>`;
|
|
if (object instanceof Date)
|
|
return object;
|
|
if (typeof object === "object") {
|
|
const result = {};
|
|
for (const key in object) {
|
|
if (key === "sha1" || key === "_sha1" || key.endsWith("Sha1")) {
|
|
const sha1 = object[key];
|
|
if (sha1)
|
|
sha1s.add(sha1);
|
|
}
|
|
result[key] = visitTraceEvent(object[key], sha1s);
|
|
}
|
|
return result;
|
|
}
|
|
return object;
|
|
}
|
|
function createBeforeActionTraceEvent(metadata, parentId) {
|
|
if (metadata.internal || metadata.method.startsWith("tracing"))
|
|
return null;
|
|
const event = {
|
|
type: "before",
|
|
callId: metadata.id,
|
|
startTime: metadata.startTime,
|
|
title: metadata.title,
|
|
class: metadata.type,
|
|
method: metadata.method,
|
|
params: metadata.params,
|
|
stepId: metadata.stepId,
|
|
pageId: metadata.pageId
|
|
};
|
|
if (parentId)
|
|
event.parentId = parentId;
|
|
return event;
|
|
}
|
|
function createInputActionTraceEvent(metadata) {
|
|
if (metadata.internal || metadata.method.startsWith("tracing"))
|
|
return null;
|
|
return {
|
|
type: "input",
|
|
callId: metadata.id,
|
|
point: metadata.point
|
|
};
|
|
}
|
|
function createActionLogTraceEvent(metadata, message) {
|
|
if (metadata.internal || metadata.method.startsWith("tracing"))
|
|
return null;
|
|
return {
|
|
type: "log",
|
|
callId: metadata.id,
|
|
time: (0, import_time.monotonicTime)(),
|
|
message
|
|
};
|
|
}
|
|
function createAfterActionTraceEvent(metadata) {
|
|
if (metadata.internal || metadata.method.startsWith("tracing"))
|
|
return null;
|
|
return {
|
|
type: "after",
|
|
callId: metadata.id,
|
|
endTime: metadata.endTime,
|
|
error: metadata.error?.error,
|
|
result: metadata.result,
|
|
point: metadata.point
|
|
};
|
|
}
|
|
const throttledRate = 200;
|
|
const unthrottleDuration = 500;
|
|
class ScreencastTracingRecorder {
|
|
constructor(screencast, onFrame) {
|
|
this._unthrottledUntil = 0;
|
|
this._screencast = screencast;
|
|
this._client = {
|
|
onFrame: (frame) => {
|
|
const time = (0, import_time.monotonicTime)();
|
|
if (time < this._unthrottledUntil) {
|
|
onFrame(frame);
|
|
return;
|
|
}
|
|
if (this._pendingAck)
|
|
return;
|
|
onFrame(frame);
|
|
this._pendingAck = new import_manualPromise.ManualPromise();
|
|
this._timer = setTimeout(() => this._clearPendingAck(), throttledRate);
|
|
return this._pendingAck;
|
|
},
|
|
gracefulClose: () => this.dispose(),
|
|
dispose: () => this.dispose()
|
|
};
|
|
this._screencast.addClient(this._client);
|
|
}
|
|
dispose() {
|
|
this._screencast.removeClient(this._client);
|
|
this._clearPendingAck();
|
|
}
|
|
temporarilyDisableThrottling() {
|
|
this._unthrottledUntil = (0, import_time.monotonicTime)() + unthrottleDuration;
|
|
this._clearPendingAck();
|
|
}
|
|
_clearPendingAck() {
|
|
this._pendingAck?.resolve();
|
|
this._pendingAck = void 0;
|
|
if (this._timer) {
|
|
clearTimeout(this._timer);
|
|
this._timer = void 0;
|
|
}
|
|
}
|
|
}
|
|
// Annotate the CommonJS export names for ESM import in node:
|
|
0 && (module.exports = {
|
|
Tracing
|
|
});
|