@skrillex1224/playwright-toolkit 3.0.8 → 3.0.9

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/index.cjs CHANGED
@@ -1196,6 +1196,18 @@ var ensureLogPath = () => {
1196
1196
  const label = runId ? `proxy-meter-${runId}-${suffix}.json` : `proxy-meter-${process.pid}-${suffix}.json`;
1197
1197
  return import_path.default.join(baseDir, label);
1198
1198
  };
1199
+ var ensureStdioLogPath = (logPath) => `${logPath}.stdio.log`;
1200
+ var writeChildOutput = (stream, output, prefix) => {
1201
+ if (!stream || !output) return;
1202
+ output.on("data", (chunk) => {
1203
+ const text = chunk?.toString?.() || String(chunk || "");
1204
+ if (!text) return;
1205
+ for (const line of text.split(/\r?\n/)) {
1206
+ if (!line) continue;
1207
+ stream.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${prefix} ${line}\n`);
1208
+ }
1209
+ });
1210
+ };
1199
1211
  var readSnapshot = (logPath) => {
1200
1212
  if (!logPath || !(0, import_fs.existsSync)(logPath)) return null;
1201
1213
  try {
@@ -1363,6 +1375,7 @@ var startProxyMeter = (options = {}) => {
1363
1375
  observedDomainResourceTypes = /* @__PURE__ */ new Map();
1364
1376
  const port = pickFreePort();
1365
1377
  const logPath = ensureLogPath();
1378
+ const stdioLogPath = ensureStdioLogPath(logPath);
1366
1379
  const scriptPath = resolveScriptPath();
1367
1380
  const debugMode = Boolean(options.debugMode);
1368
1381
  const debugMaxEvents = Math.max(10, toSafeInt(options.debugMaxEvents) || DEFAULT_DEBUG_MAX_EVENTS);
@@ -1375,19 +1388,26 @@ var startProxyMeter = (options = {}) => {
1375
1388
  PROXY_METER_DEBUG: debugMode ? "1" : "0",
1376
1389
  PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents)
1377
1390
  };
1391
+ const stdioLog = (0, import_fs.createWriteStream)(stdioLogPath, { flags: "a" });
1392
+ stdioLog.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] [proxy-meter-runtime] start script=${scriptPath} port=${port} snapshot=${logPath}\n`);
1378
1393
  const child = (0, import_child_process.spawn)(process.execPath, [scriptPath], {
1379
1394
  env,
1380
- stdio: ["ignore", "ignore", "ignore"]
1395
+ stdio: ["ignore", "pipe", "pipe"]
1381
1396
  });
1382
- child.once("exit", (code) => {
1397
+ writeChildOutput(stdioLog, child.stdout, "stdout");
1398
+ writeChildOutput(stdioLog, child.stderr, "stderr");
1399
+ child.once("exit", (code, signal) => {
1400
+ stdioLog.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] [proxy-meter-runtime] exit code=${code ?? ""} signal=${signal ?? ""}\n`);
1401
+ stdioLog.end();
1383
1402
  if (code && code !== 0) {
1384
- logger2.warn(`[proxy-meter] exited with code ${code}`);
1403
+ logger2.warn(`[proxy-meter] exited with code ${code}; stdio=${stdioLogPath}`);
1385
1404
  }
1386
1405
  });
1387
1406
  runtime = {
1388
1407
  proc: child,
1389
1408
  port,
1390
1409
  logPath,
1410
+ stdioLogPath,
1391
1411
  startedAt: Date.now()
1392
1412
  };
1393
1413
  registerCleanup();
package/dist/index.js CHANGED
@@ -1059,7 +1059,7 @@ import { serializeError as serializeError2 } from "serialize-error";
1059
1059
 
1060
1060
  // src/internals/proxy-meter-runtime.js
1061
1061
  import { spawn, spawnSync } from "child_process";
1062
- import { existsSync, mkdirSync, readFileSync, rmSync } from "fs";
1062
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, rmSync } from "fs";
1063
1063
  import { tmpdir } from "os";
1064
1064
  import path from "path";
1065
1065
  import { fileURLToPath } from "url";
@@ -1168,6 +1168,18 @@ var ensureLogPath = () => {
1168
1168
  const label = runId ? `proxy-meter-${runId}-${suffix}.json` : `proxy-meter-${process.pid}-${suffix}.json`;
1169
1169
  return path.join(baseDir, label);
1170
1170
  };
1171
+ var ensureStdioLogPath = (logPath) => `${logPath}.stdio.log`;
1172
+ var writeChildOutput = (stream, output, prefix) => {
1173
+ if (!stream || !output) return;
1174
+ output.on("data", (chunk) => {
1175
+ const text = chunk?.toString?.() || String(chunk || "");
1176
+ if (!text) return;
1177
+ for (const line of text.split(/\r?\n/)) {
1178
+ if (!line) continue;
1179
+ stream.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] ${prefix} ${line}\n`);
1180
+ }
1181
+ });
1182
+ };
1171
1183
  var readSnapshot = (logPath) => {
1172
1184
  if (!logPath || !existsSync(logPath)) return null;
1173
1185
  try {
@@ -1335,6 +1347,7 @@ var startProxyMeter = (options = {}) => {
1335
1347
  observedDomainResourceTypes = /* @__PURE__ */ new Map();
1336
1348
  const port = pickFreePort();
1337
1349
  const logPath = ensureLogPath();
1350
+ const stdioLogPath = ensureStdioLogPath(logPath);
1338
1351
  const scriptPath = resolveScriptPath();
1339
1352
  const debugMode = Boolean(options.debugMode);
1340
1353
  const debugMaxEvents = Math.max(10, toSafeInt(options.debugMaxEvents) || DEFAULT_DEBUG_MAX_EVENTS);
@@ -1347,19 +1360,26 @@ var startProxyMeter = (options = {}) => {
1347
1360
  PROXY_METER_DEBUG: debugMode ? "1" : "0",
1348
1361
  PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents)
1349
1362
  };
1363
+ const stdioLog = createWriteStream(stdioLogPath, { flags: "a" });
1364
+ stdioLog.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] [proxy-meter-runtime] start script=${scriptPath} port=${port} snapshot=${logPath}\n`);
1350
1365
  const child = spawn(process.execPath, [scriptPath], {
1351
1366
  env,
1352
- stdio: ["ignore", "ignore", "ignore"]
1367
+ stdio: ["ignore", "pipe", "pipe"]
1353
1368
  });
1354
- child.once("exit", (code) => {
1369
+ writeChildOutput(stdioLog, child.stdout, "stdout");
1370
+ writeChildOutput(stdioLog, child.stderr, "stderr");
1371
+ child.once("exit", (code, signal) => {
1372
+ stdioLog.write(`[${(/* @__PURE__ */ new Date()).toISOString()}] [proxy-meter-runtime] exit code=${code ?? ""} signal=${signal ?? ""}\n`);
1373
+ stdioLog.end();
1355
1374
  if (code && code !== 0) {
1356
- logger2.warn(`[proxy-meter] exited with code ${code}`);
1375
+ logger2.warn(`[proxy-meter] exited with code ${code}; stdio=${stdioLogPath}`);
1357
1376
  }
1358
1377
  });
1359
1378
  runtime = {
1360
1379
  proc: child,
1361
1380
  port,
1362
1381
  logPath,
1382
+ stdioLogPath,
1363
1383
  startedAt: Date.now()
1364
1384
  };
1365
1385
  registerCleanup();
@@ -32,6 +32,25 @@ const state = {
32
32
  : null,
33
33
  };
34
34
 
35
+ const formatFatalError = (error) => {
36
+ if (error instanceof Error) {
37
+ return error.stack || error.message || String(error);
38
+ }
39
+ try {
40
+ return JSON.stringify(error);
41
+ } catch {
42
+ return String(error);
43
+ }
44
+ };
45
+
46
+ const exitAfterFatal = (kind, error) => {
47
+ try {
48
+ console.error(`[proxy-meter] fatal ${kind}: ${formatFatalError(error)}`);
49
+ } catch {}
50
+ flushSnapshot();
51
+ process.exit(1);
52
+ };
53
+
35
54
  const getHostBucket = (host) => {
36
55
  if (!host) return null;
37
56
  if (!state.hosts[host]) {
@@ -60,6 +79,21 @@ const safeError = (error) => {
60
79
  return message.length > 240 ? message.slice(0, 240) : message;
61
80
  };
62
81
 
82
+ const sendBadGateway = (res, error = null) => {
83
+ if (!res || res.destroyed || res.writableEnded) return;
84
+
85
+ try {
86
+ if (!res.headersSent) {
87
+ res.writeHead(502);
88
+ res.end('Bad Gateway');
89
+ return;
90
+ }
91
+
92
+ // Headers are already committed; the only truthful error signal left is closing the stream.
93
+ res.destroy(error instanceof Error ? error : undefined);
94
+ } catch {}
95
+ };
96
+
63
97
  const statusLabel = (statusCode, error) => {
64
98
  const code = Number(statusCode) || 0;
65
99
  if (error || code <= 0) return 'ERR';
@@ -349,8 +383,7 @@ const forwardHttp = (req, res) => {
349
383
 
350
384
  if (!target) {
351
385
  tracker.close({ statusCode: 0, error: 'invalid_target_url' });
352
- res.writeHead(502);
353
- res.end('Bad Gateway');
386
+ sendBadGateway(res);
354
387
  return;
355
388
  }
356
389
 
@@ -381,7 +414,19 @@ const forwardHttp = (req, res) => {
381
414
  let responseStatus = 0;
382
415
  const proxyReq = http.request(requestOptions, (proxyRes) => {
383
416
  responseStatus = Number(proxyRes.statusCode) || 0;
384
- res.writeHead(responseStatus || 502, proxyRes.headers);
417
+ if (res.destroyed || res.writableEnded) {
418
+ tracker.close({ statusCode: responseStatus || 499, error: 'client_response_closed' });
419
+ proxyRes.resume();
420
+ return;
421
+ }
422
+ try {
423
+ res.writeHead(responseStatus || 502, proxyRes.headers);
424
+ } catch (error) {
425
+ tracker.close({ statusCode: responseStatus, error: safeError(error) });
426
+ proxyRes.resume();
427
+ sendBadGateway(res, error);
428
+ return;
429
+ }
385
430
  proxyRes.on('data', (chunk) => {
386
431
  const size = chunk?.length || 0;
387
432
  addTraffic(hostname, 'in', size);
@@ -412,8 +457,7 @@ const forwardHttp = (req, res) => {
412
457
 
413
458
  proxyReq.on('error', (error) => {
414
459
  tracker.close({ statusCode: responseStatus, error: safeError(error) });
415
- res.writeHead(502);
416
- res.end('Bad Gateway');
460
+ sendBadGateway(res, error);
417
461
  });
418
462
  };
419
463
 
@@ -545,5 +589,7 @@ const shutdown = () => {
545
589
  process.exit(0);
546
590
  };
547
591
 
592
+ process.on('uncaughtException', (error) => exitAfterFatal('uncaughtException', error));
593
+ process.on('unhandledRejection', (error) => exitAfterFatal('unhandledRejection', error));
548
594
  process.on('SIGINT', shutdown);
549
595
  process.on('SIGTERM', shutdown);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skrillex1224/playwright-toolkit",
3
- "version": "3.0.8",
3
+ "version": "3.0.9",
4
4
  "description": "一个在 Apify/Crawlee Actor 中启用实时截图视图的实用工具库。",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.js",