@skrillex1224/playwright-toolkit 2.1.198 → 2.1.199

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.js CHANGED
@@ -571,9 +571,31 @@ var logger2 = createInternalLogger("ProxyMeter");
571
571
  var MAX_TOP_DOMAINS = 20;
572
572
  var FLUSH_INTERVAL_MS = 2e3;
573
573
  var DEFAULT_DEBUG_MAX_EVENTS = 400;
574
+ var PROXY_METER_READY_TIMEOUT_MS = 5e3;
575
+ var PROXY_METER_STABLE_WINDOW_MS = 2e3;
576
+ var PROXY_METER_POLL_INTERVAL_MS = 100;
577
+ var PROXY_METER_CONNECT_TIMEOUT_MS = 200;
574
578
  var runtime = null;
575
579
  var cleanupInstalled = false;
576
580
  var observedDomainResourceTypes = /* @__PURE__ */ new Map();
581
+ var sleepSignal = new Int32Array(new SharedArrayBuffer(4));
582
+ var portProbeScript = [
583
+ 'const net = require("net");',
584
+ "const port = Number(process.argv[1] || 0);",
585
+ "const timeout = Number(process.argv[2] || 200);",
586
+ "if (!Number.isFinite(port) || port <= 0) process.exit(2);",
587
+ 'const socket = net.connect({ host: "127.0.0.1", port });',
588
+ "let done = false;",
589
+ "const finish = (code) => {",
590
+ " if (done) return;",
591
+ " done = true;",
592
+ " try { socket.destroy(); } catch {}",
593
+ " process.exit(code);",
594
+ "};",
595
+ 'socket.once("connect", () => finish(0));',
596
+ 'socket.once("error", () => finish(1));',
597
+ "socket.setTimeout(timeout, () => finish(1));"
598
+ ].join("");
577
599
  var toSafeInt = (value) => {
578
600
  const num = Number(value);
579
601
  if (!Number.isFinite(num) || num <= 0) return 0;
@@ -672,6 +694,17 @@ var ensureLogPath = () => {
672
694
  const label = runId ? `proxy-meter-${runId}-${suffix}.json` : `proxy-meter-${process.pid}-${suffix}.json`;
673
695
  return path.join(baseDir, label);
674
696
  };
697
+ var ensureStatePath = () => {
698
+ const baseDir = resolveLogDir();
699
+ if (!existsSync(baseDir)) {
700
+ try {
701
+ mkdirSync(baseDir, { recursive: true });
702
+ } catch {
703
+ }
704
+ }
705
+ const suffix = `${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
706
+ return path.join(baseDir, `proxy-meter-state-${process.pid}-${suffix}.json`);
707
+ };
675
708
  var readSnapshot = (logPath) => {
676
709
  if (!logPath || !existsSync(logPath)) return null;
677
710
  try {
@@ -682,6 +715,86 @@ var readSnapshot = (logPath) => {
682
715
  return null;
683
716
  }
684
717
  };
718
+ var readState = (statePath) => {
719
+ if (!statePath || !existsSync(statePath)) return null;
720
+ try {
721
+ const raw = readFileSync(statePath, "utf8");
722
+ if (!raw) return null;
723
+ return JSON.parse(raw);
724
+ } catch {
725
+ return null;
726
+ }
727
+ };
728
+ var sleepSync = (durationMs) => {
729
+ const timeout = Math.max(0, Number(durationMs) || 0);
730
+ if (timeout <= 0) return;
731
+ Atomics.wait(sleepSignal, 0, 0, timeout);
732
+ };
733
+ var canConnectToPort = (port, timeoutMs = PROXY_METER_CONNECT_TIMEOUT_MS) => {
734
+ const result = spawnSync(process.execPath, ["-e", portProbeScript, String(port), String(timeoutMs)], {
735
+ stdio: "ignore",
736
+ timeout: timeoutMs + 100
737
+ });
738
+ return result.status === 0;
739
+ };
740
+ var waitForProxyMeterReady = ({ port, statePath }) => {
741
+ const startedAt = Date.now();
742
+ const listenDeadline = startedAt + PROXY_METER_READY_TIMEOUT_MS;
743
+ let firstConnectAt = 0;
744
+ let stableHealthy = true;
745
+ while (Date.now() < listenDeadline) {
746
+ const lifecycle = readState(statePath);
747
+ if (lifecycle?.status === "exited") {
748
+ return {
749
+ ok: false,
750
+ reason: "child_exit_before_ready",
751
+ childExitCode: lifecycle.exitCode,
752
+ latencyMs: Date.now() - startedAt
753
+ };
754
+ }
755
+ if (canConnectToPort(port)) {
756
+ firstConnectAt = Date.now();
757
+ break;
758
+ }
759
+ sleepSync(PROXY_METER_POLL_INTERVAL_MS);
760
+ }
761
+ if (!firstConnectAt) {
762
+ return {
763
+ ok: false,
764
+ reason: "listen_timeout",
765
+ childExitCode: readState(statePath)?.exitCode ?? null,
766
+ latencyMs: Date.now() - startedAt
767
+ };
768
+ }
769
+ const stableDeadline = firstConnectAt + PROXY_METER_STABLE_WINDOW_MS;
770
+ while (Date.now() < stableDeadline) {
771
+ const lifecycle = readState(statePath);
772
+ if (lifecycle?.status === "exited") {
773
+ return {
774
+ ok: false,
775
+ reason: "stabilize_timeout",
776
+ childExitCode: lifecycle.exitCode,
777
+ latencyMs: Date.now() - startedAt
778
+ };
779
+ }
780
+ if (!canConnectToPort(port)) {
781
+ stableHealthy = false;
782
+ }
783
+ sleepSync(PROXY_METER_POLL_INTERVAL_MS);
784
+ }
785
+ if (!stableHealthy || !canConnectToPort(port)) {
786
+ return {
787
+ ok: false,
788
+ reason: "stabilize_timeout",
789
+ childExitCode: readState(statePath)?.exitCode ?? null,
790
+ latencyMs: Date.now() - startedAt
791
+ };
792
+ }
793
+ return {
794
+ ok: true,
795
+ latencyMs: Date.now() - startedAt
796
+ };
797
+ };
685
798
  var normalizeDomainRows = (hosts) => {
686
799
  const rows = [];
687
800
  let requestCount = 0;
@@ -830,15 +943,23 @@ var startProxyMeter = (options = {}) => {
830
943
  const upstreamUrl = String(options.proxyUrl || "").trim();
831
944
  if (!upstreamUrl) return null;
832
945
  if (runtime && runtime.proc) {
946
+ const previousStatePath = runtime.statePath;
833
947
  try {
834
948
  runtime.proc.kill("SIGTERM");
835
949
  } catch {
836
950
  }
837
951
  runtime = null;
952
+ if (previousStatePath) {
953
+ try {
954
+ rmSync(previousStatePath, { force: true });
955
+ } catch {
956
+ }
957
+ }
838
958
  }
839
959
  observedDomainResourceTypes = /* @__PURE__ */ new Map();
840
960
  const port = pickFreePort();
841
961
  const logPath = ensureLogPath();
962
+ const statePath = ensureStatePath();
842
963
  const scriptPath = resolveScriptPath();
843
964
  const debugMode = Boolean(options.debugMode);
844
965
  const debugMaxEvents = Math.max(10, toSafeInt(options.debugMaxEvents) || DEFAULT_DEBUG_MAX_EVENTS);
@@ -849,7 +970,8 @@ var startProxyMeter = (options = {}) => {
849
970
  PROXY_METER_UPSTREAM: upstreamUrl,
850
971
  PROXY_METER_FLUSH_MS: String(FLUSH_INTERVAL_MS),
851
972
  PROXY_METER_DEBUG: debugMode ? "1" : "0",
852
- PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents)
973
+ PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents),
974
+ PROXY_METER_STATE: statePath
853
975
  };
854
976
  const child = spawn(process.execPath, [scriptPath], {
855
977
  env,
@@ -864,8 +986,27 @@ var startProxyMeter = (options = {}) => {
864
986
  proc: child,
865
987
  port,
866
988
  logPath,
989
+ statePath,
867
990
  startedAt: Date.now()
868
991
  };
992
+ const readiness = waitForProxyMeterReady({ port, statePath });
993
+ if (!readiness.ok) {
994
+ logger2.warn(
995
+ `[proxy-meter] startup failed reason=${readiness.reason} latency_ms=${readiness.latencyMs} exit_code=${readiness.childExitCode ?? "unknown"}`
996
+ );
997
+ try {
998
+ child.kill("SIGTERM");
999
+ } catch {
1000
+ }
1001
+ runtime = null;
1002
+ try {
1003
+ rmSync(statePath, { force: true });
1004
+ } catch {
1005
+ }
1006
+ throw new Error(`proxy-meter startup failed: ${readiness.reason}`);
1007
+ }
1008
+ runtime.startedAt = Date.now() - readiness.latencyMs;
1009
+ logger2.info(`[proxy-meter] ready latency_ms=${readiness.latencyMs} stable_window_ms=${PROXY_METER_STABLE_WINDOW_MS}`);
869
1010
  registerCleanup();
870
1011
  return { server: `http://127.0.0.1:${port}` };
871
1012
  };
@@ -877,9 +1018,15 @@ var recordProxyMeterResourceType = (requestUrl, resourceType) => {
877
1018
  };
878
1019
  var stopProxyMeter = async () => {
879
1020
  if (!runtime) return null;
880
- const { proc, logPath } = runtime;
1021
+ const { proc, logPath, statePath } = runtime;
881
1022
  if (!proc || proc.killed) {
882
1023
  runtime = null;
1024
+ if (statePath) {
1025
+ try {
1026
+ rmSync(statePath, { force: true });
1027
+ } catch {
1028
+ }
1029
+ }
883
1030
  return logPath || null;
884
1031
  }
885
1032
  await new Promise((resolve) => {
@@ -901,6 +1048,12 @@ var stopProxyMeter = async () => {
901
1048
  }
902
1049
  });
903
1050
  runtime = null;
1051
+ if (statePath) {
1052
+ try {
1053
+ rmSync(statePath, { force: true });
1054
+ } catch {
1055
+ }
1056
+ }
904
1057
  return logPath || null;
905
1058
  };
906
1059
  var getProxyMeterSnapshot = async (options = {}) => {