@checksum-ai/runtime 4.16.2-beta.1 → 4.16.3

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.
@@ -2,29 +2,22 @@ const fs = require("fs");
2
2
  const crypto = require("crypto");
3
3
  const { join } = require("path");
4
4
 
5
- // Args
6
5
  const on = process.argv[2] !== "off";
7
6
 
8
- // -------- [Modifiers] -------- //
9
-
10
- // Amends the file with the given entry point text and append text
11
- // When "on" is true, the append text is added to the entry point,
12
- // otherwise the append text is completely removed from the file
7
+ // When `on`, appendText is spliced in after entryPointText; when off, it is
8
+ // stripped back out. Leaves no marker, so an amend cannot be detected later.
13
9
  function amend(filePath, entryPointText, appendText) {
14
10
  const data = fs.readFileSync(filePath, "utf8");
15
11
  if (!data.includes(entryPointText)) {
16
12
  throw new Error("Entry point not found!", entryPointText);
17
13
  }
18
- // Ignore if the append text is already present
19
14
  if (on && data.includes(appendText)) {
20
15
  return;
21
16
  }
22
- // Add or clear according to on state
23
17
  const result = on
24
18
  ? data.replace(entryPointText, entryPointText + appendText)
25
19
  : data.replace(appendText, "");
26
20
 
27
- // Write
28
21
  fs.writeFileSync(filePath, result, "utf8");
29
22
  }
30
23
 
