@midscene/core 1.17.4 → 1.17.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/es/agent/agent-report-manager.mjs +28 -5
- package/dist/es/agent/agent-report-manager.mjs.map +1 -1
- package/dist/es/agent/agent.mjs +2 -2
- package/dist/es/agent/agent.mjs.map +1 -1
- package/dist/es/agent/utils.mjs +1 -1
- package/dist/es/dump/html-utils.mjs +51 -68
- package/dist/es/dump/html-utils.mjs.map +1 -1
- package/dist/es/dump/report-artifact-publication.mjs +52 -0
- package/dist/es/dump/report-artifact-publication.mjs.map +1 -0
- package/dist/es/dump/report-artifact-store.mjs +2 -2
- package/dist/es/dump/report-artifact-store.mjs.map +1 -1
- package/dist/es/dump/report-artifact-writer.mjs +129 -0
- package/dist/es/dump/report-artifact-writer.mjs.map +1 -0
- package/dist/es/dump/report-session.mjs +229 -0
- package/dist/es/dump/report-session.mjs.map +1 -0
- package/dist/es/dump/test-report-images.mjs +68 -42
- package/dist/es/dump/test-report-images.mjs.map +1 -1
- package/dist/es/index.mjs +2 -2
- package/dist/es/index.mjs.map +1 -1
- package/dist/es/report-cli.mjs +38 -11
- package/dist/es/report-cli.mjs.map +1 -1
- package/dist/es/report-generator.mjs +2 -1
- package/dist/es/report-generator.mjs.map +1 -1
- package/dist/es/report-html-template.mjs +1 -1
- package/dist/es/report.mjs +152 -159
- package/dist/es/report.mjs.map +1 -1
- package/dist/es/test-run-report.mjs.map +1 -1
- package/dist/es/utils.mjs +1 -1
- package/dist/es/yaml/player.mjs +1 -1
- package/dist/es/yaml/player.mjs.map +1 -1
- package/dist/lib/agent/agent-report-manager.js +27 -4
- package/dist/lib/agent/agent-report-manager.js.map +1 -1
- package/dist/lib/agent/agent.js +2 -2
- package/dist/lib/agent/agent.js.map +1 -1
- package/dist/lib/agent/utils.js +1 -1
- package/dist/lib/dump/html-utils.js +59 -70
- package/dist/lib/dump/html-utils.js.map +1 -1
- package/dist/lib/dump/report-artifact-publication.js +89 -0
- package/dist/lib/dump/report-artifact-publication.js.map +1 -0
- package/dist/lib/dump/report-artifact-store.js +2 -2
- package/dist/lib/dump/report-artifact-store.js.map +1 -1
- package/dist/lib/dump/report-artifact-writer.js +163 -0
- package/dist/lib/dump/report-artifact-writer.js.map +1 -0
- package/dist/lib/dump/report-session.js +266 -0
- package/dist/lib/dump/report-session.js.map +1 -0
- package/dist/lib/dump/test-report-images.js +67 -41
- package/dist/lib/dump/test-report-images.js.map +1 -1
- package/dist/lib/index.js +3 -0
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/report-cli.js +37 -10
- package/dist/lib/report-cli.js.map +1 -1
- package/dist/lib/report-generator.js +2 -1
- package/dist/lib/report-generator.js.map +1 -1
- package/dist/lib/report-html-template.js +1 -1
- package/dist/lib/report.js +152 -153
- package/dist/lib/report.js.map +1 -1
- package/dist/lib/test-run-report.js.map +1 -1
- package/dist/lib/utils.js +1 -1
- package/dist/lib/yaml/player.js +1 -1
- package/dist/lib/yaml/player.js.map +1 -1
- package/dist/types/agent/agent-report-manager.d.ts +4 -1
- package/dist/types/agent/agent-report-manager.d.ts.map +1 -1
- package/dist/types/agent/agent.d.ts +1 -1
- package/dist/types/agent/agent.d.ts.map +1 -1
- package/dist/types/dump/html-utils.d.ts +7 -1
- package/dist/types/dump/html-utils.d.ts.map +1 -1
- package/dist/types/dump/report-artifact-publication.d.ts +5 -0
- package/dist/types/dump/report-artifact-publication.d.ts.map +1 -0
- package/dist/types/dump/report-artifact-store.d.ts +1 -1
- package/dist/types/dump/report-artifact-store.d.ts.map +1 -1
- package/dist/types/dump/report-artifact-writer.d.ts +21 -0
- package/dist/types/dump/report-artifact-writer.d.ts.map +1 -0
- package/dist/types/dump/report-session.d.ts +48 -0
- package/dist/types/dump/report-session.d.ts.map +1 -0
- package/dist/types/dump/test-report-images.d.ts +5 -2
- package/dist/types/dump/test-report-images.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/report-cli.d.ts +2 -1
- package/dist/types/report-cli.d.ts.map +1 -1
- package/dist/types/report-generator.d.ts.map +1 -1
- package/dist/types/report.d.ts +11 -0
- package/dist/types/report.d.ts.map +1 -1
- package/dist/types/test-run-report.d.ts +2 -2
- package/dist/types/test-run-report.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -40,6 +40,8 @@ var __webpack_exports__ = {};
|
|
|
40
40
|
__webpack_require__.r(__webpack_exports__);
|
|
41
41
|
__webpack_require__.d(__webpack_exports__, {
|
|
42
42
|
collectImageScriptIds: ()=>collectImageScriptIds,
|
|
43
|
+
streamScanTagsAsync: ()=>streamScanTagsAsync,
|
|
44
|
+
unescapeContent: ()=>unescapeContent,
|
|
43
45
|
generateImageScriptTag: ()=>generateImageScriptTag,
|
|
44
46
|
generateAgentReportComment: ()=>generateAgentReportComment,
|
|
45
47
|
getBaseUrlFixScript: ()=>getBaseUrlFixScript,
|
|
@@ -61,9 +63,9 @@ var __webpack_exports__ = {};
|
|
|
61
63
|
parseImageScripts: ()=>parseImageScripts,
|
|
62
64
|
extractAllDumpScriptsSync: ()=>extractAllDumpScriptsSync,
|
|
63
65
|
extractReportArtifactPathAsync: ()=>extractReportArtifactPathAsync,
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
66
|
+
streamInlineReportImages: ()=>streamInlineReportImages,
|
|
67
|
+
streamInlineReportImagesAsync: ()=>streamInlineReportImagesAsync,
|
|
68
|
+
streamScanTags: ()=>streamScanTags
|
|
67
69
|
});
|
|
68
70
|
var external_node_fs_ = __webpack_require__("node:fs");
|
|
69
71
|
const promises_namespaceObject = require("node:fs/promises");
|
|
@@ -192,7 +194,7 @@ var __webpack_exports__ = {};
|
|
|
192
194
|
const tagEnd = content.indexOf('>');
|
|
193
195
|
const type = content.slice(0, tagEnd).match(/(?:^|\s)type\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
194
196
|
return 'midscene_web_dump' === type ? visitor({
|
|
195
|
-
openTag: content.slice(0, tagEnd + 1)
|
|
197
|
+
openTag: `${String.fromCharCode(60)}script${content.slice(0, tagEnd + 1)}`,
|
|
196
198
|
content: content.slice(tagEnd + 1)
|
|
197
199
|
}) : false;
|
|
198
200
|
});
|
|
@@ -417,78 +419,61 @@ var __webpack_exports__ = {};
|
|
|
417
419
|
});
|
|
418
420
|
return results;
|
|
419
421
|
}
|
|
420
|
-
function streamDumpScriptsSync(filePath,
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
422
|
+
function streamDumpScriptsSync(filePath, visitor) {
|
|
423
|
+
streamScanTags(filePath, `${String.fromCharCode(60)}script`, htmlScriptCloseTag(), (content)=>{
|
|
424
|
+
const end = content.indexOf('>');
|
|
425
|
+
const type = content.slice(0, end).match(/(?:^|\s)type\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
426
|
+
return 'midscene_web_dump' === type ? visitor({
|
|
427
|
+
openTag: `${String.fromCharCode(60)}script${content.slice(0, end + 1)}`,
|
|
428
|
+
content: content.slice(end + 1)
|
|
429
|
+
}) : false;
|
|
430
|
+
});
|
|
431
|
+
}
|
|
432
|
+
function inlineImageElement(content) {
|
|
433
|
+
const end = content.indexOf('>');
|
|
434
|
+
const attributes = content.slice(0, end);
|
|
435
|
+
const type = attributes.match(/(?:^|\s)type\s*=\s*["']([^"']+)["']/i)?.[1];
|
|
436
|
+
const id = attributes.match(/(?:^|\s)data-id="([a-z0-9_-]{1,128})"/i)?.[1];
|
|
437
|
+
return 'midscene-image' === type && id ? {
|
|
438
|
+
id,
|
|
439
|
+
data: unescapeContent(content.slice(end + 1))
|
|
440
|
+
} : void 0;
|
|
441
|
+
}
|
|
442
|
+
function streamInlineReportImages(filePath, visit) {
|
|
443
|
+
streamScanTags(filePath, `${String.fromCharCode(60)}script`, htmlScriptCloseTag(), (content)=>{
|
|
444
|
+
const image = inlineImageElement(content);
|
|
445
|
+
return image ? visit(image.id, image.data) : false;
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
async function* streamInlineReportImagesAsync(filePath) {
|
|
449
|
+
const open = `${String.fromCharCode(60)}script`;
|
|
450
|
+
const close = htmlScriptCloseTag();
|
|
451
|
+
let pending = '';
|
|
428
452
|
let capturing = false;
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
const endIdx = chunk.indexOf(closeTag, searchStart);
|
|
439
|
-
if (-1 !== endIdx) {
|
|
440
|
-
currentContent += chunk.slice(searchStart, endIdx);
|
|
441
|
-
const shouldStop = onMatch({
|
|
442
|
-
openTag: currentOpenTag,
|
|
443
|
-
content: currentContent.trim()
|
|
444
|
-
});
|
|
445
|
-
if (shouldStop) return;
|
|
446
|
-
capturing = false;
|
|
447
|
-
currentContent = '';
|
|
448
|
-
currentOpenTag = '';
|
|
449
|
-
searchStart = endIdx + closeTag.length;
|
|
450
|
-
} else {
|
|
451
|
-
currentContent += chunk.slice(searchStart, -closeTag.length);
|
|
452
|
-
leftover = chunk.slice(-closeTag.length);
|
|
453
|
-
break;
|
|
454
|
-
}
|
|
455
|
-
} else {
|
|
456
|
-
const startIdx = chunk.indexOf(openTagPrefix, searchStart);
|
|
457
|
-
if (-1 !== startIdx) {
|
|
458
|
-
const tagEndIdx = chunk.indexOf('>', startIdx);
|
|
459
|
-
if (-1 !== tagEndIdx) {
|
|
460
|
-
capturing = true;
|
|
461
|
-
currentOpenTag = chunk.slice(startIdx, tagEndIdx + 1);
|
|
462
|
-
currentContent = chunk.slice(tagEndIdx + 1);
|
|
463
|
-
const endIdx = currentContent.indexOf(closeTag);
|
|
464
|
-
if (-1 !== endIdx) {
|
|
465
|
-
const shouldStop = onMatch({
|
|
466
|
-
openTag: currentOpenTag,
|
|
467
|
-
content: currentContent.slice(0, endIdx).trim()
|
|
468
|
-
});
|
|
469
|
-
if (shouldStop) return;
|
|
470
|
-
capturing = false;
|
|
471
|
-
currentContent = '';
|
|
472
|
-
currentOpenTag = '';
|
|
473
|
-
searchStart = tagEndIdx + 1 + endIdx + closeTag.length;
|
|
474
|
-
} else {
|
|
475
|
-
leftover = currentContent.slice(-closeTag.length);
|
|
476
|
-
currentContent = currentContent.slice(0, -closeTag.length);
|
|
477
|
-
break;
|
|
478
|
-
}
|
|
479
|
-
} else {
|
|
480
|
-
leftover = chunk.slice(startIdx);
|
|
481
|
-
break;
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
leftover = chunk.slice(-openTagPrefix.length);
|
|
453
|
+
for await (const chunk of (0, external_node_fs_.createReadStream)(filePath, {
|
|
454
|
+
encoding: 'utf8'
|
|
455
|
+
})){
|
|
456
|
+
pending += chunk;
|
|
457
|
+
while(true){
|
|
458
|
+
if (!capturing) {
|
|
459
|
+
const start = pending.indexOf(open);
|
|
460
|
+
if (start < 0) {
|
|
461
|
+
pending = pending.slice(-(open.length - 1));
|
|
485
462
|
break;
|
|
486
463
|
}
|
|
464
|
+
pending = pending.slice(start + open.length);
|
|
465
|
+
capturing = true;
|
|
487
466
|
}
|
|
467
|
+
const end = pending.indexOf(close);
|
|
468
|
+
if (end < 0) break;
|
|
469
|
+
const content = pending.slice(0, end);
|
|
470
|
+
pending = pending.slice(end + close.length);
|
|
471
|
+
capturing = false;
|
|
472
|
+
const image = inlineImageElement(content);
|
|
473
|
+
if (image) yield image;
|
|
488
474
|
}
|
|
489
|
-
} finally{
|
|
490
|
-
(0, external_node_fs_.closeSync)(fd);
|
|
491
475
|
}
|
|
476
|
+
if (capturing) throw new Error(`Unterminated report script in ${filePath}`);
|
|
492
477
|
}
|
|
493
478
|
function parseImageScripts(html) {
|
|
494
479
|
const imageMap = {};
|
|
@@ -566,6 +551,8 @@ exports.parseImageScripts = __webpack_exports__.parseImageScripts;
|
|
|
566
551
|
exports.streamDumpScriptsAsync = __webpack_exports__.streamDumpScriptsAsync;
|
|
567
552
|
exports.streamDumpScriptsSync = __webpack_exports__.streamDumpScriptsSync;
|
|
568
553
|
exports.streamImageScriptsToFile = __webpack_exports__.streamImageScriptsToFile;
|
|
554
|
+
exports.streamInlineReportImages = __webpack_exports__.streamInlineReportImages;
|
|
555
|
+
exports.streamInlineReportImagesAsync = __webpack_exports__.streamInlineReportImagesAsync;
|
|
569
556
|
exports.streamScanTags = __webpack_exports__.streamScanTags;
|
|
570
557
|
exports.streamScanTagsAsync = __webpack_exports__.streamScanTagsAsync;
|
|
571
558
|
exports.unescapeContent = __webpack_exports__.unescapeContent;
|
|
@@ -592,6 +579,8 @@ for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
|
592
579
|
"streamDumpScriptsAsync",
|
|
593
580
|
"streamDumpScriptsSync",
|
|
594
581
|
"streamImageScriptsToFile",
|
|
582
|
+
"streamInlineReportImages",
|
|
583
|
+
"streamInlineReportImagesAsync",
|
|
595
584
|
"streamScanTags",
|
|
596
585
|
"streamScanTagsAsync",
|
|
597
586
|
"unescapeContent"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dump/html-utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/html-utils.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { closeSync, openSync, readSync, statSync } from 'node:fs';\nimport { open as openAsync } from 'node:fs/promises';\nimport { StringDecoder } from 'node:string_decoder';\nimport {\n REPORT_ARTIFACT_SCRIPT_TYPE,\n assertReportArtifactPath,\n} from '@midscene/shared/report-artifact';\nimport { antiEscapeScriptTag, escapeScriptTag } from '@midscene/shared/utils';\nimport {\n TEST_RUN_REPORT_SCRIPT_TYPE,\n type TestRunReportDump,\n} from '../test-run-report';\nimport type { AIUsageInfo, IReportActionDump, ModelBrief } from '../types';\n\nexport const escapeContent = escapeScriptTag;\nexport const unescapeContent = antiEscapeScriptTag;\n\nfunction cleanHtmlCommentValue(value: unknown): string {\n return String(value ?? 'N/A')\n .replace(/\\0/g, '')\n .replace(/--/g, '- -');\n}\n\nfunction formatModelBriefForAgent(brief: ModelBrief): string {\n const intent = brief.intent || 'default';\n const model = brief.name || 'unknown';\n const description = brief.modelDescription\n ? ` (${brief.modelDescription})`\n : '';\n return `${intent}: ${model}${description}`;\n}\n\nfunction hasUsageModelInfo(usage?: AIUsageInfo): usage is AIUsageInfo {\n return Boolean(\n usage &&\n (usage.model_name ||\n usage.response_model_name ||\n usage.model_description ||\n usage.intent),\n );\n}\n\nfunction formatUsageModelForAgent(source: string, usage: AIUsageInfo): string {\n const intent = usage.intent || source;\n const model = usage.model_name || usage.response_model_name || 'unknown';\n const description = usage.model_description\n ? ` (${usage.model_description})`\n : '';\n return `${intent}: ${model}${description}`;\n}\n\nfunction collectUsageModelsForAgent(report: IReportActionDump): string {\n const models = new Map<string, string>();\n const executions = Array.isArray(report.executions) ? report.executions : [];\n for (const execution of executions) {\n const tasks = Array.isArray(execution.tasks) ? execution.tasks : [];\n for (const task of tasks) {\n const taskWithUsage = task as {\n usage?: AIUsageInfo;\n searchAreaUsage?: AIUsageInfo;\n };\n const usages: Array<[string, AIUsageInfo | undefined]> = [\n ['main', taskWithUsage.usage],\n ['searchArea', taskWithUsage.searchAreaUsage],\n ];\n\n for (const [source, usage] of usages) {\n if (!hasUsageModelInfo(usage)) {\n continue;\n }\n const formatted = formatUsageModelForAgent(source, usage);\n models.set(formatted, formatted);\n }\n }\n }\n\n return Array.from(models.values()).join('; ');\n}\n\nexport function generateAgentReportComment(report: IReportActionDump): string {\n const executions = Array.isArray(report.executions) ? report.executions : [];\n const taskCount = executions.reduce(\n (sum, execution) =>\n sum + (Array.isArray(execution.tasks) ? execution.tasks.length : 0),\n 0,\n );\n const modelBriefs = report.modelBriefs?.length\n ? report.modelBriefs.map(formatModelBriefForAgent).join('; ')\n : collectUsageModelsForAgent(report) || 'No model metadata recorded';\n\n const lines = [\n 'For Agent Analysis:',\n `Report: ${cleanHtmlCommentValue(report.groupName)}`,\n `SDK: ${cleanHtmlCommentValue(report.sdkVersion)}`,\n `Device: ${cleanHtmlCommentValue(report.deviceType)}`,\n `Executions: ${executions.length}; Tasks: ${taskCount}`,\n `Models: ${cleanHtmlCommentValue(modelBriefs)}`,\n 'Structured report JSON is stored in script[type=\"midscene_web_dump\"] tags near this comment.',\n 'Screenshots are stored as script[type=\"midscene-image\"] tags or files referenced by screenshot refs.',\n 'For AI analysis, inspect each execution task for type, status, timing, param, output, usage, searchAreaUsage, recorder, and screenshot refs.',\n 'Use the Markdown export when available; it contains the same report context plus image links for agent review.',\n ];\n\n return `\\n<!--\\n${lines.join('\\n')}\\n-->\\n`;\n}\n\nfunction htmlScriptCloseTag(): string {\n // biome-ignore lint/style/useTemplate: keep this token runtime-built for inline report bundles\n return String.fromCharCode(60) + '/script>';\n}\n\n/** Directory reports declare their data entry separately from the Viewer. */\nexport function generateReportArtifactScriptTag(path: string): string {\n assertReportArtifactPath(path);\n return [\n String.fromCharCode(60),\n 'script type=\"',\n REPORT_ARTIFACT_SCRIPT_TYPE,\n '\">',\n JSON.stringify(path),\n htmlScriptCloseTag(),\n ].join('');\n}\n\nfunction reportArtifactPathExtractor(filePath: string) {\n let result: string | undefined;\n return {\n get path() {\n return result;\n },\n visit: (content: string) => {\n const tagEnd = content.indexOf('>');\n const type = content\n .slice(0, tagEnd)\n .match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n if (type !== REPORT_ARTIFACT_SCRIPT_TYPE) return false;\n if (result !== undefined)\n throw new Error(\n `Report contains multiple artifact entries: ${filePath}`,\n );\n const path: unknown = JSON.parse(\n unescapeContent(content.slice(tagEnd + 1)),\n );\n assertReportArtifactPath(path);\n result = path;\n return false;\n },\n };\n}\n\nexport function extractReportArtifactPathSync(\n filePath: string,\n): string | undefined {\n const extractor = reportArtifactPathExtractor(filePath);\n streamScanTags(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n extractor.visit,\n );\n return extractor.path;\n}\n\nexport async function extractReportArtifactPathAsync(\n filePath: string,\n): Promise<string | undefined> {\n const extractor = reportArtifactPathExtractor(filePath);\n await streamScanTagsAsync(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n extractor.visit,\n );\n return extractor.path;\n}\n\n/** Consume complete elements so dump-tag strings in the Viewer are never payloads. */\nexport async function streamDumpScriptsAsync(\n filePath: string,\n visitor: (dump: { openTag: string; content: string }) => boolean,\n): Promise<void> {\n await streamScanTagsAsync(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n (content) => {\n const tagEnd = content.indexOf('>');\n const type = content\n .slice(0, tagEnd)\n .match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n return type === 'midscene_web_dump'\n ? visitor({\n openTag: content.slice(0, tagEnd + 1),\n content: content.slice(tagEnd + 1),\n })\n : false;\n },\n );\n}\n\n/** Avoid raw close tokens: this writer itself is bundled into report HTML. */\nexport function generateTestRunReportScriptTag(\n dump: TestRunReportDump,\n): string {\n return [\n String.fromCharCode(60),\n 'script type=\"',\n TEST_RUN_REPORT_SCRIPT_TYPE,\n '\">\\n',\n escapeScriptTag(JSON.stringify(dump)),\n '\\n',\n htmlScriptCloseTag(),\n '\\n',\n ].join('');\n}\n\nexport function extractTestRunReportDumpSync(\n filePath: string,\n): TestRunReportDump | undefined {\n let result: TestRunReportDump | undefined;\n // Consume executable scripts as whole elements: the embedded viewer itself\n // contains report-writer source with data-tag strings that are not payloads.\n const openTag = `${String.fromCharCode(60)}script`;\n streamScanTags(filePath, openTag, htmlScriptCloseTag(), (content) => {\n const tagEnd = content.indexOf('>');\n const attributes = content.slice(0, tagEnd);\n const type = attributes.match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n if (type !== TEST_RUN_REPORT_SCRIPT_TYPE) return false;\n if (result)\n throw new Error(\n `Report contains multiple Midscene Test dumps: ${filePath}`,\n );\n const parsed = JSON.parse(unescapeContent(content.slice(tagEnd + 1)));\n if (\n parsed?.schemaVersion !== 1 ||\n parsed?.kind !== 'test-runner' ||\n !Array.isArray(parsed.projects)\n )\n throw new Error(`Invalid Midscene Test report dump: ${filePath}`);\n result = parsed;\n return false;\n });\n return result;\n}\n\n/** Chunk size for streaming file operations (64KB) */\nexport const STREAMING_CHUNK_SIZE = 64 * 1024;\n\n/**\n * Callback for processing matched tags during streaming.\n * @param content - The content between open and close tags\n * @returns true to stop scanning, false to continue\n */\ntype TagMatchCallback = (content: string) => boolean;\n\nclass StreamingTagMatcher {\n private leftover = '';\n private capturing = false;\n private currentContent = '';\n\n constructor(\n private readonly openTag: string,\n private readonly closeTag: string,\n private readonly onMatch: TagMatchCallback,\n ) {}\n\n push(nextChunk: string): boolean {\n const chunk = this.leftover + nextChunk;\n this.leftover = '';\n let searchStart = 0;\n\n while (searchStart < chunk.length) {\n if (!this.capturing) {\n const startIndex = chunk.indexOf(this.openTag, searchStart);\n if (startIndex === -1) {\n const retainedSuffixLength = Math.max(0, this.openTag.length - 1);\n this.leftover = retainedSuffixLength\n ? chunk.slice(-retainedSuffixLength)\n : '';\n return false;\n }\n this.capturing = true;\n searchStart = startIndex + this.openTag.length;\n }\n\n const endIndex = chunk.indexOf(this.closeTag, searchStart);\n if (endIndex !== -1) {\n this.currentContent += chunk.slice(searchStart, endIndex);\n if (this.onMatch(this.currentContent)) return true;\n this.capturing = false;\n this.currentContent = '';\n searchStart = endIndex + this.closeTag.length;\n continue;\n }\n\n const retainedSuffixLength = Math.max(0, this.closeTag.length - 1);\n const contentEnd = Math.max(\n searchStart,\n chunk.length - retainedSuffixLength,\n );\n this.currentContent += chunk.slice(searchStart, contentEnd);\n this.leftover = chunk.slice(contentEnd);\n return false;\n }\n\n return false;\n }\n}\n\n/**\n * Stream through a file and find tags matching the pattern.\n * Memory usage: O(chunk_size + tag_size), not O(file_size).\n *\n * @param filePath - Absolute path to the file\n * @param openTag - Opening tag to search for\n * @param closeTag - Closing tag\n * @param onMatch - Callback for each matched tag content\n */\nexport function streamScanTags(\n filePath: string,\n openTag: string,\n closeTag: string,\n onMatch: TagMatchCallback,\n): void {\n const fd = openSync(filePath, 'r');\n const fileSize = statSync(filePath).size;\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n const decoder = new StringDecoder('utf8');\n const matcher = new StreamingTagMatcher(openTag, closeTag, onMatch);\n let position = 0;\n\n try {\n while (position < fileSize) {\n const bytesRead = readSync(fd, buffer, 0, STREAMING_CHUNK_SIZE, position);\n position += bytesRead;\n if (matcher.push(decoder.write(buffer.subarray(0, bytesRead)))) return;\n }\n matcher.push(decoder.end());\n } finally {\n closeSync(fd);\n }\n}\n\n/** Asynchronously stream tags without blocking the Node.js event loop. */\nexport async function streamScanTagsAsync(\n filePath: string,\n openTag: string,\n closeTag: string,\n onMatch: TagMatchCallback,\n): Promise<void> {\n const handle = await openAsync(filePath, 'r');\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n const decoder = new StringDecoder('utf8');\n let position = 0;\n const matcher = new StreamingTagMatcher(openTag, closeTag, onMatch);\n\n try {\n while (true) {\n const { bytesRead } = await handle.read(\n buffer,\n 0,\n STREAMING_CHUNK_SIZE,\n position,\n );\n if (bytesRead === 0) {\n matcher.push(decoder.end());\n return;\n }\n position += bytesRead;\n if (matcher.push(decoder.write(buffer.subarray(0, bytesRead)))) return;\n }\n } finally {\n await handle.close();\n }\n}\n\n/**\n * Synchronously extract a specific image's base64 data from an HTML file by its id.\n * Uses streaming to avoid loading the entire file into memory.\n *\n * @param htmlPath - Absolute path to the HTML file\n * @param imageId - The id of the image to extract\n * @returns The base64 data string, or null if not found\n */\nexport function extractImageByIdSync(\n htmlPath: string,\n imageId: string,\n): string | null {\n const targetTag = `<script type=\"midscene-image\" data-id=\"${imageId}\">`;\n const closeTag = htmlScriptCloseTag();\n\n let result: string | null = null;\n\n streamScanTags(htmlPath, targetTag, closeTag, (content) => {\n result = unescapeContent(content);\n return true; // Stop after first match\n });\n\n return result;\n}\n\n/**\n * Stream image script tags from source file directly to output file.\n * Memory usage: O(single_image_size), not O(all_images_size).\n *\n * @param srcFilePath - Source HTML file path\n * @param destFilePath - Destination file path to append to\n * @param writtenImageIds - IDs already written to the destination\n */\nexport function streamImageScriptsToFile(\n srcFilePath: string,\n destFilePath: string,\n writtenImageIds: Set<string> = new Set(),\n): void {\n const { appendFileSync } = require('node:fs');\n const openTag = '<script type=\"midscene-image\"';\n const closeTag = htmlScriptCloseTag();\n\n streamScanTags(srcFilePath, openTag, closeTag, (content) => {\n const imageId = parseImageScriptId(content);\n if (!imageId || writtenImageIds.has(imageId)) {\n return false;\n }\n // Write complete tag immediately to destination, don't accumulate\n appendFileSync(destFilePath, `${openTag}${content}${closeTag}\\n`);\n writtenImageIds.add(imageId);\n return false; // Continue scanning for more tags\n });\n}\n\nfunction parseImageScriptId(contentAfterType: string): string | null {\n const match = /^ data-id=\"([a-z0-9_-]{1,128})\">/i.exec(contentAfterType);\n return match?.[1] ?? null;\n}\n\n/** Collect IDs of real inline image script tags without blocking on a large report. */\nexport async function collectImageScriptIds(\n filePath: string,\n): Promise<Set<string>> {\n const imageIds = new Set<string>();\n const openTag = '<script type=\"midscene-image\"';\n const closeTag = htmlScriptCloseTag();\n\n await streamScanTagsAsync(filePath, openTag, closeTag, (content) => {\n const imageId = parseImageScriptId(content);\n if (imageId) imageIds.add(imageId);\n return false;\n });\n return imageIds;\n}\n\n/**\n * Extract the LAST dump script content from HTML file using streaming.\n * Memory usage: O(dump_size), not O(file_size).\n *\n * @param filePath - Absolute path to the HTML file\n * @returns The dump script content (trimmed), or empty string if not found\n */\nexport function extractLastDumpScriptSync(filePath: string): string {\n const openTagPrefix = '<script type=\"midscene_web_dump\"';\n const closeTag = htmlScriptCloseTag();\n\n let lastContent = '';\n\n // Custom streaming to handle the special case where open tag has variable attributes\n const fd = openSync(filePath, 'r');\n const fileSize = statSync(filePath).size;\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n\n let position = 0;\n let leftover = '';\n let capturing = false;\n let currentContent = '';\n\n try {\n while (position < fileSize) {\n const bytesRead = readSync(fd, buffer, 0, STREAMING_CHUNK_SIZE, position);\n const chunk = leftover + buffer.toString('utf-8', 0, bytesRead);\n position += bytesRead;\n\n let searchStart = 0;\n\n while (searchStart < chunk.length) {\n if (!capturing) {\n const startIdx = chunk.indexOf(openTagPrefix, searchStart);\n if (startIdx !== -1) {\n // Find the end of the opening tag (the '>' character)\n const tagEndIdx = chunk.indexOf('>', startIdx);\n if (tagEndIdx !== -1) {\n capturing = true;\n currentContent = chunk.slice(tagEndIdx + 1);\n const endIdx = currentContent.indexOf(closeTag);\n if (endIdx !== -1) {\n lastContent = currentContent.slice(0, endIdx).trim();\n capturing = false;\n currentContent = '';\n searchStart = tagEndIdx + 1 + endIdx + closeTag.length;\n } else {\n leftover = currentContent.slice(-closeTag.length);\n currentContent = currentContent.slice(0, -closeTag.length);\n break;\n }\n } else {\n leftover = chunk.slice(startIdx);\n break;\n }\n } else {\n leftover = chunk.slice(-openTagPrefix.length);\n break;\n }\n } else {\n const endIdx = chunk.indexOf(closeTag, searchStart);\n if (endIdx !== -1) {\n currentContent += chunk.slice(searchStart, endIdx);\n lastContent = currentContent.trim();\n capturing = false;\n currentContent = '';\n searchStart = endIdx + closeTag.length;\n } else {\n currentContent += chunk.slice(searchStart, -closeTag.length);\n leftover = chunk.slice(-closeTag.length);\n break;\n }\n }\n }\n }\n } finally {\n closeSync(fd);\n }\n\n return lastContent;\n}\n\n/**\n * Extract ALL dump script contents from an HTML file using streaming.\n * Each entry includes the full opening tag (for attribute extraction) and the content.\n *\n * @param filePath - Absolute path to the HTML file\n * @returns Array of { openTag, content } for each dump script found\n */\nexport function extractAllDumpScriptsSync(\n filePath: string,\n): { openTag: string; content: string }[] {\n const results: { openTag: string; content: string }[] = [];\n streamDumpScriptsSync(filePath, (dumpScript) => {\n results.push(dumpScript);\n return false;\n });\n return results;\n}\n\n/**\n * Stream ALL dump scripts from an HTML file.\n * Calls onMatch for each dump script and keeps memory bounded to a single\n * dump script payload instead of accumulating every dump in memory.\n *\n * @param filePath - Absolute path to the HTML file\n * @param onMatch - Callback for each dump script; return true to stop early\n */\nexport function streamDumpScriptsSync(\n filePath: string,\n onMatch: (dumpScript: { openTag: string; content: string }) => boolean,\n): void {\n const openTagPrefix = '<script type=\"midscene_web_dump\"';\n const closeTag = htmlScriptCloseTag();\n\n const fd = openSync(filePath, 'r');\n const fileSize = statSync(filePath).size;\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n\n let position = 0;\n let leftover = '';\n let capturing = false;\n let currentContent = '';\n let currentOpenTag = '';\n\n try {\n while (position < fileSize) {\n const bytesRead = readSync(fd, buffer, 0, STREAMING_CHUNK_SIZE, position);\n const chunk = leftover + buffer.toString('utf-8', 0, bytesRead);\n position += bytesRead;\n\n let searchStart = 0;\n\n while (searchStart < chunk.length) {\n if (!capturing) {\n const startIdx = chunk.indexOf(openTagPrefix, searchStart);\n if (startIdx !== -1) {\n const tagEndIdx = chunk.indexOf('>', startIdx);\n if (tagEndIdx !== -1) {\n capturing = true;\n currentOpenTag = chunk.slice(startIdx, tagEndIdx + 1);\n currentContent = chunk.slice(tagEndIdx + 1);\n const endIdx = currentContent.indexOf(closeTag);\n if (endIdx !== -1) {\n const shouldStop = onMatch({\n openTag: currentOpenTag,\n content: currentContent.slice(0, endIdx).trim(),\n });\n if (shouldStop) return;\n capturing = false;\n currentContent = '';\n currentOpenTag = '';\n searchStart = tagEndIdx + 1 + endIdx + closeTag.length;\n } else {\n leftover = currentContent.slice(-closeTag.length);\n currentContent = currentContent.slice(0, -closeTag.length);\n break;\n }\n } else {\n leftover = chunk.slice(startIdx);\n break;\n }\n } else {\n leftover = chunk.slice(-openTagPrefix.length);\n break;\n }\n } else {\n const endIdx = chunk.indexOf(closeTag, searchStart);\n if (endIdx !== -1) {\n currentContent += chunk.slice(searchStart, endIdx);\n const shouldStop = onMatch({\n openTag: currentOpenTag,\n content: currentContent.trim(),\n });\n if (shouldStop) return;\n capturing = false;\n currentContent = '';\n currentOpenTag = '';\n searchStart = endIdx + closeTag.length;\n } else {\n currentContent += chunk.slice(searchStart, -closeTag.length);\n leftover = chunk.slice(-closeTag.length);\n break;\n }\n }\n }\n }\n } finally {\n closeSync(fd);\n }\n}\n\nexport function parseImageScripts(html: string): Record<string, string> {\n const imageMap: Record<string, string> = {};\n const regex =\n /<script type=\"midscene-image\" data-id=\"([^\"]+)\">([\\s\\S]*?)<\\/script>/g;\n\n for (const match of html.matchAll(regex)) {\n const [, id, content] = match;\n imageMap[id] = unescapeContent(content);\n }\n\n return imageMap;\n}\n\nexport function parseDumpScript(html: string): string {\n // Use string search instead of regex to avoid ReDoS vulnerability\n // Find the LAST dump script tag (template may contain similar patterns in bundled JS)\n const scriptOpenTag = '<script type=\"midscene_web_dump\"';\n const closeTag = htmlScriptCloseTag();\n\n // Find the last occurrence of the opening tag\n const lastOpenIndex = html.lastIndexOf(scriptOpenTag);\n if (lastOpenIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Find the end of the opening tag (the '>' character)\n const tagEndIndex = html.indexOf('>', lastOpenIndex);\n if (tagEndIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Find the closing tag after the opening tag\n const closeIndex = html.indexOf(closeTag, tagEndIndex);\n if (closeIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Extract content between opening and closing tags\n const content = html.substring(tagEndIndex + 1, closeIndex);\n return unescapeContent(content);\n}\n\nexport function parseDumpScriptAttributes(\n html: string,\n): Record<string, string> {\n const regex = /<script type=\"midscene_web_dump\"([^>]*)>/;\n const match = regex.exec(html);\n\n if (!match) {\n return {};\n }\n\n const attrString = match[1];\n const attributes: Record<string, string> = {};\n const attrRegex = /(\\w+)=\"([^\"]*)\"/g;\n\n for (const attrMatch of attrString.matchAll(attrRegex)) {\n const [, key, value] = attrMatch;\n if (key !== 'type') {\n attributes[key] = decodeURIComponent(value);\n }\n }\n\n return attributes;\n}\n\nexport function generateImageScriptTag(id: string, data: string): string {\n // Do not use template string here, will cause bundle error with <script\n const closeTag = htmlScriptCloseTag();\n return (\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene-image\" data-id=\"' +\n id +\n '\">' +\n escapeContent(data) +\n closeTag\n );\n}\n\n/**\n * Inline script that fixes relative URL resolution for directory-mode reports.\n *\n * Problem: when a static server (e.g. `npx serve`) serves `name/index.html`\n * at URL `/name` (without trailing slash), relative paths like\n * `./screenshots/xxx.png` resolve to `/screenshots/xxx.png` instead of\n * `/name/screenshots/xxx.png`.\n *\n * Fix: dynamically insert a <base> tag so relative URLs resolve correctly.\n */\n// Do not use template string here, will cause bundle error with <script\n//\n// The closing script tag is built at runtime so bundlers cannot inline the\n// token that would prematurely close the report template's inline app bundle.\n//\n// Do NOT replace this with a string constant, hex escape (\\x3c), or literal\n// string concatenation. Bundlers may optimise those forms back to the unsafe\n// token.\nlet _baseUrlFixScript: string;\nexport function getBaseUrlFixScript(): string {\n if (!_baseUrlFixScript) {\n const close = htmlScriptCloseTag();\n _baseUrlFixScript =\n // biome-ignore lint/style/useTemplate: see above\n '\\n<script>(function(){' +\n 'var p=window.location.pathname;' +\n 'if(p.endsWith(\"/\")||/\\\\.\\\\w+$/.test(p))return;' +\n 'var b=document.createElement(\"base\");' +\n 'b.href=p+\"/\";' +\n 'document.head.insertBefore(b,document.head.firstChild)' +\n '})()' +\n close +\n '\\n';\n }\n return _baseUrlFixScript;\n}\n\n/**\n * Dump-script attribute that records how the report file stores screenshots.\n * Written by the report generator and the merger, read back when deciding\n * whether a report is in directory mode. Kept here, next to dump-tag\n * generation, so the writer and reader share one source of truth.\n */\nexport const DATA_SCREENSHOT_MODE_ATTR = 'data-screenshot-mode';\n\nexport function generateDumpScriptTag(\n json: string,\n attributes?: Record<string, string | number | boolean>,\n): string {\n const closeTag = htmlScriptCloseTag();\n let attrString = '';\n if (attributes && Object.keys(attributes).length > 0) {\n // Do not use template string here, will cause bundle error with <script\n attrString =\n // biome-ignore lint/style/useTemplate: <explanation>\n ' ' +\n Object.entries(attributes)\n // biome-ignore lint/style/useTemplate: <explanation>\n .map(([k, v]) => k + '=\"' + encodeURIComponent(v) + '\"')\n .join(' ');\n }\n\n // Do not use template string here, will cause bundle error with <script\n return (\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\"' +\n attrString +\n '>' +\n escapeContent(json) +\n closeTag\n );\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","escapeContent","escapeScriptTag","unescapeContent","antiEscapeScriptTag","cleanHtmlCommentValue","value","String","formatModelBriefForAgent","brief","intent","model","description","hasUsageModelInfo","usage","Boolean","formatUsageModelForAgent","source","collectUsageModelsForAgent","report","models","Map","executions","Array","execution","tasks","task","taskWithUsage","usages","formatted","generateAgentReportComment","taskCount","sum","modelBriefs","lines","htmlScriptCloseTag","generateReportArtifactScriptTag","path","assertReportArtifactPath","REPORT_ARTIFACT_SCRIPT_TYPE","JSON","reportArtifactPathExtractor","filePath","result","content","tagEnd","type","undefined","Error","extractReportArtifactPathSync","extractor","streamScanTags","extractReportArtifactPathAsync","streamScanTagsAsync","streamDumpScriptsAsync","visitor","generateTestRunReportScriptTag","dump","TEST_RUN_REPORT_SCRIPT_TYPE","extractTestRunReportDumpSync","openTag","attributes","parsed","STREAMING_CHUNK_SIZE","StreamingTagMatcher","nextChunk","chunk","searchStart","startIndex","retainedSuffixLength","Math","endIndex","contentEnd","closeTag","onMatch","fd","openSync","fileSize","statSync","buffer","Buffer","decoder","StringDecoder","matcher","position","bytesRead","readSync","closeSync","handle","openAsync","extractImageByIdSync","htmlPath","imageId","targetTag","streamImageScriptsToFile","srcFilePath","destFilePath","writtenImageIds","Set","appendFileSync","require","parseImageScriptId","contentAfterType","match","collectImageScriptIds","imageIds","extractLastDumpScriptSync","openTagPrefix","lastContent","leftover","capturing","currentContent","endIdx","startIdx","tagEndIdx","extractAllDumpScriptsSync","results","streamDumpScriptsSync","dumpScript","currentOpenTag","shouldStop","parseImageScripts","html","imageMap","regex","id","parseDumpScript","scriptOpenTag","lastOpenIndex","tagEndIndex","closeIndex","parseDumpScriptAttributes","attrString","attrRegex","attrMatch","decodeURIComponent","generateImageScriptTag","data","_baseUrlFixScript","getBaseUrlFixScript","close","DATA_SCREENSHOT_MODE_ATTR","generateDumpScriptTag","json","k","v","encodeURIComponent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dump/html-utils.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/html-utils.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import {\n closeSync,\n createReadStream,\n openSync,\n readSync,\n statSync,\n} from 'node:fs';\nimport { open as openAsync } from 'node:fs/promises';\nimport { StringDecoder } from 'node:string_decoder';\nimport {\n REPORT_ARTIFACT_SCRIPT_TYPE,\n assertReportArtifactPath,\n} from '@midscene/shared/report-artifact';\nimport { antiEscapeScriptTag, escapeScriptTag } from '@midscene/shared/utils';\nimport {\n TEST_RUN_REPORT_SCRIPT_TYPE,\n type TestRunReportDump,\n} from '../test-run-report';\nimport type { AIUsageInfo, IReportActionDump, ModelBrief } from '../types';\n\nexport const escapeContent = escapeScriptTag;\nexport const unescapeContent = antiEscapeScriptTag;\n\nfunction cleanHtmlCommentValue(value: unknown): string {\n return String(value ?? 'N/A')\n .replace(/\\0/g, '')\n .replace(/--/g, '- -');\n}\n\nfunction formatModelBriefForAgent(brief: ModelBrief): string {\n const intent = brief.intent || 'default';\n const model = brief.name || 'unknown';\n const description = brief.modelDescription\n ? ` (${brief.modelDescription})`\n : '';\n return `${intent}: ${model}${description}`;\n}\n\nfunction hasUsageModelInfo(usage?: AIUsageInfo): usage is AIUsageInfo {\n return Boolean(\n usage &&\n (usage.model_name ||\n usage.response_model_name ||\n usage.model_description ||\n usage.intent),\n );\n}\n\nfunction formatUsageModelForAgent(source: string, usage: AIUsageInfo): string {\n const intent = usage.intent || source;\n const model = usage.model_name || usage.response_model_name || 'unknown';\n const description = usage.model_description\n ? ` (${usage.model_description})`\n : '';\n return `${intent}: ${model}${description}`;\n}\n\nfunction collectUsageModelsForAgent(report: IReportActionDump): string {\n const models = new Map<string, string>();\n const executions = Array.isArray(report.executions) ? report.executions : [];\n for (const execution of executions) {\n const tasks = Array.isArray(execution.tasks) ? execution.tasks : [];\n for (const task of tasks) {\n const taskWithUsage = task as {\n usage?: AIUsageInfo;\n searchAreaUsage?: AIUsageInfo;\n };\n const usages: Array<[string, AIUsageInfo | undefined]> = [\n ['main', taskWithUsage.usage],\n ['searchArea', taskWithUsage.searchAreaUsage],\n ];\n\n for (const [source, usage] of usages) {\n if (!hasUsageModelInfo(usage)) {\n continue;\n }\n const formatted = formatUsageModelForAgent(source, usage);\n models.set(formatted, formatted);\n }\n }\n }\n\n return Array.from(models.values()).join('; ');\n}\n\nexport function generateAgentReportComment(report: IReportActionDump): string {\n const executions = Array.isArray(report.executions) ? report.executions : [];\n const taskCount = executions.reduce(\n (sum, execution) =>\n sum + (Array.isArray(execution.tasks) ? execution.tasks.length : 0),\n 0,\n );\n const modelBriefs = report.modelBriefs?.length\n ? report.modelBriefs.map(formatModelBriefForAgent).join('; ')\n : collectUsageModelsForAgent(report) || 'No model metadata recorded';\n\n const lines = [\n 'For Agent Analysis:',\n `Report: ${cleanHtmlCommentValue(report.groupName)}`,\n `SDK: ${cleanHtmlCommentValue(report.sdkVersion)}`,\n `Device: ${cleanHtmlCommentValue(report.deviceType)}`,\n `Executions: ${executions.length}; Tasks: ${taskCount}`,\n `Models: ${cleanHtmlCommentValue(modelBriefs)}`,\n 'Structured report JSON is stored in script[type=\"midscene_web_dump\"] tags near this comment.',\n 'Screenshots are stored as script[type=\"midscene-image\"] tags or files referenced by screenshot refs.',\n 'For AI analysis, inspect each execution task for type, status, timing, param, output, usage, searchAreaUsage, recorder, and screenshot refs.',\n 'Use the Markdown export when available; it contains the same report context plus image links for agent review.',\n ];\n\n return `\\n<!--\\n${lines.join('\\n')}\\n-->\\n`;\n}\n\nfunction htmlScriptCloseTag(): string {\n // biome-ignore lint/style/useTemplate: keep this token runtime-built for inline report bundles\n return String.fromCharCode(60) + '/script>';\n}\n\n/** Directory reports declare their data entry separately from the Viewer. */\nexport function generateReportArtifactScriptTag(path: string): string {\n assertReportArtifactPath(path);\n return [\n String.fromCharCode(60),\n 'script type=\"',\n REPORT_ARTIFACT_SCRIPT_TYPE,\n '\">',\n JSON.stringify(path),\n htmlScriptCloseTag(),\n ].join('');\n}\n\nfunction reportArtifactPathExtractor(filePath: string) {\n let result: string | undefined;\n return {\n get path() {\n return result;\n },\n visit: (content: string) => {\n const tagEnd = content.indexOf('>');\n const type = content\n .slice(0, tagEnd)\n .match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n if (type !== REPORT_ARTIFACT_SCRIPT_TYPE) return false;\n if (result !== undefined)\n throw new Error(\n `Report contains multiple artifact entries: ${filePath}`,\n );\n const path: unknown = JSON.parse(\n unescapeContent(content.slice(tagEnd + 1)),\n );\n assertReportArtifactPath(path);\n result = path;\n return false;\n },\n };\n}\n\nexport function extractReportArtifactPathSync(\n filePath: string,\n): string | undefined {\n const extractor = reportArtifactPathExtractor(filePath);\n streamScanTags(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n extractor.visit,\n );\n return extractor.path;\n}\n\nexport async function extractReportArtifactPathAsync(\n filePath: string,\n): Promise<string | undefined> {\n const extractor = reportArtifactPathExtractor(filePath);\n await streamScanTagsAsync(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n extractor.visit,\n );\n return extractor.path;\n}\n\n/** Consume complete elements so dump-tag strings in the Viewer are never payloads. */\nexport async function streamDumpScriptsAsync(\n filePath: string,\n visitor: (dump: { openTag: string; content: string }) => boolean,\n): Promise<void> {\n await streamScanTagsAsync(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n (content) => {\n const tagEnd = content.indexOf('>');\n const type = content\n .slice(0, tagEnd)\n .match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n return type === 'midscene_web_dump'\n ? visitor({\n openTag: `${String.fromCharCode(60)}script${content.slice(0, tagEnd + 1)}`,\n content: content.slice(tagEnd + 1),\n })\n : false;\n },\n );\n}\n\n/** Avoid raw close tokens: this writer itself is bundled into report HTML. */\nexport function generateTestRunReportScriptTag(\n dump: TestRunReportDump,\n): string {\n return [\n String.fromCharCode(60),\n 'script type=\"',\n TEST_RUN_REPORT_SCRIPT_TYPE,\n '\">\\n',\n escapeScriptTag(JSON.stringify(dump)),\n '\\n',\n htmlScriptCloseTag(),\n '\\n',\n ].join('');\n}\n\nexport function extractTestRunReportDumpSync(\n filePath: string,\n): TestRunReportDump | undefined {\n let result: TestRunReportDump | undefined;\n // Consume executable scripts as whole elements: the embedded viewer itself\n // contains report-writer source with data-tag strings that are not payloads.\n const openTag = `${String.fromCharCode(60)}script`;\n streamScanTags(filePath, openTag, htmlScriptCloseTag(), (content) => {\n const tagEnd = content.indexOf('>');\n const attributes = content.slice(0, tagEnd);\n const type = attributes.match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n if (type !== TEST_RUN_REPORT_SCRIPT_TYPE) return false;\n if (result)\n throw new Error(\n `Report contains multiple Midscene Test dumps: ${filePath}`,\n );\n const parsed = JSON.parse(unescapeContent(content.slice(tagEnd + 1)));\n if (\n parsed?.schemaVersion !== 1 ||\n parsed?.kind !== 'test-runner' ||\n !Array.isArray(parsed.projects)\n )\n throw new Error(`Invalid Midscene Test report dump: ${filePath}`);\n result = parsed;\n return false;\n });\n return result;\n}\n\n/** Chunk size for streaming file operations (64KB) */\nexport const STREAMING_CHUNK_SIZE = 64 * 1024;\n\n/**\n * Callback for processing matched tags during streaming.\n * @param content - The content between open and close tags\n * @returns true to stop scanning, false to continue\n */\ntype TagMatchCallback = (content: string) => boolean;\n\nclass StreamingTagMatcher {\n private leftover = '';\n private capturing = false;\n private currentContent = '';\n\n constructor(\n private readonly openTag: string,\n private readonly closeTag: string,\n private readonly onMatch: TagMatchCallback,\n ) {}\n\n push(nextChunk: string): boolean {\n const chunk = this.leftover + nextChunk;\n this.leftover = '';\n let searchStart = 0;\n\n while (searchStart < chunk.length) {\n if (!this.capturing) {\n const startIndex = chunk.indexOf(this.openTag, searchStart);\n if (startIndex === -1) {\n const retainedSuffixLength = Math.max(0, this.openTag.length - 1);\n this.leftover = retainedSuffixLength\n ? chunk.slice(-retainedSuffixLength)\n : '';\n return false;\n }\n this.capturing = true;\n searchStart = startIndex + this.openTag.length;\n }\n\n const endIndex = chunk.indexOf(this.closeTag, searchStart);\n if (endIndex !== -1) {\n this.currentContent += chunk.slice(searchStart, endIndex);\n if (this.onMatch(this.currentContent)) return true;\n this.capturing = false;\n this.currentContent = '';\n searchStart = endIndex + this.closeTag.length;\n continue;\n }\n\n const retainedSuffixLength = Math.max(0, this.closeTag.length - 1);\n const contentEnd = Math.max(\n searchStart,\n chunk.length - retainedSuffixLength,\n );\n this.currentContent += chunk.slice(searchStart, contentEnd);\n this.leftover = chunk.slice(contentEnd);\n return false;\n }\n\n return false;\n }\n}\n\n/**\n * Stream through a file and find tags matching the pattern.\n * Memory usage: O(chunk_size + tag_size), not O(file_size).\n *\n * @param filePath - Absolute path to the file\n * @param openTag - Opening tag to search for\n * @param closeTag - Closing tag\n * @param onMatch - Callback for each matched tag content\n */\nexport function streamScanTags(\n filePath: string,\n openTag: string,\n closeTag: string,\n onMatch: TagMatchCallback,\n): void {\n const fd = openSync(filePath, 'r');\n const fileSize = statSync(filePath).size;\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n const decoder = new StringDecoder('utf8');\n const matcher = new StreamingTagMatcher(openTag, closeTag, onMatch);\n let position = 0;\n\n try {\n while (position < fileSize) {\n const bytesRead = readSync(fd, buffer, 0, STREAMING_CHUNK_SIZE, position);\n position += bytesRead;\n if (matcher.push(decoder.write(buffer.subarray(0, bytesRead)))) return;\n }\n matcher.push(decoder.end());\n } finally {\n closeSync(fd);\n }\n}\n\n/** Asynchronously stream tags without blocking the Node.js event loop. */\nexport async function streamScanTagsAsync(\n filePath: string,\n openTag: string,\n closeTag: string,\n onMatch: TagMatchCallback,\n): Promise<void> {\n const handle = await openAsync(filePath, 'r');\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n const decoder = new StringDecoder('utf8');\n let position = 0;\n const matcher = new StreamingTagMatcher(openTag, closeTag, onMatch);\n\n try {\n while (true) {\n const { bytesRead } = await handle.read(\n buffer,\n 0,\n STREAMING_CHUNK_SIZE,\n position,\n );\n if (bytesRead === 0) {\n matcher.push(decoder.end());\n return;\n }\n position += bytesRead;\n if (matcher.push(decoder.write(buffer.subarray(0, bytesRead)))) return;\n }\n } finally {\n await handle.close();\n }\n}\n\n/**\n * Synchronously extract a specific image's base64 data from an HTML file by its id.\n * Uses streaming to avoid loading the entire file into memory.\n *\n * @param htmlPath - Absolute path to the HTML file\n * @param imageId - The id of the image to extract\n * @returns The base64 data string, or null if not found\n */\nexport function extractImageByIdSync(\n htmlPath: string,\n imageId: string,\n): string | null {\n const targetTag = `<script type=\"midscene-image\" data-id=\"${imageId}\">`;\n const closeTag = htmlScriptCloseTag();\n\n let result: string | null = null;\n\n streamScanTags(htmlPath, targetTag, closeTag, (content) => {\n result = unescapeContent(content);\n return true; // Stop after first match\n });\n\n return result;\n}\n\n/**\n * Stream image script tags from source file directly to output file.\n * Memory usage: O(single_image_size), not O(all_images_size).\n *\n * @param srcFilePath - Source HTML file path\n * @param destFilePath - Destination file path to append to\n * @param writtenImageIds - IDs already written to the destination\n */\nexport function streamImageScriptsToFile(\n srcFilePath: string,\n destFilePath: string,\n writtenImageIds: Set<string> = new Set(),\n): void {\n const { appendFileSync } = require('node:fs');\n const openTag = '<script type=\"midscene-image\"';\n const closeTag = htmlScriptCloseTag();\n\n streamScanTags(srcFilePath, openTag, closeTag, (content) => {\n const imageId = parseImageScriptId(content);\n if (!imageId || writtenImageIds.has(imageId)) {\n return false;\n }\n // Write complete tag immediately to destination, don't accumulate\n appendFileSync(destFilePath, `${openTag}${content}${closeTag}\\n`);\n writtenImageIds.add(imageId);\n return false; // Continue scanning for more tags\n });\n}\n\nfunction parseImageScriptId(contentAfterType: string): string | null {\n const match = /^ data-id=\"([a-z0-9_-]{1,128})\">/i.exec(contentAfterType);\n return match?.[1] ?? null;\n}\n\n/** Collect IDs of real inline image script tags without blocking on a large report. */\nexport async function collectImageScriptIds(\n filePath: string,\n): Promise<Set<string>> {\n const imageIds = new Set<string>();\n const openTag = '<script type=\"midscene-image\"';\n const closeTag = htmlScriptCloseTag();\n\n await streamScanTagsAsync(filePath, openTag, closeTag, (content) => {\n const imageId = parseImageScriptId(content);\n if (imageId) imageIds.add(imageId);\n return false;\n });\n return imageIds;\n}\n\n/**\n * Extract the LAST dump script content from HTML file using streaming.\n * Memory usage: O(dump_size), not O(file_size).\n *\n * @param filePath - Absolute path to the HTML file\n * @returns The dump script content (trimmed), or empty string if not found\n */\nexport function extractLastDumpScriptSync(filePath: string): string {\n const openTagPrefix = '<script type=\"midscene_web_dump\"';\n const closeTag = htmlScriptCloseTag();\n\n let lastContent = '';\n\n // Custom streaming to handle the special case where open tag has variable attributes\n const fd = openSync(filePath, 'r');\n const fileSize = statSync(filePath).size;\n const buffer = Buffer.alloc(STREAMING_CHUNK_SIZE);\n\n let position = 0;\n let leftover = '';\n let capturing = false;\n let currentContent = '';\n\n try {\n while (position < fileSize) {\n const bytesRead = readSync(fd, buffer, 0, STREAMING_CHUNK_SIZE, position);\n const chunk = leftover + buffer.toString('utf-8', 0, bytesRead);\n position += bytesRead;\n\n let searchStart = 0;\n\n while (searchStart < chunk.length) {\n if (!capturing) {\n const startIdx = chunk.indexOf(openTagPrefix, searchStart);\n if (startIdx !== -1) {\n // Find the end of the opening tag (the '>' character)\n const tagEndIdx = chunk.indexOf('>', startIdx);\n if (tagEndIdx !== -1) {\n capturing = true;\n currentContent = chunk.slice(tagEndIdx + 1);\n const endIdx = currentContent.indexOf(closeTag);\n if (endIdx !== -1) {\n lastContent = currentContent.slice(0, endIdx).trim();\n capturing = false;\n currentContent = '';\n searchStart = tagEndIdx + 1 + endIdx + closeTag.length;\n } else {\n leftover = currentContent.slice(-closeTag.length);\n currentContent = currentContent.slice(0, -closeTag.length);\n break;\n }\n } else {\n leftover = chunk.slice(startIdx);\n break;\n }\n } else {\n leftover = chunk.slice(-openTagPrefix.length);\n break;\n }\n } else {\n const endIdx = chunk.indexOf(closeTag, searchStart);\n if (endIdx !== -1) {\n currentContent += chunk.slice(searchStart, endIdx);\n lastContent = currentContent.trim();\n capturing = false;\n currentContent = '';\n searchStart = endIdx + closeTag.length;\n } else {\n currentContent += chunk.slice(searchStart, -closeTag.length);\n leftover = chunk.slice(-closeTag.length);\n break;\n }\n }\n }\n }\n } finally {\n closeSync(fd);\n }\n\n return lastContent;\n}\n\n/**\n * Extract ALL dump script contents from an HTML file using streaming.\n * Each entry includes the full opening tag (for attribute extraction) and the content.\n *\n * @param filePath - Absolute path to the HTML file\n * @returns Array of { openTag, content } for each dump script found\n */\nexport function extractAllDumpScriptsSync(\n filePath: string,\n): { openTag: string; content: string }[] {\n const results: { openTag: string; content: string }[] = [];\n streamDumpScriptsSync(filePath, (dumpScript) => {\n results.push(dumpScript);\n return false;\n });\n return results;\n}\n\n/**\n * Stream ALL dump scripts from an HTML file.\n * Calls onMatch for each dump script and keeps memory bounded to a single\n * dump script payload instead of accumulating every dump in memory.\n *\n * @param filePath - Absolute path to the HTML file\n * @param onMatch - Callback for each dump script; return true to stop early\n */\nexport function streamDumpScriptsSync(\n filePath: string,\n visitor: (dump: { openTag: string; content: string }) => boolean,\n): void {\n streamScanTags(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n (content) => {\n const end = content.indexOf('>');\n const type = content\n .slice(0, end)\n .match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n return type === 'midscene_web_dump'\n ? visitor({\n openTag: `${String.fromCharCode(60)}script${content.slice(0, end + 1)}`,\n content: content.slice(end + 1),\n })\n : false;\n },\n );\n}\n\n/** Visit one inline image at a time; never retain all image bytes from a report. */\nfunction inlineImageElement(\n content: string,\n): { id: string; data: string } | undefined {\n const end = content.indexOf('>');\n const attributes = content.slice(0, end);\n const type = attributes.match(/(?:^|\\s)type\\s*=\\s*[\"']([^\"']+)[\"']/i)?.[1];\n const id = attributes.match(/(?:^|\\s)data-id=\"([a-z0-9_-]{1,128})\"/i)?.[1];\n return type === 'midscene-image' && id\n ? { id, data: unescapeContent(content.slice(end + 1)) }\n : undefined;\n}\n\nexport function streamInlineReportImages(\n filePath: string,\n visit: (id: string, data: string) => boolean,\n): void {\n streamScanTags(\n filePath,\n `${String.fromCharCode(60)}script`,\n htmlScriptCloseTag(),\n (content) => {\n const image = inlineImageElement(content);\n return image ? visit(image.id, image.data) : false;\n },\n );\n}\n\n/** Async backpressure keeps report import memory bounded to one image or Viewer script. */\nexport async function* streamInlineReportImagesAsync(\n filePath: string,\n): AsyncGenerator<{ id: string; data: string }> {\n const open = `${String.fromCharCode(60)}script`;\n const close = htmlScriptCloseTag();\n let pending = '';\n let capturing = false;\n for await (const chunk of createReadStream(filePath, { encoding: 'utf8' })) {\n pending += chunk;\n while (true) {\n if (!capturing) {\n const start = pending.indexOf(open);\n if (start < 0) {\n pending = pending.slice(-(open.length - 1));\n break;\n }\n pending = pending.slice(start + open.length);\n capturing = true;\n }\n const end = pending.indexOf(close);\n if (end < 0) break;\n const content = pending.slice(0, end);\n pending = pending.slice(end + close.length);\n capturing = false;\n const image = inlineImageElement(content);\n if (image) yield image;\n }\n }\n if (capturing) throw new Error(`Unterminated report script in ${filePath}`);\n}\n\nexport function parseImageScripts(html: string): Record<string, string> {\n const imageMap: Record<string, string> = {};\n const regex =\n /<script type=\"midscene-image\" data-id=\"([^\"]+)\">([\\s\\S]*?)<\\/script>/g;\n\n for (const match of html.matchAll(regex)) {\n const [, id, content] = match;\n imageMap[id] = unescapeContent(content);\n }\n\n return imageMap;\n}\n\nexport function parseDumpScript(html: string): string {\n // Use string search instead of regex to avoid ReDoS vulnerability\n // Find the LAST dump script tag (template may contain similar patterns in bundled JS)\n const scriptOpenTag = '<script type=\"midscene_web_dump\"';\n const closeTag = htmlScriptCloseTag();\n\n // Find the last occurrence of the opening tag\n const lastOpenIndex = html.lastIndexOf(scriptOpenTag);\n if (lastOpenIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Find the end of the opening tag (the '>' character)\n const tagEndIndex = html.indexOf('>', lastOpenIndex);\n if (tagEndIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Find the closing tag after the opening tag\n const closeIndex = html.indexOf(closeTag, tagEndIndex);\n if (closeIndex === -1) {\n throw new Error('No dump script found in HTML');\n }\n\n // Extract content between opening and closing tags\n const content = html.substring(tagEndIndex + 1, closeIndex);\n return unescapeContent(content);\n}\n\nexport function parseDumpScriptAttributes(\n html: string,\n): Record<string, string> {\n const regex = /<script type=\"midscene_web_dump\"([^>]*)>/;\n const match = regex.exec(html);\n\n if (!match) {\n return {};\n }\n\n const attrString = match[1];\n const attributes: Record<string, string> = {};\n const attrRegex = /(\\w+)=\"([^\"]*)\"/g;\n\n for (const attrMatch of attrString.matchAll(attrRegex)) {\n const [, key, value] = attrMatch;\n if (key !== 'type') {\n attributes[key] = decodeURIComponent(value);\n }\n }\n\n return attributes;\n}\n\nexport function generateImageScriptTag(id: string, data: string): string {\n // Do not use template string here, will cause bundle error with <script\n const closeTag = htmlScriptCloseTag();\n return (\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene-image\" data-id=\"' +\n id +\n '\">' +\n escapeContent(data) +\n closeTag\n );\n}\n\n/**\n * Inline script that fixes relative URL resolution for directory-mode reports.\n *\n * Problem: when a static server (e.g. `npx serve`) serves `name/index.html`\n * at URL `/name` (without trailing slash), relative paths like\n * `./screenshots/xxx.png` resolve to `/screenshots/xxx.png` instead of\n * `/name/screenshots/xxx.png`.\n *\n * Fix: dynamically insert a <base> tag so relative URLs resolve correctly.\n */\n// Do not use template string here, will cause bundle error with <script\n//\n// The closing script tag is built at runtime so bundlers cannot inline the\n// token that would prematurely close the report template's inline app bundle.\n//\n// Do NOT replace this with a string constant, hex escape (\\x3c), or literal\n// string concatenation. Bundlers may optimise those forms back to the unsafe\n// token.\nlet _baseUrlFixScript: string;\nexport function getBaseUrlFixScript(): string {\n if (!_baseUrlFixScript) {\n const close = htmlScriptCloseTag();\n _baseUrlFixScript =\n // biome-ignore lint/style/useTemplate: see above\n '\\n<script>(function(){' +\n 'var p=window.location.pathname;' +\n 'if(p.endsWith(\"/\")||/\\\\.\\\\w+$/.test(p))return;' +\n 'var b=document.createElement(\"base\");' +\n 'b.href=p+\"/\";' +\n 'document.head.insertBefore(b,document.head.firstChild)' +\n '})()' +\n close +\n '\\n';\n }\n return _baseUrlFixScript;\n}\n\n/**\n * Dump-script attribute that records how the report file stores screenshots.\n * Written by the report generator and the merger, read back when deciding\n * whether a report is in directory mode. Kept here, next to dump-tag\n * generation, so the writer and reader share one source of truth.\n */\nexport const DATA_SCREENSHOT_MODE_ATTR = 'data-screenshot-mode';\n\nexport function generateDumpScriptTag(\n json: string,\n attributes?: Record<string, string | number | boolean>,\n): string {\n const closeTag = htmlScriptCloseTag();\n let attrString = '';\n if (attributes && Object.keys(attributes).length > 0) {\n // Do not use template string here, will cause bundle error with <script\n attrString =\n // biome-ignore lint/style/useTemplate: <explanation>\n ' ' +\n Object.entries(attributes)\n // biome-ignore lint/style/useTemplate: <explanation>\n .map(([k, v]) => k + '=\"' + encodeURIComponent(v) + '\"')\n .join(' ');\n }\n\n // Do not use template string here, will cause bundle error with <script\n return (\n // biome-ignore lint/style/useTemplate: <explanation>\n '<script type=\"midscene_web_dump\"' +\n attrString +\n '>' +\n escapeContent(json) +\n closeTag\n );\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","escapeContent","escapeScriptTag","unescapeContent","antiEscapeScriptTag","cleanHtmlCommentValue","value","String","formatModelBriefForAgent","brief","intent","model","description","hasUsageModelInfo","usage","Boolean","formatUsageModelForAgent","source","collectUsageModelsForAgent","report","models","Map","executions","Array","execution","tasks","task","taskWithUsage","usages","formatted","generateAgentReportComment","taskCount","sum","modelBriefs","lines","htmlScriptCloseTag","generateReportArtifactScriptTag","path","assertReportArtifactPath","REPORT_ARTIFACT_SCRIPT_TYPE","JSON","reportArtifactPathExtractor","filePath","result","content","tagEnd","type","undefined","Error","extractReportArtifactPathSync","extractor","streamScanTags","extractReportArtifactPathAsync","streamScanTagsAsync","streamDumpScriptsAsync","visitor","generateTestRunReportScriptTag","dump","TEST_RUN_REPORT_SCRIPT_TYPE","extractTestRunReportDumpSync","openTag","attributes","parsed","STREAMING_CHUNK_SIZE","StreamingTagMatcher","nextChunk","chunk","searchStart","startIndex","retainedSuffixLength","Math","endIndex","contentEnd","closeTag","onMatch","fd","openSync","fileSize","statSync","buffer","Buffer","decoder","StringDecoder","matcher","position","bytesRead","readSync","closeSync","handle","openAsync","extractImageByIdSync","htmlPath","imageId","targetTag","streamImageScriptsToFile","srcFilePath","destFilePath","writtenImageIds","Set","appendFileSync","require","parseImageScriptId","contentAfterType","match","collectImageScriptIds","imageIds","extractLastDumpScriptSync","openTagPrefix","lastContent","leftover","capturing","currentContent","endIdx","startIdx","tagEndIdx","extractAllDumpScriptsSync","results","streamDumpScriptsSync","dumpScript","end","inlineImageElement","id","streamInlineReportImages","visit","image","streamInlineReportImagesAsync","open","close","pending","createReadStream","start","parseImageScripts","html","imageMap","regex","parseDumpScript","scriptOpenTag","lastOpenIndex","tagEndIndex","closeIndex","parseDumpScriptAttributes","attrString","attrRegex","attrMatch","decodeURIComponent","generateImageScriptTag","data","_baseUrlFixScript","getBaseUrlFixScript","DATA_SCREENSHOT_MODE_ATTR","generateDumpScriptTag","json","k","v","encodeURIComponent"],"mappings":"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"}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __webpack_require__ = {};
|
|
3
|
+
(()=>{
|
|
4
|
+
__webpack_require__.d = (exports1, definition)=>{
|
|
5
|
+
for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: definition[key]
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
})();
|
|
11
|
+
(()=>{
|
|
12
|
+
__webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
|
|
13
|
+
})();
|
|
14
|
+
(()=>{
|
|
15
|
+
__webpack_require__.r = (exports1)=>{
|
|
16
|
+
if ('undefined' != typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
|
|
17
|
+
value: 'Module'
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports1, '__esModule', {
|
|
20
|
+
value: true
|
|
21
|
+
});
|
|
22
|
+
};
|
|
23
|
+
})();
|
|
24
|
+
var __webpack_exports__ = {};
|
|
25
|
+
__webpack_require__.r(__webpack_exports__);
|
|
26
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
27
|
+
publishReportArtifact: ()=>publishReportArtifact,
|
|
28
|
+
publishReportArtifactSync: ()=>publishReportArtifactSync
|
|
29
|
+
});
|
|
30
|
+
const external_node_crypto_namespaceObject = require("node:crypto");
|
|
31
|
+
const external_node_fs_namespaceObject = require("node:fs");
|
|
32
|
+
const promises_namespaceObject = require("node:fs/promises");
|
|
33
|
+
const external_node_path_namespaceObject = require("node:path");
|
|
34
|
+
const external_report_artifact_store_js_namespaceObject = require("./report-artifact-store.js");
|
|
35
|
+
function publicationLockName(destination) {
|
|
36
|
+
const id = (0, external_node_crypto_namespaceObject.createHash)('sha256').update((0, external_node_path_namespaceObject.resolve)(destination)).digest('hex');
|
|
37
|
+
return `.report-publish-${id}.lock`;
|
|
38
|
+
}
|
|
39
|
+
function assertAvailable(destination, overwrite) {
|
|
40
|
+
if (!overwrite && (0, external_node_fs_namespaceObject.existsSync)(destination)) throw new Error(`Report artifact already exists: ${destination}`);
|
|
41
|
+
}
|
|
42
|
+
async function publishReportArtifact(prepared, destination, directory, overwrite = false) {
|
|
43
|
+
await (0, external_report_artifact_store_js_namespaceObject.withReportArtifactLock)((0, external_node_path_namespaceObject.dirname)(destination), async ()=>{
|
|
44
|
+
assertAvailable(destination, overwrite);
|
|
45
|
+
if (directory) {
|
|
46
|
+
if (overwrite) await (0, promises_namespaceObject.rm)(destination, {
|
|
47
|
+
recursive: true,
|
|
48
|
+
force: true
|
|
49
|
+
});
|
|
50
|
+
await (0, promises_namespaceObject.rename)(prepared, destination);
|
|
51
|
+
} else if (overwrite) await (0, promises_namespaceObject.rename)(prepared, destination);
|
|
52
|
+
else await (0, promises_namespaceObject.link)(prepared, destination);
|
|
53
|
+
}, 10000, publicationLockName(destination));
|
|
54
|
+
}
|
|
55
|
+
function publishReportArtifactSync(prepared, destination, directory, overwrite = false) {
|
|
56
|
+
const lockPath = (0, external_node_path_namespaceObject.join)((0, external_node_path_namespaceObject.dirname)(destination), publicationLockName(destination));
|
|
57
|
+
const lock = (0, external_node_fs_namespaceObject.openSync)(lockPath, 'wx');
|
|
58
|
+
try {
|
|
59
|
+
(0, external_node_fs_namespaceObject.writeFileSync)(lock, JSON.stringify({
|
|
60
|
+
pid: process.pid
|
|
61
|
+
}));
|
|
62
|
+
assertAvailable(destination, overwrite);
|
|
63
|
+
if (directory) {
|
|
64
|
+
if (overwrite) (0, external_node_fs_namespaceObject.rmSync)(destination, {
|
|
65
|
+
recursive: true,
|
|
66
|
+
force: true
|
|
67
|
+
});
|
|
68
|
+
(0, external_node_fs_namespaceObject.renameSync)(prepared, destination);
|
|
69
|
+
} else if (overwrite) (0, external_node_fs_namespaceObject.renameSync)(prepared, destination);
|
|
70
|
+
else (0, external_node_fs_namespaceObject.linkSync)(prepared, destination);
|
|
71
|
+
} finally{
|
|
72
|
+
try {
|
|
73
|
+
(0, external_node_fs_namespaceObject.closeSync)(lock);
|
|
74
|
+
} finally{
|
|
75
|
+
(0, external_node_fs_namespaceObject.unlinkSync)(lockPath);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
exports.publishReportArtifact = __webpack_exports__.publishReportArtifact;
|
|
80
|
+
exports.publishReportArtifactSync = __webpack_exports__.publishReportArtifactSync;
|
|
81
|
+
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
82
|
+
"publishReportArtifact",
|
|
83
|
+
"publishReportArtifactSync"
|
|
84
|
+
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
85
|
+
Object.defineProperty(exports, '__esModule', {
|
|
86
|
+
value: true
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
//# sourceMappingURL=report-artifact-publication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dump/report-artifact-publication.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/report-artifact-publication.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { createHash } from 'node:crypto';\nimport {\n closeSync,\n existsSync,\n linkSync,\n openSync,\n renameSync,\n rmSync,\n unlinkSync,\n writeFileSync,\n} from 'node:fs';\nimport { link, rename, rm } from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport { withReportArtifactLock } from './report-artifact-store';\n\nfunction publicationLockName(destination: string): string {\n const id = createHash('sha256').update(resolve(destination)).digest('hex');\n return `.report-publish-${id}.lock`;\n}\n\nfunction assertAvailable(destination: string, overwrite: boolean): void {\n if (!overwrite && existsSync(destination))\n throw new Error(`Report artifact already exists: ${destination}`);\n}\n\n/** The prepared artifact and destination share a filesystem. Lock only the\n * final publication, and never remove the other format's sibling artifact. */\nexport async function publishReportArtifact(\n prepared: string,\n destination: string,\n directory: boolean,\n overwrite = false,\n): Promise<void> {\n await withReportArtifactLock(\n dirname(destination),\n async () => {\n assertAvailable(destination, overwrite);\n if (directory) {\n if (overwrite) await rm(destination, { recursive: true, force: true });\n await rename(prepared, destination);\n } else if (overwrite) {\n await rename(prepared, destination);\n } else {\n // Unlike rename, link cannot replace a file created after the check.\n await link(prepared, destination);\n }\n },\n 10_000,\n publicationLockName(destination),\n );\n}\n\nexport function publishReportArtifactSync(\n prepared: string,\n destination: string,\n directory: boolean,\n overwrite = false,\n): void {\n const lockPath = join(dirname(destination), publicationLockName(destination));\n // A synchronous caller must not block the event loop waiting for an async\n // publisher in this same process. A busy destination fails without changes.\n const lock = openSync(lockPath, 'wx');\n try {\n writeFileSync(lock, JSON.stringify({ pid: process.pid }));\n assertAvailable(destination, overwrite);\n if (directory) {\n if (overwrite) rmSync(destination, { recursive: true, force: true });\n renameSync(prepared, destination);\n } else if (overwrite) {\n renameSync(prepared, destination);\n } else {\n linkSync(prepared, destination);\n }\n } finally {\n try {\n closeSync(lock);\n } finally {\n unlinkSync(lockPath);\n }\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","publicationLockName","destination","id","createHash","resolve","assertAvailable","overwrite","existsSync","Error","publishReportArtifact","prepared","directory","withReportArtifactLock","dirname","rm","rename","link","publishReportArtifactSync","lockPath","join","lock","openSync","writeFileSync","JSON","process","rmSync","renameSync","linkSync","closeSync","unlinkSync"],"mappings":"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"}
|
|
@@ -56,8 +56,8 @@ async function writeReportArtifactFile(path, content) {
|
|
|
56
56
|
});
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
-
async function withReportArtifactLock(root, publish, timeoutMs = 10000) {
|
|
60
|
-
const lockPath = (0, external_node_path_namespaceObject.resolve)(root,
|
|
59
|
+
async function withReportArtifactLock(root, publish, timeoutMs = 10000, lockFileName = '.report.json.lock') {
|
|
60
|
+
const lockPath = (0, external_node_path_namespaceObject.resolve)(root, lockFileName);
|
|
61
61
|
await (0, promises_namespaceObject.mkdir)((0, external_node_path_namespaceObject.dirname)(lockPath), {
|
|
62
62
|
recursive: true
|
|
63
63
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dump/report-artifact-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/report-artifact-store.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import {\n mkdir,\n open,\n readFile,\n rename,\n unlink,\n writeFile,\n} from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport {\n type ReportArtifactManifest,\n parseReportArtifactManifest,\n} from '@midscene/shared/report-artifact';\nimport { uuid } from '@midscene/shared/utils';\n\n/** Publish individual files atomically; readers never observe truncated JSON. */\nexport async function writeReportArtifactFile(\n path: string,\n content: string | Uint8Array,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const temporary = `${path}.${uuid()}.tmp`;\n try {\n await writeFile(temporary, content, 'utf8');\n await rename(temporary, path);\n } finally {\n await unlink(temporary).catch((error) => {\n if (error.code !== 'ENOENT') throw error;\n });\n }\n}\n\n/** Serialize the entire read/merge/write transaction across Node processes. */\nexport async function withReportArtifactLock<T>(\n root: string,\n publish: () => Promise<T>,\n timeoutMs = 10_000,\n): Promise<T> {\n const lockPath = resolve(root, '.report.json.lock');\n await mkdir(dirname(lockPath), { recursive: true });\n const startedAt = Date.now();\n const acquire = async () => {\n while (true) {\n try {\n return await open(lockPath, 'wx');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(\n `Timed out waiting for report artifact lock ${lockPath}. Another publisher may still be running. If its owner crashed, remove the lock only after confirming that process has exited.`,\n { cause: error },\n );\n }\n await new Promise((resolve) =>\n setTimeout(resolve, 20 + Math.random() * 10),\n );\n }\n }\n };\n const lock = await acquire();\n try {\n await lock.writeFile(JSON.stringify({ pid: process.pid }));\n return await publish();\n } finally {\n // Never expire a live publisher's lock based on elapsed time: a slow\n // filesystem or paused process must not result in two simultaneous owners.\n await lock.close().finally(() => unlink(lockPath));\n }\n}\n\n/** Stores report data without rendering HTML or owning execution resources. */\nexport class ReportArtifactStore {\n private readonly executionPaths = new Map<string, string>();\n private nextExecution = 0;\n private readonly manifest: ReportArtifactManifest;\n private queue: Promise<void> = Promise.resolve();\n private hasPublished = false;\n private finalization?: Promise<void>;\n\n constructor(\n private readonly root: string,\n reportId: string,\n kind: 'agent' | 'test' = 'agent',\n private readonly reuseExistingReport = false,\n entry = 'index.html',\n ) {\n if (!/^[a-zA-Z0-9_-]{1,128}$/.test(reportId))\n throw new Error('Invalid report artifact ID');\n this.manifest = {\n schemaVersion: 1,\n kind,\n status: 'running',\n reportId,\n entry,\n groups: [{ id: reportId, status: 'running', attributes: {}, dumps: [] }],\n };\n }\n\n async writeExecution(\n key: string,\n serialized: string,\n attributes: Record<string, string>,\n ): Promise<void> {\n this.assertOpen();\n this.queue = this.queue.then(async () => {\n let path = this.executionPaths.get(key);\n if (!path) {\n path = `data/${this.manifest.reportId}/${++this.nextExecution}.json`;\n this.executionPaths.set(key, path);\n }\n await writeReportArtifactFile(join(this.root, path), serialized);\n const group = this.manifest.groups[0];\n group.attributes = attributes;\n if (!group.dumps.includes(path)) group.dumps.push(path);\n await this.publish();\n });\n await this.queue;\n }\n\n async writeRunner(serialized: string): Promise<void> {\n this.assertOpen();\n this.queue = this.queue.then(async () => {\n const path = `data/${this.manifest.reportId}/runner.json`;\n await writeReportArtifactFile(join(this.root, path), serialized);\n this.manifest.runner = path;\n await this.publish();\n });\n await this.queue;\n }\n\n async finalize(): Promise<void> {\n if (!this.finalization) {\n this.finalization = this.queue = this.queue.then(async () => {\n this.manifest.groups[0].status = 'complete';\n await this.publish();\n });\n }\n await this.finalization;\n }\n\n private assertOpen(): void {\n if (this.finalization)\n throw new Error('The report artifact stream has been finalized.');\n }\n\n private async publish(): Promise<void> {\n const path = resolve(this.root, 'report.json');\n await withReportArtifactLock(this.root, async () => {\n let manifest = this.manifest;\n if (this.reuseExistingReport || this.hasPublished) {\n const existing = await readFile(path, 'utf8').catch((error) => {\n if (error.code === 'ENOENT') return undefined;\n throw error;\n });\n if (existing !== undefined) {\n const previous = parseReportArtifactManifest(JSON.parse(existing));\n if (\n previous.kind !== manifest.kind ||\n previous.entry !== manifest.entry\n )\n throw new Error(\n 'Cannot combine reports with different kinds or entries',\n );\n manifest = {\n ...previous,\n groups: [\n ...new Map(\n [...previous.groups, ...manifest.groups].map((group) => [\n group.id,\n group,\n ]),\n ).values(),\n ],\n runner: manifest.runner ?? previous.runner,\n };\n }\n }\n manifest = {\n ...manifest,\n status: manifest.groups.every((group) => group.status === 'complete')\n ? 'complete'\n : 'running',\n };\n parseReportArtifactManifest(manifest);\n await writeReportArtifactFile(path, JSON.stringify(manifest));\n this.hasPublished = true;\n });\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","writeReportArtifactFile","path","content","mkdir","dirname","temporary","uuid","writeFile","rename","unlink","error","withReportArtifactLock","root","publish","timeoutMs","lockPath","resolve","startedAt","Date","acquire","open","Error","Promise","setTimeout","Math","lock","JSON","process","ReportArtifactStore","serialized","attributes","join","group","manifest","existing","readFile","undefined","previous","parseReportArtifactManifest","Map","reportId","kind","reuseExistingReport","entry"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dump/report-artifact-store.js","sources":["webpack/runtime/define_property_getters","webpack/runtime/has_own_property","webpack/runtime/make_namespace_object","../../../src/dump/report-artifact-store.ts"],"sourcesContent":["__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n }\n }\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import {\n mkdir,\n open,\n readFile,\n rename,\n unlink,\n writeFile,\n} from 'node:fs/promises';\nimport { dirname, join, resolve } from 'node:path';\nimport {\n type ReportArtifactManifest,\n parseReportArtifactManifest,\n} from '@midscene/shared/report-artifact';\nimport { uuid } from '@midscene/shared/utils';\n\n/** Publish individual files atomically; readers never observe truncated JSON. */\nexport async function writeReportArtifactFile(\n path: string,\n content: string | Uint8Array,\n): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n const temporary = `${path}.${uuid()}.tmp`;\n try {\n await writeFile(temporary, content, 'utf8');\n await rename(temporary, path);\n } finally {\n await unlink(temporary).catch((error) => {\n if (error.code !== 'ENOENT') throw error;\n });\n }\n}\n\n/** Serialize the entire read/merge/write transaction across Node processes. */\nexport async function withReportArtifactLock<T>(\n root: string,\n publish: () => Promise<T>,\n timeoutMs = 10_000,\n lockFileName = '.report.json.lock',\n): Promise<T> {\n const lockPath = resolve(root, lockFileName);\n await mkdir(dirname(lockPath), { recursive: true });\n const startedAt = Date.now();\n const acquire = async () => {\n while (true) {\n try {\n return await open(lockPath, 'wx');\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'EEXIST') throw error;\n if (Date.now() - startedAt >= timeoutMs) {\n throw new Error(\n `Timed out waiting for report artifact lock ${lockPath}. Another publisher may still be running. If its owner crashed, remove the lock only after confirming that process has exited.`,\n { cause: error },\n );\n }\n await new Promise((resolve) =>\n setTimeout(resolve, 20 + Math.random() * 10),\n );\n }\n }\n };\n const lock = await acquire();\n try {\n await lock.writeFile(JSON.stringify({ pid: process.pid }));\n return await publish();\n } finally {\n // Never expire a live publisher's lock based on elapsed time: a slow\n // filesystem or paused process must not result in two simultaneous owners.\n await lock.close().finally(() => unlink(lockPath));\n }\n}\n\n/** Stores report data without rendering HTML or owning execution resources. */\nexport class ReportArtifactStore {\n private readonly executionPaths = new Map<string, string>();\n private nextExecution = 0;\n private readonly manifest: ReportArtifactManifest;\n private queue: Promise<void> = Promise.resolve();\n private hasPublished = false;\n private finalization?: Promise<void>;\n\n constructor(\n private readonly root: string,\n reportId: string,\n kind: 'agent' | 'test' = 'agent',\n private readonly reuseExistingReport = false,\n entry = 'index.html',\n ) {\n if (!/^[a-zA-Z0-9_-]{1,128}$/.test(reportId))\n throw new Error('Invalid report artifact ID');\n this.manifest = {\n schemaVersion: 1,\n kind,\n status: 'running',\n reportId,\n entry,\n groups: [{ id: reportId, status: 'running', attributes: {}, dumps: [] }],\n };\n }\n\n async writeExecution(\n key: string,\n serialized: string,\n attributes: Record<string, string>,\n ): Promise<void> {\n this.assertOpen();\n this.queue = this.queue.then(async () => {\n let path = this.executionPaths.get(key);\n if (!path) {\n path = `data/${this.manifest.reportId}/${++this.nextExecution}.json`;\n this.executionPaths.set(key, path);\n }\n await writeReportArtifactFile(join(this.root, path), serialized);\n const group = this.manifest.groups[0];\n group.attributes = attributes;\n if (!group.dumps.includes(path)) group.dumps.push(path);\n await this.publish();\n });\n await this.queue;\n }\n\n async writeRunner(serialized: string): Promise<void> {\n this.assertOpen();\n this.queue = this.queue.then(async () => {\n const path = `data/${this.manifest.reportId}/runner.json`;\n await writeReportArtifactFile(join(this.root, path), serialized);\n this.manifest.runner = path;\n await this.publish();\n });\n await this.queue;\n }\n\n async finalize(): Promise<void> {\n if (!this.finalization) {\n this.finalization = this.queue = this.queue.then(async () => {\n this.manifest.groups[0].status = 'complete';\n await this.publish();\n });\n }\n await this.finalization;\n }\n\n private assertOpen(): void {\n if (this.finalization)\n throw new Error('The report artifact stream has been finalized.');\n }\n\n private async publish(): Promise<void> {\n const path = resolve(this.root, 'report.json');\n await withReportArtifactLock(this.root, async () => {\n let manifest = this.manifest;\n if (this.reuseExistingReport || this.hasPublished) {\n const existing = await readFile(path, 'utf8').catch((error) => {\n if (error.code === 'ENOENT') return undefined;\n throw error;\n });\n if (existing !== undefined) {\n const previous = parseReportArtifactManifest(JSON.parse(existing));\n if (\n previous.kind !== manifest.kind ||\n previous.entry !== manifest.entry\n )\n throw new Error(\n 'Cannot combine reports with different kinds or entries',\n );\n manifest = {\n ...previous,\n groups: [\n ...new Map(\n [...previous.groups, ...manifest.groups].map((group) => [\n group.id,\n group,\n ]),\n ).values(),\n ],\n runner: manifest.runner ?? previous.runner,\n };\n }\n }\n manifest = {\n ...manifest,\n status: manifest.groups.every((group) => group.status === 'complete')\n ? 'complete'\n : 'running',\n };\n parseReportArtifactManifest(manifest);\n await writeReportArtifactFile(path, JSON.stringify(manifest));\n this.hasPublished = true;\n });\n }\n}\n"],"names":["__webpack_require__","definition","key","Object","obj","prop","Symbol","writeReportArtifactFile","path","content","mkdir","dirname","temporary","uuid","writeFile","rename","unlink","error","withReportArtifactLock","root","publish","timeoutMs","lockFileName","lockPath","resolve","startedAt","Date","acquire","open","Error","Promise","setTimeout","Math","lock","JSON","process","ReportArtifactStore","serialized","attributes","join","group","manifest","existing","readFile","undefined","previous","parseReportArtifactManifest","Map","reportId","kind","reuseExistingReport","entry"],"mappings":"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"}
|