@skrillex1224/playwright-toolkit 2.1.198 → 2.1.200

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
@@ -599,9 +599,31 @@ var logger2 = createInternalLogger("ProxyMeter");
599
599
  var MAX_TOP_DOMAINS = 20;
600
600
  var FLUSH_INTERVAL_MS = 2e3;
601
601
  var DEFAULT_DEBUG_MAX_EVENTS = 400;
602
+ var PROXY_METER_READY_TIMEOUT_MS = 5e3;
603
+ var PROXY_METER_STABLE_WINDOW_MS = 2e3;
604
+ var PROXY_METER_POLL_INTERVAL_MS = 100;
605
+ var PROXY_METER_CONNECT_TIMEOUT_MS = 500;
602
606
  var runtime = null;
603
607
  var cleanupInstalled = false;
604
608
  var observedDomainResourceTypes = /* @__PURE__ */ new Map();
609
+ var sleepSignal = new Int32Array(new SharedArrayBuffer(4));
610
+ var portProbeScript = [
611
+ 'const net = require("net");',
612
+ "const port = Number(process.argv[1] || 0);",
613
+ "const timeout = Number(process.argv[2] || 200);",
614
+ "if (!Number.isFinite(port) || port <= 0) process.exit(2);",
615
+ 'const socket = net.connect({ host: "127.0.0.1", port });',
616
+ "let done = false;",
617
+ "const finish = (code) => {",
618
+ " if (done) return;",
619
+ " done = true;",
620
+ " try { socket.destroy(); } catch {}",
621
+ " process.exit(code);",
622
+ "};",
623
+ 'socket.once("connect", () => finish(0));',
624
+ 'socket.once("error", () => finish(1));',
625
+ "socket.setTimeout(timeout, () => finish(1));"
626
+ ].join("");
605
627
  var toSafeInt = (value) => {
606
628
  const num = Number(value);
607
629
  if (!Number.isFinite(num) || num <= 0) return 0;
@@ -700,6 +722,17 @@ var ensureLogPath = () => {
700
722
  const label = runId ? `proxy-meter-${runId}-${suffix}.json` : `proxy-meter-${process.pid}-${suffix}.json`;
701
723
  return import_path.default.join(baseDir, label);
702
724
  };
725
+ var ensureStatePath = () => {
726
+ const baseDir = resolveLogDir();
727
+ if (!(0, import_fs.existsSync)(baseDir)) {
728
+ try {
729
+ (0, import_fs.mkdirSync)(baseDir, { recursive: true });
730
+ } catch {
731
+ }
732
+ }
733
+ const suffix = `${Date.now()}-${Math.floor(Math.random() * 1e6)}`;
734
+ return import_path.default.join(baseDir, `proxy-meter-state-${process.pid}-${suffix}.json`);
735
+ };
703
736
  var readSnapshot = (logPath) => {
704
737
  if (!logPath || !(0, import_fs.existsSync)(logPath)) return null;
705
738
  try {
@@ -710,6 +743,83 @@ var readSnapshot = (logPath) => {
710
743
  return null;
711
744
  }
712
745
  };
746
+ var readState = (statePath) => {
747
+ if (!statePath || !(0, import_fs.existsSync)(statePath)) return null;
748
+ try {
749
+ const raw = (0, import_fs.readFileSync)(statePath, "utf8");
750
+ if (!raw) return null;
751
+ return JSON.parse(raw);
752
+ } catch {
753
+ return null;
754
+ }
755
+ };
756
+ var sleepSync = (durationMs) => {
757
+ const timeout = Math.max(0, Number(durationMs) || 0);
758
+ if (timeout <= 0) return;
759
+ Atomics.wait(sleepSignal, 0, 0, timeout);
760
+ };
761
+ var canConnectToPort = (port, timeoutMs = PROXY_METER_CONNECT_TIMEOUT_MS) => {
762
+ const result = (0, import_child_process.spawnSync)(process.execPath, ["-e", portProbeScript, String(port), String(timeoutMs)], {
763
+ stdio: "ignore",
764
+ timeout: timeoutMs + 100
765
+ });
766
+ return result.status === 0;
767
+ };
768
+ var waitForProxyMeterReady = ({ port, statePath }) => {
769
+ const startedAt = Date.now();
770
+ const listenDeadline = startedAt + PROXY_METER_READY_TIMEOUT_MS;
771
+ let firstConnectAt = 0;
772
+ while (Date.now() < listenDeadline) {
773
+ const lifecycle = readState(statePath);
774
+ if (lifecycle?.status === "exited") {
775
+ return {
776
+ ok: false,
777
+ reason: "child_exit_before_ready",
778
+ childExitCode: lifecycle.exitCode,
779
+ latencyMs: Date.now() - startedAt
780
+ };
781
+ }
782
+ if (canConnectToPort(port)) {
783
+ firstConnectAt = Date.now();
784
+ break;
785
+ }
786
+ sleepSync(PROXY_METER_POLL_INTERVAL_MS);
787
+ }
788
+ if (!firstConnectAt) {
789
+ return {
790
+ ok: false,
791
+ reason: "listen_timeout",
792
+ childExitCode: readState(statePath)?.exitCode ?? null,
793
+ latencyMs: Date.now() - startedAt
794
+ };
795
+ }
796
+ const stableDeadline = firstConnectAt + PROXY_METER_STABLE_WINDOW_MS;
797
+ while (Date.now() < stableDeadline) {
798
+ const lifecycle = readState(statePath);
799
+ if (lifecycle?.status === "exited") {
800
+ return {
801
+ ok: false,
802
+ reason: "child_exit_before_ready",
803
+ childExitCode: lifecycle.exitCode,
804
+ latencyMs: Date.now() - startedAt
805
+ };
806
+ }
807
+ canConnectToPort(port);
808
+ sleepSync(PROXY_METER_POLL_INTERVAL_MS);
809
+ }
810
+ if (!canConnectToPort(port)) {
811
+ return {
812
+ ok: false,
813
+ reason: "stabilize_timeout",
814
+ childExitCode: readState(statePath)?.exitCode ?? null,
815
+ latencyMs: Date.now() - startedAt
816
+ };
817
+ }
818
+ return {
819
+ ok: true,
820
+ latencyMs: Date.now() - startedAt
821
+ };
822
+ };
713
823
  var normalizeDomainRows = (hosts) => {
714
824
  const rows = [];
715
825
  let requestCount = 0;
@@ -858,15 +968,23 @@ var startProxyMeter = (options = {}) => {
858
968
  const upstreamUrl = String(options.proxyUrl || "").trim();
859
969
  if (!upstreamUrl) return null;
860
970
  if (runtime && runtime.proc) {
971
+ const previousStatePath = runtime.statePath;
861
972
  try {
862
973
  runtime.proc.kill("SIGTERM");
863
974
  } catch {
864
975
  }
865
976
  runtime = null;
977
+ if (previousStatePath) {
978
+ try {
979
+ (0, import_fs.rmSync)(previousStatePath, { force: true });
980
+ } catch {
981
+ }
982
+ }
866
983
  }
867
984
  observedDomainResourceTypes = /* @__PURE__ */ new Map();
868
985
  const port = pickFreePort();
869
986
  const logPath = ensureLogPath();
987
+ const statePath = ensureStatePath();
870
988
  const scriptPath = resolveScriptPath();
871
989
  const debugMode = Boolean(options.debugMode);
872
990
  const debugMaxEvents = Math.max(10, toSafeInt(options.debugMaxEvents) || DEFAULT_DEBUG_MAX_EVENTS);
@@ -877,7 +995,8 @@ var startProxyMeter = (options = {}) => {
877
995
  PROXY_METER_UPSTREAM: upstreamUrl,
878
996
  PROXY_METER_FLUSH_MS: String(FLUSH_INTERVAL_MS),
879
997
  PROXY_METER_DEBUG: debugMode ? "1" : "0",
880
- PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents)
998
+ PROXY_METER_DEBUG_MAX_EVENTS: String(debugMaxEvents),
999
+ PROXY_METER_STATE: statePath
881
1000
  };
882
1001
  const child = (0, import_child_process.spawn)(process.execPath, [scriptPath], {
883
1002
  env,
@@ -892,8 +1011,27 @@ var startProxyMeter = (options = {}) => {
892
1011
  proc: child,
893
1012
  port,
894
1013
  logPath,
1014
+ statePath,
895
1015
  startedAt: Date.now()
896
1016
  };
1017
+ const readiness = waitForProxyMeterReady({ port, statePath });
1018
+ if (!readiness.ok) {
1019
+ logger2.warn(
1020
+ `[proxy-meter] startup failed reason=${readiness.reason} latency_ms=${readiness.latencyMs} exit_code=${readiness.childExitCode ?? "unknown"}`
1021
+ );
1022
+ try {
1023
+ child.kill("SIGTERM");
1024
+ } catch {
1025
+ }
1026
+ runtime = null;
1027
+ try {
1028
+ (0, import_fs.rmSync)(statePath, { force: true });
1029
+ } catch {
1030
+ }
1031
+ throw new Error(`proxy-meter startup failed: ${readiness.reason}`);
1032
+ }
1033
+ runtime.startedAt = Date.now() - readiness.latencyMs;
1034
+ logger2.info(`[proxy-meter] ready latency_ms=${readiness.latencyMs} stable_window_ms=${PROXY_METER_STABLE_WINDOW_MS}`);
897
1035
  registerCleanup();
898
1036
  return { server: `http://127.0.0.1:${port}` };
899
1037
  };
@@ -905,9 +1043,15 @@ var recordProxyMeterResourceType = (requestUrl, resourceType) => {
905
1043
  };
906
1044
  var stopProxyMeter = async () => {
907
1045
  if (!runtime) return null;
908
- const { proc, logPath } = runtime;
1046
+ const { proc, logPath, statePath } = runtime;
909
1047
  if (!proc || proc.killed) {
910
1048
  runtime = null;
1049
+ if (statePath) {
1050
+ try {
1051
+ (0, import_fs.rmSync)(statePath, { force: true });
1052
+ } catch {
1053
+ }
1054
+ }
911
1055
  return logPath || null;
912
1056
  }
913
1057
  await new Promise((resolve) => {
@@ -929,6 +1073,12 @@ var stopProxyMeter = async () => {
929
1073
  }
930
1074
  });
931
1075
  runtime = null;
1076
+ if (statePath) {
1077
+ try {
1078
+ (0, import_fs.rmSync)(statePath, { force: true });
1079
+ } catch {
1080
+ }
1081
+ }
932
1082
  return logPath || null;
933
1083
  };
934
1084
  var getProxyMeterSnapshot = async (options = {}) => {