@@ -34,6 +27,9 @@ function amend(filePath, entryPointText, appendText) {
34
27
  // (whose newContent collapses to the bare marker) to clobber the FIRST
35
28
  // `/* checksumai */ ` it found, corrupting whichever patch happened to live
36
29
  // at the lowest line number.
30
+ // When `on`, newContent replaces originalContent; when off, the original is
31
+ // restored. The `/* checksumai */` prefix is the marker that makes the off
32
+ // direction findable.
37
33
  function replaceContent(filePath, originalContent, newContent) {
38
34
  const fileContent = fs.readFileSync(filePath, "utf8");
39
35
 
@@ -89,9 +85,6 @@ function doesFileExist(filePath) {
89
85
  return true;
90
86
  }
91
87
 
92
- // -------- [Modifications] -------- //
93
-
94
- // Remove conditions for injecting Playwright scripts
95
88
  function alwaysInjectScripts(projectRoot) {
96
89
  const file = join(
97
90
  projectRoot,
@@ -100,11 +93,6 @@ function alwaysInjectScripts(projectRoot) {
100
93
  if (!doesFileExist(file)) {
101
94
  return;
102
95
  }
103
- // const originalContent =
104
- // "if ((0, _debug.debugMode)() === 'console') await this.extendInjectedScript(consoleApiSource.source);";
105
-
106
- // const newContent =
107
- // "await this.extendInjectedScript(consoleApiSource.source);";
108
96
 
109
97
  const originalContent = 'if ((0, import_debug.debugMode)() === "console")';
110
98
 
@@ -113,7 +101,6 @@ function alwaysInjectScripts(projectRoot) {
113
101
  replaceContent(file, originalContent, newContent);
114
102
  }
115
103
 
116
- // Add implementation for generateSelectorAndLocator and inject to Playwright console API
117
104
  function addGenerateSelectorAndLocator(projectRoot) {
118
105
  const file = join(
119
106
  projectRoot,
@@ -133,8 +120,6 @@ function addGenerateSelectorAndLocator(projectRoot) {
133
120
  amend(file, entryPointText2, appendText2);
134
121
  }
135
122
 
136
- // -------- [Runtime modifications] -------- //
137
-
138
123
  function expect(projectRoot) {
139
124
  const file = join(
140
125
  projectRoot,
@@ -144,30 +129,6 @@ function expect(projectRoot) {
144
129
  return;
145
130
  }
146
131
  let originalContent, newContent;
147
-
148
- // originalContent = `return (...args) => {
149
- // const testInfo = (0, _globals.currentTestInfo)();`;
150
- // newContent = `return (...args) => {
151
- // let noSoft = false;
152
- // if (args.find(arg=>arg==='no-soft')){
153
- // noSoft = true;
154
- // args.pop();
155
- // }
156
- // const testInfo = (0, _globals.currentTestInfo)();`;
157
- // replaceContent(file, originalContent, newContent);
158
-
159
- // originalContent = `step.complete({
160
- // error
161
- // })`;
162
- // newContent = `step.complete({
163
- // error,
164
- // noSoft
165
- // })`;
166
- // replaceContent(file, originalContent, newContent);
167
-
168
- // originalContent = `if (this._info.isSoft) testInfo._failWithError(error);else throw error;`;
169
- // newContent = `if (this._info.isSoft && !noSoft) testInfo._failWithError(error);else throw error;`;
170
- // replaceContent(file, originalContent, newContent);
171
132
  }
172
133
 
173
134
  function testInfo(projectRoot) {
@@ -181,10 +142,6 @@ function testInfo(projectRoot) {
181
142
  let originalContent, newContent;
182
143
  let entryPointText, appendText;
183
144
 
184
- // originalContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());`;
185
- // newContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime')));`;
186
- // replaceContent(file, originalContent, newContent);
187
-
188
145
  entryPointText = `data.location = data.location || filteredStack[0];`;
189
146
  appendText = `\nif (this._checksumInternal) {
190
147
  data.location = undefined;
@@ -222,7 +179,6 @@ function testType(projectRoot) {
222
179
  }
223
180
 
224
181
  entryPointText = `return await (0, import_utils.currentZone)().with("stepZone", step).run(async () => {`;
225
- // entryPointText = `return await _utils.zones.run('stepZone', step, async () => {`;
226
182
  appendText = `\nif (options.obtainStep){
227
183
  options.obtainStep(step);
228
184
  }`;
@@ -280,7 +236,6 @@ function channelOwner(projectRoot) {
280
236
  let entryPointText, appendText;
281
237
 
282
238
  entryPointText = `async _wrapApiCall(func, isInternal) {`;
283
- // entryPointText = `async _wrapApiCall(func, isInternal = false) {`;
284
239
 
285
240
  appendText = `\nif (this._checksumInternal){
286
241
  isInternal = true;
@@ -366,8 +321,6 @@ function reportTraceFile(projectRoot) {
366
321
  replaceContent(file, originalContent, newContent);
367
322
  }
368
323
 
369
- // -------- [Run] -------- //
370
-
371
324
  const isRuntime = true || process.env.RUNTIME === "true";
372
325
 
373
326
  function run(projectPath) {
@@ -394,7 +347,6 @@ function run(projectPath) {
394
347
  console.warn("Project path not found", projectPath);
395
348
  }
396
349
  } catch (e) {
397
- // ignore
398
350
  console.error(e);
399
351
  }
400
352
  }
@@ -2,29 +2,22 @@ const fs = require("fs");
2
2
  const crypto = require("crypto");
3
3
  const { join } = require("path");
4
4
 
5
- // Args
6
5
  const on = process.argv[2] !== "off";
7
6
 
8
- // -------- [Modifiers] -------- //
9
-
10
- // Amends the file with the given entry point text and append text
11
- // When "on" is true, the append text is added to the entry point,
12
- // otherwise the append text is completely removed from the file
7
+ // When `on`, appendText is spliced in after entryPointText; when off, it is
8
+ // stripped back out. Leaves no marker, so an amend cannot be detected later.
13
9
  function amend(filePath, entryPointText, appendText) {
14
10
  const data = fs.readFileSync(filePath, "utf8");
15
11
  if (!data.includes(entryPointText)) {
16
12
  throw new Error("Entry point not found!", entryPointText);
17
13
  }
18
- // Ignore if the append text is already present
19
14
  if (on && data.includes(appendText)) {
20
15
  return;
21
16
  }
22
- // Add or clear according to on state
23
17
  const result = on
24
18
  ? data.replace(entryPointText, entryPointText + appendText)
25
19
  : data.replace(appendText, "");
26
20
 
27
- // Write
28
21
  fs.writeFileSync(filePath, result, "utf8");
29
22
  }
30
23
 
@@ -34,6 +27,9 @@ function amend(filePath, entryPointText, appendText) {
34
27
  // (whose newContent collapses to the bare marker) to clobber the FIRST
35
28
  // `/* checksumai */ ` it found, corrupting whichever patch happened to live
36
29
  // at the lowest line number.
30
+ // When `on`, newContent replaces originalContent; when off, the original is
31
+ // restored. The `/* checksumai */` prefix is the marker that makes the off
32
+ // direction findable.
37
33
  function replaceContent(filePath, originalContent, newContent) {
38
34
  const fileContent = fs.readFileSync(filePath, "utf8");
39
35
 
@@ -89,9 +85,6 @@ function doesFileExist(filePath) {
89
85
  return true;
90
86
  }
91
87
 
92
- // -------- [Modifications] -------- //
93
-
94
- // Remove conditions for injecting Playwright scripts
95
88
  function alwaysInjectScripts(projectRoot) {
96
89
  const file = join(
97
90
  projectRoot,
@@ -108,7 +101,6 @@ function alwaysInjectScripts(projectRoot) {
108
101
  replaceContent(file, originalContent, newContent);
109
102
  }
110
103
 
111
- // Add implementation for generateSelectorAndLocator and inject to Playwright console API
112
104
  function addGenerateSelectorAndLocator(projectRoot) {
113
105
  const file = join(
114
106
  projectRoot,
@@ -128,8 +120,6 @@ function addGenerateSelectorAndLocator(projectRoot) {
128
120
  amend(file, entryPointText2, appendText2);
129
121
  }
130
122
 
131
- // -------- [Runtime modifications] -------- //
132
-
133
123
  function expect(projectRoot) {
134
124
  const file = join(
135
125
  projectRoot,
@@ -139,30 +129,6 @@ function expect(projectRoot) {
139
129
  return;
140
130
  }
141
131
  let originalContent, newContent;
142
-
143
- // originalContent = `return (...args) => {
144
- // const testInfo = (0, _globals.currentTestInfo)();`;
145
- // newContent = `return (...args) => {
146
- // let noSoft = false;
147
- // if (args.find(arg=>arg==='no-soft')){
148
- // noSoft = true;
149
- // args.pop();
150
- // }
151
- // const testInfo = (0, _globals.currentTestInfo)();`;
152
- // replaceContent(file, originalContent, newContent);
153
-
154
- // originalContent = `step.complete({
155
- // error
156
- // })`;
157
- // newContent = `step.complete({
158
- // error,
159
- // noSoft
160
- // })`;
161
- // replaceContent(file, originalContent, newContent);
162
-
163
- // originalContent = `if (this._info.isSoft) testInfo._failWithError(error);else throw error;`;
164
- // newContent = `if (this._info.isSoft && !noSoft) testInfo._failWithError(error);else throw error;`;
165
- // replaceContent(file, originalContent, newContent);
166
132
  }
167
133
 
168
134
  function testInfo(projectRoot) {
@@ -176,10 +142,6 @@ function testInfo(projectRoot) {
176
142
  let originalContent, newContent;
177
143
  let entryPointText, appendText;
178
144
 
179
- // originalContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());`;
180
- // newContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime')));`;
181
- // replaceContent(file, originalContent, newContent);
182
-
183
145
  entryPointText = `location = location || filteredStack[0];`;
184
146
  appendText = `\nif (this._checksumInternal) {
185
147
  location = undefined;
@@ -217,7 +179,6 @@ function testType(projectRoot) {
217
179
  }
218
180
 
219
181
  entryPointText = `return await (0, import_utils.currentZone)().with("stepZone", step).run(async () => {`;
220
- // entryPointText = `return await _utils.zones.run('stepZone', step, async () => {`;
221
182
  appendText = `\nif (options.obtainStep){
222
183
  options.obtainStep(step);
223
184
  }`;
@@ -502,8 +463,6 @@ function htmlReporter(projectRoot) {
502
463
  replaceContent(file, originalContent, newContent);
503
464
  }
504
465
 
505
- // -------- [Run] -------- //
506
-
507
466
  const isRuntime = true || process.env.RUNTIME === "true";
508
467
 
509
468
  function run(projectPath) {
@@ -531,7 +490,6 @@ function run(projectPath) {
531
490
  console.warn("Project path not found", projectPath);
532
491
  }
533
492
  } catch (e) {
534
- // ignore
535
493
  console.error(e);
536
494
  }
537
495
  }
@@ -2,29 +2,22 @@ const fs = require("fs");
2
2
  const crypto = require("crypto");
3
3
  const { join } = require("path");
4
4
 
5
- // Args
6
5
  const on = process.argv[2] !== "off";
7
6
 
8
- // -------- [Modifiers] -------- //
9
-
10
- // Amends the file with the given entry point text and append text
11
- // When "on" is true, the append text is added to the entry point,
12
- // otherwise the append text is completely removed from the file
7
+ // When `on`, appendText is spliced in after entryPointText; when off, it is
8
+ // stripped back out. Leaves no marker, so an amend cannot be detected later.
13
9
  function amend(filePath, entryPointText, appendText) {
14
10
  const data = fs.readFileSync(filePath, "utf8");
15
11
  if (!data.includes(entryPointText)) {
16
12
  throw new Error("Entry point not found!", entryPointText);
17
13
  }
18
- // Ignore if the append text is already present
19
14
  if (on && data.includes(appendText)) {
20
15
  return;
21
16
  }
22
- // Add or clear according to on state
23
17
  const result = on
24
18
  ? data.replace(entryPointText, entryPointText + appendText)
25
19
  : data.replace(appendText, "");
26
20
 
27
- // Write
28
21
  fs.writeFileSync(filePath, result, "utf8");
29
22
  }
30
23
 
@@ -34,6 +27,9 @@ function amend(filePath, entryPointText, appendText) {
34
27
  // (whose newContent collapses to the bare marker) to clobber the FIRST
35
28
  // `/* checksumai */ ` it found, corrupting whichever patch happened to live
36
29
  // at the lowest line number.
30
+ // When `on`, newContent replaces originalContent; when off, the original is
31
+ // restored. The `/* checksumai */` prefix is the marker that makes the off
32
+ // direction findable.
37
33
  function replaceContent(filePath, originalContent, newContent) {
38
34
  const fileContent = fs.readFileSync(filePath, "utf8");
39
35
 
@@ -89,9 +85,6 @@ function doesFileExist(filePath) {
89
85
  return true;
90
86
  }
91
87
 
92
- // -------- [Modifications] -------- //
93
-
94
- // Remove conditions for injecting Playwright scripts
95
88
  function alwaysInjectScripts(projectRoot) {
96
89
  const file = join(
97
90
  projectRoot,
@@ -108,7 +101,6 @@ function alwaysInjectScripts(projectRoot) {
108
101
  replaceContent(file, originalContent, newContent);
109
102
  }
110
103
 
111
- // Add implementation for generateSelectorAndLocator and inject to Playwright console API
112
104
  function addGenerateSelectorAndLocator(projectRoot) {
113
105
  const file = join(
114
106
  projectRoot,
@@ -128,8 +120,6 @@ function addGenerateSelectorAndLocator(projectRoot) {
128
120
  amend(file, entryPointText2, appendText2);
129
121
  }
130
122
 
131
- // -------- [Runtime modifications] -------- //
132
-
133
123
  function expect(projectRoot) {
134
124
  const file = join(
135
125
  projectRoot,
@@ -139,30 +129,6 @@ function expect(projectRoot) {
139
129
  return;
140
130
  }
141
131
  let originalContent, newContent;
142
-
143
- // originalContent = `return (...args) => {
144
- // const testInfo = (0, _globals.currentTestInfo)();`;
145
- // newContent = `return (...args) => {
146
- // let noSoft = false;
147
- // if (args.find(arg=>arg==='no-soft')){
148
- // noSoft = true;
149
- // args.pop();
150
- // }
151
- // const testInfo = (0, _globals.currentTestInfo)();`;
152
- // replaceContent(file, originalContent, newContent);
153
-
154
- // originalContent = `step.complete({
155
- // error
156
- // })`;
157
- // newContent = `step.complete({
158
- // error,
159
- // noSoft
160
- // })`;
161
- // replaceContent(file, originalContent, newContent);
162
-
163
- // originalContent = `if (this._info.isSoft) testInfo._failWithError(error);else throw error;`;
164
- // newContent = `if (this._info.isSoft && !noSoft) testInfo._failWithError(error);else throw error;`;
165
- // replaceContent(file, originalContent, newContent);
166
132
  }
167
133
 
168
134
  function testInfo(projectRoot) {
@@ -176,10 +142,6 @@ function testInfo(projectRoot) {
176
142
  let originalContent, newContent;
177
143
  let entryPointText, appendText;
178
144
 
179
- // originalContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)());`;
180
- // newContent = `const filteredStack = (0, _util.filteredStackTrace)((0, _utils.captureRawStack)().filter(s=>!s.includes('@checksum-ai/runtime')));`;
181
- // replaceContent(file, originalContent, newContent);
182
-
183
145
  entryPointText = `location = location || filteredStack[0];`;
184
146
  appendText = `\nif (this._checksumInternal) {
185
147
  location = undefined;
@@ -217,7 +179,6 @@ function testType(projectRoot) {
217
179
  }
218
180
 
219
181
  entryPointText = `return await (0, import_utils.currentZone)().with("stepZone", step).run(async () => {`;
220
- // entryPointText = `return await _utils.zones.run('stepZone', step, async () => {`;
221
182
  appendText = `\nif (options.obtainStep){
222
183
  options.obtainStep(step);
223
184
  }`;
@@ -502,8 +463,6 @@ function htmlReporter(projectRoot) {
502
463
  replaceContent(file, originalContent, newContent);
503
464
  }
504
465
 
505
- // -------- [Run] -------- //
506
-
507
466
  const isRuntime = true || process.env.RUNTIME === "true";
508
467
 
509
468
  function run(projectPath) {
@@ -531,7 +490,6 @@ function run(projectPath) {
531
490
  console.warn("Project path not found", projectPath);
532
491
  }
533
492
  } catch (e) {
534
- // ignore
535
493
  console.error(e);
536
494
  }
537
495
  }
@@ -164,7 +164,7 @@ Actual: `+_.attribValue);else{var J=_.tag,le=_.tags[_.tags.length-1]||_;J.ns===l
164
164
  `)?t:`${t}
165
165
  `)},"writeStderrLine");var n0=a(t=>{let e=t.kind??"event",r=t.outcome?` ${t.outcome}`:"",n=typeof t.duration_ms=="number"?` ${t.duration_ms}ms`:"";return`${e}${r}${n}`.trim()},"defaultMessage"),i0=a((t,e,r)=>{let n=Date.now(),i={timestamp:new Date().toISOString(),kind:t,...e},s=!1,o={set(c){return Object.assign(i,c),o},emit(c){s||(s=!0,c&&Object.assign(i,c),i.duration_ms===void 0&&(i.duration_ms=Date.now()-n),r(i))}};return o},"startHandle"),s0=a((t={})=>{let e=t.decide??(()=>!0),r=t.deriveMessage??n0,n=t.label??"[wide-event]",i=t.sink??(c=>kp(c)),s=a(c=>{if(!e(c))return;let l={severity:Rp(c),message:c.message??r(c),...c};try{i(l)}catch(u){try{Mp(`${n} emit failed: ${String(u)}`)}catch{}}},"emit");return{emit:s,emitWideEvent:a((c,l={})=>{s({timestamp:new Date().toISOString(),kind:c,...l})},"emitWideEvent"),wideEvent:a((c,l={})=>i0(c,l,s),"wideEvent"),configureSink:a(c=>{i=c},"configureSink")}},"createWideEvents"),Pp=a(t=>t==="true"||t==="1","truthy"),Np=a(()=>Pp(process.env.CHECKSUM_WIDE_EVENTS)||Pp(process.env.WIDE_EVENT_PRETTY),"wideEventsEnabled"),xo=s0({decide:a(()=>Np(),"decide")}),Io=xo.configureSink,Zr=a((t,e={})=>xo.wideEvent(t,e),"wideEvent"),mr=a((t,e={})=>{xo.emitWideEvent(t,e)},"emitWideEvent"),tt=a(t=>t instanceof Error?{type:t.name,message:t.message}:{type:"UnknownError",message:String(t)},"toErrorField");async function Lp(t,e){let r;try{r=await t.json()}catch{r=void 0}return a0({ok:t.ok,status:t.status,body:r},e)}a(Lp,"assertOkJson");function a0(t,e){let r=t.body&&typeof t.body=="object"?t.body:void 0;if(!t.ok){let i=o0(r?.message);throw c0(new Error(`${e.resource} failed (HTTP ${t.status})`+(i?`: ${i}`:".")),t.status)}if(!r)throw new Error(`${e.resource} (HTTP ${t.status}) returned a non-object body; expected JSON.`);let n=(e.requiredFields??[]).filter(i=>!r[i]);if(n.length>0)throw new Error(`${e.resource} (HTTP ${t.status}) response is missing required field${n.length>1?"s":""}: ${n.join(", ")}.`);return r}a(a0,"assertJsonBody");function o0(t){return typeof t=="string"?t:Array.isArray(t)?t.filter(e=>typeof e=="string").join("; "):""}a(o0,"extractMessage");function c0(t,e){return Object.assign(t,{status:e})}a(c0,"withStatus");var Ji=a(t=>typeof t=="number"&&t>=400&&t<500&&t!==408&&t!==429,"isNonRetryableStatus");var Zi={uploadTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_TIMEOUT_MS",fallback:6e5,min:5e3,max:36e5},noProgressAbortMs:{env:"CHECKSUM_RUNTIME_UPLOAD_NO_PROGRESS_MS",fallback:6e4,min:5e3,max:6e5},assetDeadlineMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ASSET_DEADLINE_MS",fallback:12e5,min:3e4,max:54e5},maxAttempts:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_ATTEMPTS",fallback:6,min:1,max:20},stallTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_STALL_TIMEOUT_MS",fallback:6e5,min:3e4,max:36e5},minProgressBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_MIN_PROGRESS_BYTES",fallback:65536,min:1,max:67108864},finalizeBudgetMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_BUDGET_MS",fallback:18e5,min:6e4,max:54e5},finalizeCeilingMs:{env:"CHECKSUM_RUNTIME_UPLOAD_FINALIZE_CEILING_MS",fallback:24e5,min:12e4,max:72e5},cliHardCapMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CLI_HARD_CAP_MS",fallback:27e5,min:12e4,max:72e5},watchTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_WATCH_TIMEOUT_MS",fallback:12e4,min:5e3,max:18e5},ipcTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_IPC_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},onEndFlushTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_ONEND_FLUSH_TIMEOUT_MS",fallback:5e3,min:500,max:6e4},resumableChunkBytes:{env:"CHECKSUM_RUNTIME_UPLOAD_RESUMABLE_CHUNK_BYTES",fallback:8388608,min:262144,max:268435456},connectTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_CONNECT_TIMEOUT_MS",fallback:1e4,min:1e3,max:6e4},headersTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_HEADERS_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},bodyTimeoutMs:{env:"CHECKSUM_RUNTIME_UPLOAD_BODY_TIMEOUT_MS",fallback:3e5,min:5e3,max:18e5},maxConcurrentUploads:{env:"CHECKSUM_RUNTIME_UPLOAD_MAX_CONCURRENT",fallback:15,min:1,max:64}};function l0(t,e,r,n){if(t===void 0||t.trim()==="")return e;let i=Number(t);return Number.isInteger(i)?Math.min(n,Math.max(r,i)):e}a(l0,"clampEnvInt");var u0=[["cliHardCapMs",["finalizeCeilingMs"],.9],["finalizeCeilingMs",["finalizeBudgetMs"],1],["finalizeBudgetMs",["stallTimeoutMs","assetDeadlineMs","watchTimeoutMs"],1],["assetDeadlineMs",["uploadTimeoutMs"],1],["uploadTimeoutMs",["noProgressAbortMs"],.5]];function d0(t){let e={...t},r=[];for(let[n,i,s]of u0)for(let o of i){let c=Math.floor(e[n]*s);e[o]>c&&(r.push(`${Zi[o].env} (${e[o]}ms) exceeds its bound under ${Zi[n].env} (${e[n]}ms); using ${c}ms`),e[o]=c)}return{tunables:e,warnings:r}}a(d0,"coerceScopeHierarchy");function Ao(t){let e={};for(let r of Object.keys(Zi)){let n=Zi[r];e[r]=l0(t[n.env],n.fallback,n.min,n.max)}return e.resumableChunkBytes=Math.max(1,Math.floor(e.resumableChunkBytes/262144))*262144,d0(e)}a(Ao,"resolveUploadTunablesDetailed");function f0(t){return Ao(t).tunables}a(f0,"resolveUploadTunables");var Dp=f0({});var Up=new WeakMap,Co=new WeakMap;function $p(t,e){t.loadedBytes=0,t.committedBytes??=0,t.lastProgress=e,Up.set(t,t.committedBytes),Co.set(t,0)}a($p,"beginUpload");function Ro(t){t.loadedBytes=0,Co.set(t,0)}a(Ro,"resetAttemptBytes");var Fp=a(t=>(e,r,n,i)=>{let s=t.get(e)??0;return r-s<n?!1:(e.lastProgress=i,t.set(e,r),!0)},"stamperFor"),p0=Fp(Co),m0=Fp(Up);function Oo(t,e,r,n){return t.loadedBytes=e,p0(t,e,r,n)}a(Oo,"recordSent");function ko(t,e,r,n){let i=Math.max(t.committedBytes??0,e);return t.committedBytes=i,m0(t,i,r,n)}a(ko,"recordCommitted");var Xi=require("fs"),jp=require("stream");function Yi(t,{baseMs:e,capMs:r,random:n=Math.random}){let i=Math.min(r,e*2**(t-1));return i/2+n()*(i/2)}a(Yi,"jitteredBackoffMs");async function Yr(t){await t.body?.cancel().catch(()=>{})}a(Yr,"drainBody");var No=a(t=>t===200||t===201,"isStored"),Hp=a(t=>t===308,"isResumeIncomplete"),h0=a(t=>t===404||t===410,"isSessionGoneStatus"),zp=a((t,e)=>{let r=t?.match(/bytes=0-(\d+)/);return r?Number(r[1])+1:e},"nextOffsetFromRange"),g0=a((t,e,r)=>e<=t?`bytes */${r}`:`bytes ${t}-${e-1}/${r}`,"contentRangeFor");function y0(t,e,r){let n=e,i=new TransformStream({transform(s,o){n+=s.byteLength,r?.(n),o.enqueue(s)}});return jp.Readable.toWeb(t).pipeThrough(i)}a(y0,"countingBody");var rt=class extends Error{constructor(r,n){super(r);this.status=n;this.name="ResumableUploadError"}static{a(this,"ResumableUploadError")}},Gp=a(t=>t instanceof rt?t.status:void 0,"statusOf"),_0=a(t=>{let e=Gp(t);return e!==void 0&&h0(e)},"isSessionGone"),b0=a(t=>Ji(Gp(t)),"isPermanent");async function w0(t,e,r,n){let i=await r(t,{method:"POST",headers:{"x-goog-resumable":"start","Content-Type":e,"Content-Length":"0"},signal:n});if(await Yr(i),!No(i.status))throw new rt(`resumable init failed with status ${i.status}`,i.status);let s=i.headers.get("Location");if(!s)throw new rt("resumable init returned no Location");return s}a(w0,"initResumableSession");async function E0(t,e,r,n){let i=await r(t,{method:"PUT",headers:{"Content-Range":`bytes */${e}`},signal:n});if(await Yr(i),No(i.status))return{done:!0,offset:e};if(!Hp(i.status))throw new rt(`offset query failed with status ${i.status}`,i.status);return{done:!1,offset:zp(i.headers.get("Range"),0)}}a(E0,"queryCommittedOffset");async function Bp(t,e,{offset:r,endExclusive:n},i){let s=Math.max(0,(0,Xi.statSync)(t.filePath).size-r),o=Math.min(Math.max(0,n-r),s),c=r+o,l=o>0?(0,Xi.createReadStream)(t.filePath,{start:r,end:c-1}):void 0;try{let u={method:"PUT",headers:{"Content-Range":g0(r,c,t.size),"Content-Length":String(o)},duplex:"half",signal:i,...l?{body:y0(l,r,t.onSent)}:{}},d=await t.fetchImpl(e,u);if(await Yr(d),No(d.status))return{stored:!0,committed:t.size};if(Hp(d.status))return{stored:!1,committed:zp(d.headers.get("Range"),r)};throw new rt(`resumable PUT failed with status ${d.status}`,d.status)}finally{l?.destroy()}}a(Bp,"putChunk");async function T0(t,e,r,n){let i=r;for(;i<t.size;){let o=Math.min(i+t.chunkSizeBytes,t.size),{stored:c,committed:l}=await Bp(t,e,{offset:i,endExclusive:o},n);if(c){t.onCommitted?.(t.size);return}if(l<=i)throw new rt("resumable PUT made no forward progress");i=l,t.onCommitted?.(i)}let{stored:s}=await Bp(t,e,{offset:t.size,endExclusive:t.size},n);if(!s)throw new rt("resumable upload did not finalize");t.onCommitted?.(t.size)}a(T0,"sendFrom");async function v0(t,e,r){if(e.url)return e.url;if(!t.target.initUrl)throw new rt("no resumable target provided");return e.url=await w0(t.target.initUrl,t.contentType,t.fetchImpl,r),e.used=!1,e.url}a(v0,"openSession");async function S0(t,e,r,n){if(!r)return 0;let i=await E0(e,t.size,t.fetchImpl,n);if(!i.done)return t.onCommitted?.(i.offset),i.offset}a(S0,"resumePoint");async function x0(t,e,r){let n=await v0(t,e,r),i=await S0(t,n,e.used,r);if(e.used=!0,i===void 0){t.onCommitted?.(t.size);return}await T0(t,n,i,r)}a(x0,"runAttempt");function I0(t,e,r){return _0(t)&&e.target.initUrl?(r.url=void 0,r.used=!1,"retry"):b0(t)?"stop":"retry"}a(I0,"afterFailure");async function Vp(t){let e={url:t.target.sessionUrl,used:!1},r;for(let n=1;n<=t.maxAttempts&&!(t.now()>=t.deadlineAt);n++)try{await x0(t,e,t.makeSignal());return}catch(i){if(r=i,I0(i,t,e)==="stop"||n>=t.maxAttempts)break;await t.sleep(Yi(n,{baseMs:1e3,capMs:16e3,...t.random?{random:t.random}:{}}))}throw r instanceof Error?r:new rt(`resumable upload failed: ${String(r)}`)}a(Vp,"uploadResumable");var A0=a(t=>{if(typeof t!="object"||t===null)return"network_error";let e="name"in t&&typeof t.name=="string"?t.name:"";if(e==="TimeoutError")return"timeout";if(e==="AbortError")return"no_progress_abort";let r="cause"in t?t.cause:void 0,n=typeof r=="object"&&r!==null&&"code"in r&&typeof r.code=="string"?r.code:void 0;if(n==="UND_ERR_CONNECT_TIMEOUT"||n==="UND_ERR_HEADERS_TIMEOUT"||n==="UND_ERR_BODY_TIMEOUT")return"timeout";if(n!==void 0&&n.length>0)return`network_error:${n}`;let i="message"in t&&typeof t.message=="string"?t.message:"";return i.startsWith("Upload failed with status")?"http_error":i.startsWith("get-upload-url")?"signed_url_error":i.includes("No upload URL")?"signed_url_missing":"network_error"},"classifyUploadError"),C0=a(t=>Math.max(1e3,Math.min(1e4,Math.floor(t/4))),"noProgressPollMs"),Qi=class{constructor(e,r,n,i,s=!1,o={start:a(u=>{},"start"),complete:a(u=>{},"complete"),error:a((u,d)=>{},"error")},c,l={}){this.apiBaseURL=e;this.apiKey=r;this.uploadTimeout=n;this.makeGetUploadUrlAPIPath=i;this.isolationMode=s;this.reporter=o;this.sessionId=c;this.SIGNED_URL_TIMEOUT_MS=3e4;this.tunables=l.tunables??Dp,this.fetchImpl=l.fetchImpl??globalThis.fetch,this.now=l.now??Date.now,this.MAX_ATTEMPTS=this.tunables.maxAttempts,this.PUT_NO_PROGRESS_ABORT_MS=this.tunables.noProgressAbortMs,this.ASSET_DEADLINE_MS=this.tunables.assetDeadlineMs,this.MIN_PROGRESS_BYTES=this.tunables.minProgressBytes}static{a(this,"TestAssetUploader")}async uploadAsset(e){if(e.uploadStarted=!0,this.isolationMode){e.lastProgress=Date.now(),e.loadedBytes=0,e.sizeBytes=100,e.response=new Promise(o=>{setTimeout(()=>{e.complete=!0,e.lastProgress=Date.now(),e.loadedBytes=100,o({statusCode:200,ok:!0,body:"OK"})},10)});return}let{path:r}=e.info,n=this.now()+this.ASSET_DEADLINE_MS,i=Zr("asset_upload",{test_suite_run_id:this.sessionId,asset_type:e.info.type,file_name:e.info.fileName??(0,Wp.basename)(r),test_id:e.info.testId,project:e.info.project}),s=[];try{let c=(0,es.statSync)(r).size;e.sizeBytes=c,$p(e,this.now()),i.set({size_bytes:c}),this.reporter.start(r);let l;for(let u=1;u<=this.MAX_ATTEMPTS&&!(this.now()>=n);u++){let d={attempt:u};try{let f=this.now();if(await this.getSignedURLForUpload(e),d.signed_url_ms=this.now()-f,!e.uploadURL)throw new Error("No upload URL returned");let y=this.now();d.resumable=e.resumable===!0,e.resumable?await this.putResumable(e,r,c,n):await this.putWithWatchdog(e,r,c),d.put_ms=this.now()-y,d.loaded_bytes=e.loadedBytes,d.committed_bytes=e.committedBytes,s.push(d),this.reporter.complete(r),e.complete=!0,i.emit({outcome:"success",attempt_count:s.length,attempts:s,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes});return}catch(f){l=f,d.loaded_bytes=e.loadedBytes,d.committed_bytes=e.committedBytes,d.failure_reason=A0(f),d.error=tt(f);let y=Ji(typeof f=="object"&&f!==null&&"status"in f?f.status:void 0);d.non_retryable=y,delete e.uploadURL;let h=y?"non_retryable":e.resumable?"resumable_owns_retries":u>=this.MAX_ATTEMPTS?"max_attempts":this.now()>=n?"asset_deadline":void 0;if(d.retry_stop_reason=h,s.push(d),h)break;await this.backoff(u,n)}}this.reporter.error(r,l),e.error=!0,i.emit({outcome:"error",attempt_count:s.length,attempts:s,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,deadline_exceeded:this.now()>=n,error:tt(l)})}catch(o){this.reporter.error(r,o),e.error=!0,i.emit({outcome:"error",failure_reason:"pre_upload",attempt_count:s.length,attempts:s,error:tt(o)})}}async putWithWatchdog(e,r,n){let i=e.uploadURL;if(!i)throw new Error("No upload URL returned");let s=new AbortController,o=this.uploadTimeout??void 0;Ro(e);let c=this.armNoProgressWatchdog(e,()=>s.abort()),l=o!==void 0?setTimeout(()=>s.abort(new DOMException("upload attempt timeout","TimeoutError")),o):void 0,u=(0,es.createReadStream)(r),d=0,f=this.MIN_PROGRESS_BYTES,y=this.now,h=new TransformStream({transform(w,v){d+=w.byteLength,e.sizeBytes=n,Oo(e,d,f,y()),v.enqueue(w)}}),g=qp.Readable.toWeb(u).pipeThrough(h),b={method:"PUT",headers:{"Content-Type":vo[e.info.type]??""},body:g,duplex:"half",signal:s.signal};try{let w=await this.fetchImpl(i,b);if(!w.ok)throw await Yr(w),Object.assign(new Error(`Upload failed with status ${w.status}`),{status:w.status});ko(e,n,this.MIN_PROGRESS_BYTES,this.now()),e.response=Promise.resolve(await w.text())}finally{clearInterval(c),clearTimeout(l),u.destroy()}}armNoProgressWatchdog(e,r){let n=-1,i=this.now();return setInterval(()=>{let s=Math.max(e.loadedBytes??0,e.committedBytes??0);s>n?(n=s,i=this.now()):this.now()-i>this.PUT_NO_PROGRESS_ABORT_MS&&r()},C0(this.PUT_NO_PROGRESS_ABORT_MS))}async putResumable(e,r,n,i){let s=e.uploadURL;if(!s)throw new Error("No upload URL returned");Ro(e);let o=this.uploadTimeout??this.tunables.uploadTimeoutMs,c,l,u=a(()=>(clearInterval(l),c=new AbortController,l=this.armNoProgressWatchdog(e,()=>c?.abort()),c.signal),"armAttempt");try{await Vp({target:{initUrl:s},filePath:r,size:n,contentType:vo[e.info.type]??"",fetchImpl:this.fetchImpl,makeSignal:a(()=>AbortSignal.any([u(),AbortSignal.timeout(o)]),"makeSignal"),maxAttempts:this.MAX_ATTEMPTS,deadlineAt:i,chunkSizeBytes:this.tunables.resumableChunkBytes,now:this.now,sleep:a(d=>new Promise(f=>setTimeout(f,d)),"sleep"),onSent:a(d=>Oo(e,d,this.MIN_PROGRESS_BYTES,this.now()),"onSent"),onCommitted:a(d=>ko(e,d,this.MIN_PROGRESS_BYTES,this.now()),"onCommitted")})}finally{clearInterval(l)}e.response=Promise.resolve("OK")}async backoff(e,r){let n=Yi(e,{baseMs:1e3,capMs:16e3}),i=Math.max(0,Math.min(n,r-this.now()));i>0&&await new Promise(s=>setTimeout(s,i))}async getSignedURLForUpload(e){let r=new AbortController,n=setTimeout(()=>r.abort(),this.SIGNED_URL_TIMEOUT_MS);try{let i=JSON.stringify(e.info),s=`${this.apiBaseURL}/${this.makeGetUploadUrlAPIPath(e)}`,o={Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.apiKey},c=await this.fetchImpl(s,{method:"POST",headers:o,body:i,signal:r.signal}),{url:l,resumable:u}=await Lp(c,{resource:"get-upload-url",requiredFields:["url"]});e.uploadURL=l,e.resumable=u===!0}catch(i){throw delete e.uploadURL,i}finally{clearTimeout(n)}}};function ts(t,e,r=Date.now()){let n=t.filter(s=>!s.complete&&!s.error);if(n.length===0)return!1;let i=n.reduce((s,o)=>Math.max(s,o.lastProgress??0),0);return i>0&&r-i>e}a(ts,"isUploadStalled");function rs(t,e,r){return t!==void 0&&r-t>e}a(rs,"hasElapsedSinceTestEnd");function Kp(t,e,r){return rs(e.testRunEndTime,e.finalizeBudgetMs,r)?!0:t===void 0?!1:t.complete||t.error?!0:ts([t],e.stallTimeoutMs,r)}a(Kp,"shouldStopWaitingForReport");function Jp(t){return t.abandonedAssets.length===0}a(Jp,"mayCleanUpSources");function R0(t,e,r){if((e.length===0||ts(t.assets,t.stallTimeoutMs,r))&&rs(t.testRunEndTime,t.finalizeBudgetMs,r))return"budget";if(rs(t.testRunEndTime,t.finalizeCeilingMs,r))return"budget-ceiling"}a(R0,"backstopReason");function Zp(t,e){let r=t.assets.filter(s=>!s.complete&&!s.error),n=a(s=>({reason:s,abandonedAssets:r}),"decide"),i=R0(t,r,e);if(i!==void 0)return n(i);if(!(t.processingInProgress||!t.doneWaitingForReport)&&!(r.length>0&&!ts(t.assets,t.stallTimeoutMs,e))&&!(t.pendingWatchCount>0&&!rs(t.testRunEndTime,t.watchTimeoutMs,e)))return r.length>0?n("stall"):t.pendingWatchCount>0?n("watch-timeout"):n("complete")}a(Zp,"decideFinalize");var Yp=require("module");var O0=(0,Yp.createRequire)(__filename);function Xp(t){let e,r;try{e=O0("undici"),r=new e.Agent({connect:{timeout:t.connectTimeoutMs},headersTimeout:t.headersTimeoutMs,bodyTimeout:t.bodyTimeoutMs,keepAliveTimeout:1e4,keepAliveMaxTimeout:3e4})}catch(i){return mr("monitor_dispatcher_unavailable",{outcome:"error",error:tt(i)}),process.emitWarning("@checksum-ai/runtime: undici dispatcher unavailable; upload timeouts fall back to the platform defaults",{detail:String(i)}),globalThis.fetch}let n=e.fetch;return(i,s)=>{let o={...s,dispatcher:r};return n(i,o)}}a(Xp,"createMonitorFetch");var Lo=class{static{a(this,"CLIChannel")}constructor(){}sendToCLI(...e){let r=`{trm}${e.map(n=>n.toString()).join(`,
166
166
  `)}{/trm}`;process.stdout.write(`${r}
167
- `)}event(e,r){return new Promise(n=>{let i=r?`${e}=${r}`:e;setTimeout(()=>{this.sendToCLI(`monitor:${i}`),n(!0)},100)})}trace(e,r){let n=r?`${e}=${JSON.stringify(r)}`:e;setTimeout(()=>{this.sendToCLI(`trace:${n}`)},100)}log(e){return this.event("log",e)}debug(...e){this.sendToCLI(e)}wideEvent(e){let r=Buffer.from(JSON.stringify(e),"utf-8").toString("base64");this.sendToCLI(`wideevent:${r}`)}},ns=class{constructor(e,r=!1){this.config=e;this.isolationMode=r;this.tunablesResolution=Ao(process.env);this.tunables=this.tunablesResolution.tunables;this.MAX_UPLOADS=this.tunables.maxConcurrentUploads;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=this.tunables.uploadTimeoutMs;this.UPLOAD_STALL_TIMEOUT=this.tunables.stallTimeoutMs;this.WATCH_TIMEOUT=this.tunables.watchTimeoutMs;this.FINALIZE_BUDGET=this.tunables.finalizeBudgetMs;this.FINALIZE_CEILING=this.tunables.finalizeCeilingMs;this.SHUTDOWN_FLUSH_TIMEOUT=2e3;this.assets=[];this.watchAssets=[];this.processingPaths=new Set;this.doneWaitingForReport=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.checksumTestIdToUsingPlaceholder={};this.progressFlushInFlight=!1;this.stallEventEmitted=!1;this.channel=new Lo,Io(n=>this.channel.wideEvent(n)),this.testAssetUploader=new Qi(e.apiURL,e.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:a(n=>this.channel.trace("Upload Start",{filename:n}),"start"),complete:a(n=>{if(!this.reportAsset||n!==this.reportAsset.info.path)try{(0,ce.unlinkSync)(n),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${n}`)}catch(i){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${n}`,i)}this.channel.trace("Upload Complete",{filename:n})},"complete"),error:a((n,i)=>this.channel.trace("Upload Failed",{filename:n,error:i}),"error")},e.sessionId,{fetchImpl:Xp(this.tunables),tunables:this.tunables}),this.uploadMonitorInterval=setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL);for(let n of this.tunablesResolution.warnings)this.channel.debug(`[upload-tunables] ${n}`),mr("upload_tunable_coerced",{warning:n});this.listenForMessages(),this.startServer()}static{a(this,"TestRunMonitor")}listenForMessages(){process.stdin.on("data",e=>{(async()=>{let r=e.toString().trim();if(!r.startsWith("cli:"))return;let[n,i]=r.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+n+" "+i),n){case"report":if(this.testRunEndTime=Date.now(),i!=="false")try{let s=Buffer.from(i??"","base64").toString("utf-8"),o=JSON.parse(s);await this.handleReport(o)}catch(s){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(s)),this.stopWaitingForReport("failed")}else this.stopWaitingForReport("not-requested");this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})()})}async readMetadataFile(e){try{let r=await(0,em.readFile)(e,"utf-8");return JSON.parse(r)}catch(r){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${e}: ${r.message}`),{}}}async serveReport(e){try{let r=(0,Be.dirname)(e);await this.channel.log("Serving report in browser: "+r);let n=zi.isRepoMode?`yarn playwright show-report ${r}`:`npx playwright show-report ${r}`;(0,Qp.execSync)(n,{encoding:"utf8",stdio:"pipe"}),await this.channel.log("Success: Report opened in browser")}catch(r){await this.channel.log(`Error serving report in browser: ${r.message}`),r.stderr&&await this.channel.log(r.stderr.toString())}}async handleReport(e){let{reportPath:r,pathToChecksumMetadata:n,didFail:i,openReportCriteria:s,checksumRoot:o,projectRoot:c,isUploadReport:l,dedupeByChecksumTestId:u}=e;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+r),this.uploadReportData((0,Be.dirname)(r),l);let d=Zr("report_processing",{test_suite_run_id:this.config.sessionId,report_path:r,isolation_mode:this.isolationMode,is_upload_report:!!l});try{let f=await this.readMetadataFile(n),y=new Ki(r,this.config.sessionId,this.pwTestIdToChecksumTestId,f,{hosted:!this.isolationMode,...u?{dedupeByChecksumTestId:u}:{}},this.channel,o,c,this.checksumTestIdToUsingPlaceholder),h=this.initAsset({type:"report",path:""});this.reportAsset=h;try{let w=await y.process();h.info.path=y.getProcessedFilePath(),d.set({processed_path:h.info.path,...w}),this.uploadAsset(h)}catch(w){this.channel.debug("Error processing report, "+w.message),h.error=!0,d.set({error:tt(w)})}let g=y.getReportsStats();this.stats=g,_f(d,h.error?"error":"success",g),this.channel.debug("Checking watch assets");let b=this.watchAssets.filter(w=>!(w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??"")));b.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify(b.map(w=>w.path)))),this.watchAssets=this.watchAssets.filter(w=>w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??""))}catch(f){this.channel.debug("Error processing report, "+this.stringify(f)),this.reportAsset&&(this.reportAsset.error=!0),d.emit({outcome:"error",error:tt(f)})}finally{if((s==="always"||s==="on-failure"&&i)&&await this.serveReport(r),n&&(0,ce.existsSync)(n))try{(0,ce.unlinkSync)(n)}catch(y){console.error(`Error deleting checksum metadata file ${n}: ${y.message}`)}}}async uploadReportData(e,r){let n=(0,Be.join)(e,"data");try{let i=(0,ce.readdirSync)(n),s=r?[".webm"]:[".zip",".webm"],o=i.filter(c=>!s.includes((0,Be.extname)(c)));this.channel.debug("Preparing to upload report data files,"+o);for(let c of o)this.channel.debug("Uploading report data file,"+c),this.addAsset({type:"report-data-file",fileName:c,path:`${n}/${c}`})}catch(i){this.channel.debug(`Error reading/adding report data files from dir ${n}`+i.message)}}shutdown(){clearInterval(this.uploadMonitorInterval);try{this.server?.closeAllConnections?.(),this.server?.close?.()}catch{}this.channel.debug("Received shutdown message from CLI"),process.stdout.write("",()=>process.exit(0)),setTimeout(()=>process.exit(0),this.SHUTDOWN_FLUSH_TIMEOUT).unref()}async monitorUploadsCompletion(){let e=Date.now();!this.doneWaitingForReport&&Kp(this.reportAsset,{testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET},e)&&this.settleReport();let r=Zp({assets:this.assets,processingInProgress:this.processingInProgress,doneWaitingForReport:this.doneWaitingForReport,pendingWatchCount:this.watchAssets.length,testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,watchTimeoutMs:this.WATCH_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET,finalizeCeilingMs:this.FINALIZE_CEILING},e);if(!r){await cs(1e3),this.monitorUploadsCompletion();return}this.finalizeRun(r,e)}stopWaitingForReport(e){this.doneWaitingForReport=!0,this.reportOutcome=e}reportAssetOutcome(){return this.reportAsset?.complete?"uploaded":this.reportAsset?.error?"failed":"abandoned"}settleReport(){this.stopWaitingForReport(this.reportAssetOutcome());let e="";try{let r=JSON.stringify(this.stats??{}),n=`checksum-stats-${(0,An.randomBytes)(8).toString("hex")}.json`;e=(0,Be.join)((0,im.tmpdir)(),n),(0,ce.writeFileSync)(e,r,"utf-8"),this.channel.debug(`Stats written to temporary file: ${e}`)}catch(r){this.channel.debug("Error writing stats to file"),this.channel.log(`[monitorUploadsCompletion] Error writing stats to file: ${r.message}`)}this.channel.event("report-complete",`${this.reportOutcome==="uploaded"?"true":"false"}:${e}`)}finalizeRun(e,r){e.reason==="stall"&&this.emitStallDetected(e.abandonedAssets,r),e.abandonedAssets.forEach(o=>{o.error=!0});let n=this.assets.some(o=>o.error)?"uploads-complete-with-errors":"uploads-complete",i=this.assets.filter(o=>o.error);mr("uploads_completion",{test_suite_run_id:this.config.sessionId,outcome:i.length>0?"error":"success",decision:n,total_assets:this.assets.length,completed:this.assets.filter(o=>o.complete).length,errored:i.length,stalled:e.abandonedAssets.length>0,stalled_count:e.abandonedAssets.length,finalize_reason:e.reason,finalize_budget_ms:this.FINALIZE_BUDGET,finalize_ceiling_ms:this.FINALIZE_CEILING,watch_remaining:this.watchAssets.length,report_outcome:this.reportOutcome,upload_finalize_ms:this.testRunEndTime?r-this.testRunEndTime:void 0,errored_assets:i.map(o=>this.assetSnapshot(o,r))});let s=n==="uploads-complete"?{}:{uploadErrors:i.map(o=>{try{return JSON.stringify(o)}catch{return o.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:r,finalizeReason:e.reason,abandonedAssets:e.abandonedAssets.map(o=>this.assetSnapshot(o,r))};if(Jp(e))try{this.cleanUp()}catch(o){this.channel.debug("cleanUp failed (ignored): "+o?.message)}else this.channel.debug(`skipping cleanUp: ${e.abandonedAssets.length} asset(s) abandoned (${e.reason})`);this.channel.event(n,JSON.stringify(s))}assetSnapshot(e,r){return{file_name:e.info.fileName??(0,Be.basename)(e.info.path),asset_type:e.info.type,test_id:e.info.testId,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,last_progress_age_ms:e.lastProgress?r-e.lastProgress:void 0}}cleanUp(){let e;for(let r of this.assets)if(r.info.type==="rrweb-recording"){e=(0,Be.dirname)(r.info.path);break}e&&(0,ce.rmSync)(e,{recursive:!0,force:!0})}emitStallDetected(e,r){this.channel.log("Uploads are stalled"),!this.stallEventEmitted&&(this.stallEventEmitted=!0,mr("upload_stall_detected",{test_suite_run_id:this.config.sessionId,outcome:"error",timeout_ms:this.UPLOAD_STALL_TIMEOUT,total_assets:this.assets.length,pending_count:e.length,pending_assets:e.map(n=>this.assetSnapshot(n,r))}))}async startServer(){let e=await this.acquirePortNumber();this.channel.event("port",e.toString()),this.server=(0,rm.createServer)((r,n)=>{let i=a(o=>{n.writeHead(400,{"Content-Type":"text/plain"}),n.end(o)},"returnErrorWithMessage");if(r.method!=="POST"){n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Method not allowed");return}let s="";r.on("data",o=>{s+=o.toString()}),r.on("end",()=>{let o;try{o=JSON.parse(s)}catch{i("Invalid body");return}let{type:c,payload:l,watch:u}=o;switch(this.channel.debug(`Server received message, ${c}, ${this.stringify(l)}`),c){case"asset":if(!l.path||!l.type){i("Missing arguments");return}u?this.watchAsset(l):this.processAsset(l);break;case"testInfo":if(!l.pwTestId||!l.checksumTestId){i("Missing arguments");return}this.pwTestIdToChecksumTestId[l.pwTestId]=l.checksumTestId,l.usingChecksumTestIdPlaceholder!==void 0&&(this.checksumTestIdToUsingPlaceholder[l.checksumTestId]=l.usingChecksumTestIdPlaceholder);break;case"checksumTestMetadata":{let d=l;if(!d.checksumTestId||!l.data){i("Missing arguments");return}this.channel.event("checksumTestMetadata",JSON.stringify({...d}));break}case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(l));break;case"runProgress":this.forwardProgress(l);break;default:i("Invalid message type");return}n.writeHead(200,{"Content-Type":"text/plain"}),n.end("OK")})}),this.server.listen(e)}forwardProgress(e){this.latestProgress=e,!this.progressFlushInFlight&&this.flushProgress()}async flushProgress(){this.progressFlushInFlight=!0;try{for(;this.latestProgress;){let e=this.latestProgress;this.latestProgress=void 0,await this.patchProgress(e)}}finally{this.progressFlushInFlight=!1}}async patchProgress(e){if(this.isolationMode)return;let r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{await fetch(`${this.config.apiURL}/client-api/test-runs/${this.config.sessionId}/progress`,{method:"PATCH",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:JSON.stringify({progress:e}),signal:r.signal})}catch(i){this.channel.debug("Failed to send run progress: "+i?.message)}finally{clearTimeout(n)}}stringify(e){try{return JSON.stringify(e)}catch{return"message"in e?e.message:e}}monitorUploads(){let{totalSizeBytes:e,totalUploadedBytes:r}=this.calculateUploadProgress();if(e>0&&!this.isolationMode){let s=(r/e*100).toFixed(2);this.channel.event("upload-progress",s)}let n=this.assets.filter(s=>!s.uploadStarted);if(n.length===0)return;let i=a(()=>this.assets.filter(s=>s.uploadStarted&&!s.complete&&!s.error).length,"getNumOfActiveUploads");if(!(i()>=this.MAX_UPLOADS))for(;n.length>0&&i()<this.MAX_UPLOADS;){let s=n.pop();if(s===void 0)break;this.uploadAsset(s)}}calculateUploadProgress(){let e=this.assets.reduce((n,{sizeBytes:i})=>n+(i??0),0),r=Math.min(e,this.assets.reduce((n,{loadedBytes:i})=>n+(i??0),0));return{totalSizeBytes:e,totalUploadedBytes:r}}getUploadLogMessage(e){switch(e.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${e.info.testId}`;case"trace":return`Uploading trace file for test ${e.info.testId}`;case"esra":return`Uploading metadata file for test ${e.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${e.info.path}`;default:return}}async uploadAsset(e){try{e.uploadStarted=!0;let r=this.getUploadLogMessage(e);r&&!this.isolationMode&&this.channel.event("log",r),await this.testAssetUploader.uploadAsset(e)}catch(r){e.error=!0,this.channel.debug("Error uploading asset"+this.stringify(r)),this.channel.trace("Upload Failed",{asset:e.info.fileName,error:String(r)})}}watchAsset(e){if(this.watchAssets.some(n=>n.path===e.path)){this.channel.debug(`Already watching file ${e.path}, skipping duplicate`);return}this.channel.debug("Watching file "+e.path),this.watchAssets.push({...e,addedAt:Date.now()});let r=a(async()=>{await this.waitForFileComplete(e.path)&&(this.processAsset(e),this.watchAssets=this.watchAssets.filter(i=>i.path!==e.path))},"waitForCompletion");if((0,ce.existsSync)(e.path))r();else{let n=(0,Be.dirname)(e.path),i=(0,Be.basename)(e.path),s=!1,o=(0,ce.watch)(n,(c,l)=>{(async()=>{if(!(l!==i||s))try{this.channel.debug("Watched file changed "+e.path),s=!0,await r()}finally{o.close()}})()})}}waitForFileComplete(e,r=1e3,n=6e4,i=1){return new Promise(s=>{let o=Date.now(),c=0,l=i,u=a(()=>{if(!(0,ce.existsSync)(e)){this.channel.debug(`Asset required for upload doesn't exist anymore ${e}`),s(!1);return}let d=(0,ce.statSync)(e).size;if(d===c){if(l>0){this.channel.debug(`File size has not changed, verifying stabilization, ${e}, size: ${d}, equalSizeValidationCountLeft: ${l}`),l--,setTimeout(u,r);return}this.channel.debug(`File size has not changed, stabilization verified, ${e}, size: ${d}`),s(!0);return}if(this.channel.debug(`File size changed, waiting for stabilization, ${e}, previous size: ${c}, current size: ${d}`),Date.now()-o>n){this.channel.debug(`Asset required for upload is taking over ${n} ms to write to disk ${e}`),s(!0);return}c=d,setTimeout(u,r)},"checkFile");u()})}processAsset(e){switch(e.type){case"trace":return this.processTrace(e.path,e.testId);case"har":return this.processHar();case"rrweb-recording":case"esra":case"test-files":return this.addAsset(e);default:return}}async processHar(){}async calculateFileSha1Streaming(e){let r=(0,An.createHash)("sha1"),n=(0,ce.createReadStream)(e);return await(0,tm.pipeline)(n,r),r.digest("hex")}async processTrace(e,r){if(this.processingPaths.has(e)){this.channel.debug(`Trace file ${e} already being processed, skipping`);return}this.processingPaths.add(e);let n;try{this.processingInProgress=!0,await cs(1e3),n=Zr("trace_processing",{test_suite_run_id:this.config.sessionId,test_id:r});let i=e;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${r})...`),i=e.replace(".zip",".actual.zip"),(0,ce.renameSync)(e,i);let c="checksum-playwright-trace:"+Date.now().toString()+(0,An.randomBytes)(1024).toString("hex");(0,ce.writeFileSync)(e,c)}let o=await a(async()=>await this.calculateFileSha1Streaming(e)+(0,Be.extname)(e),"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${r} has been manipulated with file name ${o}, sending for upload...`),this.addAsset({type:"report-data-file",path:i,...r!==void 0?{testId:r}:{},fileName:o}),n.emit({outcome:"success",file_name:o})}catch(i){let s=String(i);this.channel.debug("Error processing trace file"+s),this.channel.trace("Trace Processing Error",{error:s}),n?.emit({outcome:"error",error:tt(i)})}finally{this.processingPaths.delete(e),this.processingInProgress=!1}}addAsset(e){this.channel.debug("Adding file "+e.path);let r=this.initAsset(e);return this.assets.push(r),r}initAsset(e){return{complete:!1,error:!1,info:e,removeAfterUpload:e.type==="rrweb-recording"}}async acquirePortNumber(){return new Promise((e,r)=>{let n=nm.createServer();n.unref(),n.on("error",r),n.listen(0,()=>{let i=n.address().port;n.close(()=>{e(i)})})})}},sm;try{sm=JSON.parse(process.argv[2]??"")}catch(t){console.error("Error starting test run monitor",t),process.exit(1)}new ns(sm,process.argv[3]==="isolated");0&&(module.exports={TestRunMonitor});
167
+ `)}event(e,r){return new Promise(n=>{let i=r?`${e}=${r}`:e;setTimeout(()=>{this.sendToCLI(`monitor:${i}`),n(!0)},100)})}trace(e,r){let n=r?`${e}=${JSON.stringify(r)}`:e;setTimeout(()=>{this.sendToCLI(`trace:${n}`)},100)}log(e){return this.event("log",e)}debug(...e){this.sendToCLI(e)}wideEvent(e){let r=Buffer.from(JSON.stringify(e),"utf-8").toString("base64");this.sendToCLI(`wideevent:${r}`)}},ns=class{constructor(e,r=!1){this.config=e;this.isolationMode=r;this.tunablesResolution=Ao(process.env);this.tunables=this.tunablesResolution.tunables;this.MAX_UPLOADS=this.tunables.maxConcurrentUploads;this.MONITOR_INTERVAL=2500;this.UPLOAD_TIMEOUT=this.tunables.uploadTimeoutMs;this.UPLOAD_STALL_TIMEOUT=this.tunables.stallTimeoutMs;this.WATCH_TIMEOUT=this.tunables.watchTimeoutMs;this.FINALIZE_BUDGET=this.tunables.finalizeBudgetMs;this.FINALIZE_CEILING=this.tunables.finalizeCeilingMs;this.SHUTDOWN_FLUSH_TIMEOUT=2e3;this.assets=[];this.watchAssets=[];this.processingPaths=new Set;this.doneWaitingForReport=!1;this.processingInProgress=!1;this.pwTestIdToChecksumTestId={};this.checksumTestIdToUsingPlaceholder={};this.progressFlushInFlight=!1;this.stallEventEmitted=!1;this.channel=new Lo,Io(n=>this.channel.wideEvent(n)),this.testAssetUploader=new Qi(e.apiURL,e.apiKey,this.UPLOAD_TIMEOUT,()=>`client-api/test-runs/${this.config.sessionId}/get-upload-url`,this.isolationMode,{start:a(n=>this.channel.trace("Upload Start",{filename:n}),"start"),complete:a(n=>{if(!this.reportAsset||n!==this.reportAsset.info.path)try{(0,ce.unlinkSync)(n),this.channel.debug(`[TestAssetUploader] Deleted file after successful upload: ${n}`)}catch(i){this.channel.debug(`[TestAssetUploader] Failed to delete file after upload: ${n}`,i)}this.channel.trace("Upload Complete",{filename:n})},"complete"),error:a((n,i)=>this.channel.trace("Upload Failed",{filename:n,error:i}),"error")},e.sessionId,{fetchImpl:Xp(this.tunables),tunables:this.tunables}),this.uploadMonitorInterval=setInterval(this.monitorUploads.bind(this),this.MONITOR_INTERVAL);for(let n of this.tunablesResolution.warnings)this.channel.debug(`[upload-tunables] ${n}`),mr("upload_tunable_coerced",{warning:n});this.listenForMessages(),this.startServer()}static{a(this,"TestRunMonitor")}listenForMessages(){process.stdin.on("data",e=>{(async()=>{let r=e.toString().trim();if(!r.startsWith("cli:"))return;let[n,i]=r.substring(4).split("=");switch(this.channel.debug("Received message from CLI "+n+" "+i),n){case"report":if(this.testRunEndTime=Date.now(),i!=="false")try{let s=Buffer.from(i??"","base64").toString("utf-8"),o=JSON.parse(s);await this.handleReport(o)}catch(s){this.channel.debug("Error JSON parsing report payload, continue without report. Error: "+this.stringify(s)),this.stopWaitingForReport("failed")}else this.stopWaitingForReport("not-requested");this.monitorUploadsCompletion();break;case"shutdown":this.shutdown();break}})()})}async readMetadataFile(e){try{let r=await(0,em.readFile)(e,"utf-8");return JSON.parse(r)}catch(r){return this.channel.trace("Runtime Error",`Error reading checksum metadata file ${e}: ${r.message}`),{}}}async serveReport(e){try{let r=(0,Be.dirname)(e);await this.channel.log("Serving report in browser: "+r);let n=zi.isRepoMode?`yarn playwright show-report ${r}`:`npx playwright show-report ${r}`;(0,Qp.execSync)(n,{encoding:"utf8",stdio:"pipe"}),await this.channel.log("Success: Report opened in browser")}catch(r){await this.channel.log(`Error serving report in browser: ${r.message}`),r.stderr&&await this.channel.log(r.stderr.toString())}}async handleReport(e){let{reportPath:r,pathToChecksumMetadata:n,didFail:i,openReportCriteria:s,checksumRoot:o,projectRoot:c,isUploadReport:l,dedupeByChecksumTestId:u}=e;this.channel.debug(`Handling report ${this.isolationMode?"(isolation mode)":""}`+r),this.uploadReportData((0,Be.dirname)(r),l);let d=Zr("report_processing",{test_suite_run_id:this.config.sessionId,report_path:r,isolation_mode:this.isolationMode,is_upload_report:!!l});try{let f=await this.readMetadataFile(n),y=new Ki(r,this.config.sessionId,this.pwTestIdToChecksumTestId,f,{hosted:!this.isolationMode,...u?{dedupeByChecksumTestId:u}:{}},this.channel,o,c,this.checksumTestIdToUsingPlaceholder),h=this.initAsset({type:"report",path:""});this.reportAsset=h;try{let w=await y.process();h.info.path=y.getProcessedFilePath(),d.set({processed_path:h.info.path,...w}),this.uploadAsset(h)}catch(w){this.channel.debug("Error processing report, "+w.message),h.error=!0,d.set({error:tt(w)})}let g=y.getReportsStats();this.stats=g,_f(d,h.error?"error":"success",g),this.channel.debug("Checking watch assets");let b=this.watchAssets.filter(w=>!(w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??"")));b.length>0&&(this.channel.debug("Removed watch assets - "),this.channel.debug(JSON.stringify(b.map(w=>w.path)))),this.watchAssets=this.watchAssets.filter(w=>w.type!=="trace"||y.testHasTrace(w.testId??"",w.project??""))}catch(f){this.channel.debug("Error processing report, "+this.stringify(f)),this.reportAsset&&(this.reportAsset.error=!0),d.emit({outcome:"error",error:tt(f)})}finally{if((s==="always"||s==="on-failure"&&i)&&await this.serveReport(r),n&&(0,ce.existsSync)(n))try{(0,ce.unlinkSync)(n)}catch(y){console.error(`Error deleting checksum metadata file ${n}: ${y.message}`)}}}async uploadReportData(e,r){let n=(0,Be.join)(e,"data");try{let i=(0,ce.readdirSync)(n),s=r?[".webm"]:[".zip",".webm"],o=i.filter(c=>!s.includes((0,Be.extname)(c)));this.channel.debug("Preparing to upload report data files,"+o);for(let c of o)this.channel.debug("Uploading report data file,"+c),this.addAsset({type:"report-data-file",fileName:c,path:`${n}/${c}`})}catch(i){this.channel.debug(`Error reading/adding report data files from dir ${n}`+i.message)}}shutdown(){clearInterval(this.uploadMonitorInterval);try{this.server?.closeAllConnections?.(),this.server?.close?.()}catch{}this.channel.debug("Received shutdown message from CLI"),process.stdout.write("",()=>process.exit(0)),setTimeout(()=>process.exit(0),this.SHUTDOWN_FLUSH_TIMEOUT).unref()}async monitorUploadsCompletion(){let e=Date.now();!this.doneWaitingForReport&&Kp(this.reportAsset,{testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET},e)&&this.settleReport();let r=Zp({assets:this.assets,processingInProgress:this.processingInProgress,doneWaitingForReport:this.doneWaitingForReport,pendingWatchCount:this.watchAssets.length,testRunEndTime:this.testRunEndTime,stallTimeoutMs:this.UPLOAD_STALL_TIMEOUT,watchTimeoutMs:this.WATCH_TIMEOUT,finalizeBudgetMs:this.FINALIZE_BUDGET,finalizeCeilingMs:this.FINALIZE_CEILING},e);if(!r){await cs(1e3),this.monitorUploadsCompletion();return}this.finalizeRun(r,e)}stopWaitingForReport(e){this.doneWaitingForReport=!0,this.reportOutcome=e}reportAssetOutcome(){return this.reportAsset?.complete?"uploaded":this.reportAsset?.error?"failed":"abandoned"}settleReport(){this.stopWaitingForReport(this.reportAssetOutcome());let e="";try{let r=JSON.stringify(this.stats??{}),n=`checksum-stats-${(0,An.randomBytes)(8).toString("hex")}.json`;e=(0,Be.join)((0,im.tmpdir)(),n),(0,ce.writeFileSync)(e,r,"utf-8"),this.channel.debug(`Stats written to temporary file: ${e}`)}catch(r){this.channel.debug("Error writing stats to file"),this.channel.log(`[monitorUploadsCompletion] Error writing stats to file: ${r.message}`)}this.channel.event("report-complete",`${this.reportOutcome==="uploaded"?"true":"false"}:${e}`)}finalizeRun(e,r){e.reason==="stall"&&this.emitStallDetected(e.abandonedAssets,r),e.abandonedAssets.forEach(o=>{o.error=!0});let n=this.assets.some(o=>o.error)?"uploads-complete-with-errors":"uploads-complete",i=this.assets.filter(o=>o.error);mr("uploads_completion",{test_suite_run_id:this.config.sessionId,outcome:i.length>0?"error":"success",decision:n,total_assets:this.assets.length,completed:this.assets.filter(o=>o.complete).length,errored:i.length,stalled:e.abandonedAssets.length>0,stalled_count:e.abandonedAssets.length,finalize_reason:e.reason,finalize_budget_ms:this.FINALIZE_BUDGET,finalize_ceiling_ms:this.FINALIZE_CEILING,watch_remaining:this.watchAssets.length,report_outcome:this.reportOutcome,upload_finalize_ms:this.testRunEndTime?r-this.testRunEndTime:void 0,errored_assets:i.map(o=>this.assetSnapshot(o,r))});let s=n==="uploads-complete"?{}:{uploadErrors:i.map(o=>{try{return JSON.stringify(o)}catch{return o.info.path}}),watchAssets:this.watchAssets,testRunEndTime:this.testRunEndTime,now:r,finalizeReason:e.reason,abandonedAssets:e.abandonedAssets.map(o=>this.assetSnapshot(o,r))};if(Jp(e))try{this.cleanUp()}catch(o){this.channel.debug("cleanUp failed (ignored): "+o?.message)}else this.channel.debug(`skipping cleanUp: ${e.abandonedAssets.length} asset(s) abandoned (${e.reason})`);this.channel.event(n,JSON.stringify(s))}assetSnapshot(e,r){return{file_name:e.info.fileName??(0,Be.basename)(e.info.path),asset_type:e.info.type,test_id:e.info.testId,loaded_bytes:e.loadedBytes,committed_bytes:e.committedBytes,size_bytes:e.sizeBytes,last_progress_age_ms:e.lastProgress?r-e.lastProgress:void 0}}cleanUp(){let e;for(let r of this.assets)if(r.info.type==="rrweb-recording"){e=(0,Be.dirname)(r.info.path);break}e&&(0,ce.rmSync)(e,{recursive:!0,force:!0})}emitStallDetected(e,r){this.channel.log("Uploads are stalled"),!this.stallEventEmitted&&(this.stallEventEmitted=!0,mr("upload_stall_detected",{test_suite_run_id:this.config.sessionId,outcome:"error",timeout_ms:this.UPLOAD_STALL_TIMEOUT,total_assets:this.assets.length,pending_count:e.length,pending_assets:e.map(n=>this.assetSnapshot(n,r))}))}async startServer(){let e=await this.acquirePortNumber();this.channel.event("port",e.toString()),this.server=(0,rm.createServer)((r,n)=>{let i=a(o=>{n.writeHead(400,{"Content-Type":"text/plain"}),n.end(o)},"returnErrorWithMessage");if(r.method!=="POST"){n.writeHead(404,{"Content-Type":"text/plain"}),n.end("Method not allowed");return}let s="";r.on("data",o=>{s+=o.toString()}),r.on("end",()=>{let o;try{o=JSON.parse(s)}catch{i("Invalid body");return}let{type:c,payload:l,watch:u}=o;switch(this.channel.debug(`Server received message, ${c}, ${this.stringify(l)}`),c){case"asset":if(!l.path||!l.type){i("Missing arguments");return}u?this.watchAsset(l):this.processAsset(l);break;case"testInfo":if(!l.pwTestId||!l.checksumTestId){i("Missing arguments");return}this.pwTestIdToChecksumTestId[l.pwTestId]=l.checksumTestId,l.usingChecksumTestIdPlaceholder!==void 0&&(this.checksumTestIdToUsingPlaceholder[l.checksumTestId]=l.usingChecksumTestIdPlaceholder);break;case"checksumTestMetadata":{let d=l;if(!d.checksumTestId||!l.data){i("Missing arguments");return}this.channel.event("checksumTestMetadata",JSON.stringify({...d}));break}case"testStats":break;case"playwrightConfig":this.channel.event("playwrightConfig",JSON.stringify(l));break;case"runProgress":this.forwardProgress(l);break;default:i("Invalid message type");return}n.writeHead(200,{"Content-Type":"text/plain"}),n.end("OK")})}),this.server.listen(e)}forwardProgress(e){this.latestProgress=e,!this.progressFlushInFlight&&this.flushProgress()}async flushProgress(){this.progressFlushInFlight=!0;try{for(;this.latestProgress;){let e=this.latestProgress;this.latestProgress=void 0,await this.patchProgress(e)}}finally{this.progressFlushInFlight=!1}}async patchProgress(e){if(this.isolationMode)return;let r=new AbortController,n=setTimeout(()=>r.abort(),3e4);try{await fetch(`${this.config.apiURL}/client-api/test-runs/${this.config.sessionId}/progress`,{method:"PATCH",headers:{Accept:"application/json","Content-Type":"application/json",ChecksumAppCode:this.config.apiKey},body:JSON.stringify({progress:e}),signal:r.signal})}catch(i){this.channel.debug("Failed to send run progress: "+i?.message)}finally{clearTimeout(n)}}stringify(e){try{return JSON.stringify(e)}catch{return"message"in e?e.message:e}}monitorUploads(){let{totalSizeBytes:e,totalUploadedBytes:r}=this.calculateUploadProgress();if(e>0&&!this.isolationMode){let s=(r/e*100).toFixed(2);this.channel.event("upload-progress",s)}let n=this.assets.filter(s=>!s.uploadStarted);if(n.length===0)return;let i=a(()=>this.assets.filter(s=>s.uploadStarted&&!s.complete&&!s.error).length,"getNumOfActiveUploads");if(!(i()>=this.MAX_UPLOADS))for(;n.length>0&&i()<this.MAX_UPLOADS;){let s=n.pop();if(s===void 0)break;this.uploadAsset(s)}}calculateUploadProgress(){let e=this.assets.reduce((n,{sizeBytes:i})=>n+(i??0),0),r=Math.min(e,this.assets.reduce((n,{loadedBytes:i})=>n+(i??0),0));return{totalSizeBytes:e,totalUploadedBytes:r}}getUploadLogMessage(e){switch(e.info.type){case"report":return"Uploading report";case"har":return`Uploading har file for test ${e.info.testId}`;case"trace":return`Uploading trace file for test ${e.info.testId}`;case"esra":return`Uploading metadata file for test ${e.info.testId}`;case"test-files":return`Uploading auto-healed test code for file ${e.info.path}`;default:return}}async uploadAsset(e){try{e.uploadStarted=!0;let r=this.getUploadLogMessage(e);r&&!this.isolationMode&&this.channel.event("log",r),await this.testAssetUploader.uploadAsset(e)}catch(r){e.error=!0,this.channel.debug("Error uploading asset"+this.stringify(r)),this.channel.trace("Upload Failed",{asset:e.info.fileName,error:String(r)})}}watchAsset(e){if(this.watchAssets.some(n=>n.path===e.path)){this.channel.debug(`Already watching file ${e.path}, skipping duplicate`);return}this.channel.debug("Watching file "+e.path),this.watchAssets.push({...e,addedAt:Date.now()});let r=a(async()=>{await this.waitForFileComplete(e.path)&&(this.processAsset(e),this.watchAssets=this.watchAssets.filter(i=>i.path!==e.path))},"waitForCompletion");if((0,ce.existsSync)(e.path))r();else{let n=(0,Be.dirname)(e.path),i=(0,Be.basename)(e.path),s=!1,o=(0,ce.watch)(n,(c,l)=>{(async()=>{if(!(l!==i||s))try{this.channel.debug("Watched file changed "+e.path),s=!0,await r()}finally{o.close()}})()})}}waitForFileComplete(e,r=1e3,n=6e4,i=1){return new Promise(s=>{let o=Date.now(),c=0,l=i,u=a(()=>{if(!(0,ce.existsSync)(e)){this.channel.debug(`Asset required for upload doesn't exist anymore ${e}`),s(!1);return}let d=(0,ce.statSync)(e).size;if(d===c){if(l>0){this.channel.debug(`File size has not changed, verifying stabilization, ${e}, size: ${d}, equalSizeValidationCountLeft: ${l}`),l--,setTimeout(u,r);return}this.channel.debug(`File size has not changed, stabilization verified, ${e}, size: ${d}`),s(!0);return}if(this.channel.debug(`File size changed, waiting for stabilization, ${e}, previous size: ${c}, current size: ${d}`),Date.now()-o>n){this.channel.debug(`Asset required for upload is taking over ${n} ms to write to disk ${e}`),s(!0);return}c=d,setTimeout(u,r)},"checkFile");u()})}processAsset(e){switch(e.type){case"trace":return this.processTrace(e.path,e.testId);case"har":return;case"rrweb-recording":case"esra":case"test-files":return this.addAsset(e);default:return}}async calculateFileSha1Streaming(e){let r=(0,An.createHash)("sha1"),n=(0,ce.createReadStream)(e);return await(0,tm.pipeline)(n,r),r.digest("hex")}async processTrace(e,r){if(this.processingPaths.has(e)){this.channel.debug(`Trace file ${e} already being processed, skipping`);return}this.processingPaths.add(e);let n;try{this.processingInProgress=!0,await cs(1e3),n=Zr("trace_processing",{test_suite_run_id:this.config.sessionId,test_id:r});let i=e;if(!this.isolationMode){this.channel.debug(`Preparing trace for upload (testId: ${r})...`),i=e.replace(".zip",".actual.zip"),(0,ce.renameSync)(e,i);let c="checksum-playwright-trace:"+Date.now().toString()+(0,An.randomBytes)(1024).toString("hex");(0,ce.writeFileSync)(e,c)}let o=await a(async()=>await this.calculateFileSha1Streaming(e)+(0,Be.extname)(e),"makePlaywrightHTMLReporterName")();this.channel.debug(`Trace file for test ${r} has been manipulated with file name ${o}, sending for upload...`),this.addAsset({type:"report-data-file",path:i,...r!==void 0?{testId:r}:{},fileName:o}),n.emit({outcome:"success",file_name:o})}catch(i){let s=String(i);this.channel.debug("Error processing trace file"+s),this.channel.trace("Trace Processing Error",{error:s}),n?.emit({outcome:"error",error:tt(i)})}finally{this.processingPaths.delete(e),this.processingInProgress=!1}}addAsset(e){this.channel.debug("Adding file "+e.path);let r=this.initAsset(e);return this.assets.push(r),r}initAsset(e){return{complete:!1,error:!1,info:e,removeAfterUpload:e.type==="rrweb-recording"}}async acquirePortNumber(){return new Promise((e,r)=>{let n=nm.createServer();n.unref(),n.on("error",r),n.listen(0,()=>{let i=n.address().port;n.close(()=>{e(i)})})})}},sm;try{sm=JSON.parse(process.argv[2]??"")}catch(t){console.error("Error starting test run monitor",t),process.exit(1)}new ns(sm,process.argv[3]==="isolated");0&&(module.exports={TestRunMonitor});
168
168
  /*! Bundled license information:
169
169
 
170
170
  @langchain/core/dist/utils/js-sha256/hash.js: