@saptools/cf-debugger 0.1.4 → 0.1.6

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/cli.js CHANGED
@@ -1,17 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import process4 from "process";
4
+ import process6 from "process";
5
5
  import { Command } from "commander";
6
6
 
7
- // src/debugger.ts
7
+ // src/debug-session/start.ts
8
8
  import { mkdir as mkdir3, rm } from "fs/promises";
9
- import { hostname as getHostname2 } from "os";
10
- import process3 from "process";
11
-
12
- // src/cf.ts
13
- import { execFile, spawn } from "child_process";
14
- import { promisify } from "util";
9
+ import process4 from "process";
15
10
 
16
11
  // src/types.ts
17
12
  var CfDebuggerError = class extends Error {
@@ -27,19 +22,34 @@ var CfDebuggerError = class extends Error {
27
22
  }
28
23
  };
29
24
 
30
- // src/cf.ts
25
+ // src/cloud-foundry/execute.ts
26
+ import { execFile } from "child_process";
27
+ import { promisify } from "util";
31
28
  var execFileAsync = promisify(execFile);
32
29
  var MAX_BUFFER = 16 * 1024 * 1024;
33
30
  var CF_CLI_TIMEOUT_MS = 3e4;
34
- var CF_RESTART_TIMEOUT_MS = 12e4;
35
- var CF_SSH_SIGNAL_TIMEOUT_MS = 15e3;
36
- var CF_AUTH_MAX_ATTEMPTS = 3;
31
+ var REDACTED_ARG = "<redacted>";
37
32
  function buildEnv(cfHome) {
38
33
  return { ...process.env, CF_HOME: cfHome };
39
34
  }
40
35
  function resolveBin(context) {
41
36
  return context.command ?? process.env["CF_DEBUGGER_CF_BIN"] ?? "cf";
42
37
  }
38
+ function sensitiveArgs(args) {
39
+ if (args[0] !== "auth") {
40
+ return [];
41
+ }
42
+ return args.slice(1).filter((arg) => arg.length > 0);
43
+ }
44
+ function redactText(text, values) {
45
+ return values.reduce((current, value) => current.split(value).join(REDACTED_ARG), text);
46
+ }
47
+ function formatArgsForError(args) {
48
+ if (args[0] !== "auth") {
49
+ return args.join(" ");
50
+ }
51
+ return args.map((arg, index) => index === 0 ? arg : REDACTED_ARG).join(" ");
52
+ }
43
53
  async function runCf(args, context, timeoutMs = CF_CLI_TIMEOUT_MS) {
44
54
  try {
45
55
  const { stdout } = await execFileAsync(resolveBin(context), [...args], {
@@ -50,14 +60,20 @@ async function runCf(args, context, timeoutMs = CF_CLI_TIMEOUT_MS) {
50
60
  return stdout;
51
61
  } catch (err) {
52
62
  const e = err;
53
- const stderr = e.stderr?.trim() ?? "";
63
+ const redactionValues = sensitiveArgs(args);
64
+ const stderr = redactText(e.stderr?.trim() ?? "", redactionValues);
65
+ const fallbackMessage = redactText(e.message, redactionValues);
54
66
  throw new CfDebuggerError(
55
67
  "CF_CLI_FAILED",
56
- `cf ${args.join(" ")} failed: ${stderr.length > 0 ? stderr : e.message}`,
68
+ `cf ${formatArgsForError(args)} failed: ${stderr.length > 0 ? stderr : fallbackMessage}`,
57
69
  stderr
58
70
  );
59
71
  }
60
72
  }
73
+
74
+ // src/cloud-foundry/commands.ts
75
+ var CF_RESTART_TIMEOUT_MS = 12e4;
76
+ var CF_AUTH_MAX_ATTEMPTS = 3;
61
77
  async function cfApi(apiEndpoint, context) {
62
78
  await runCf(["api", apiEndpoint], context);
63
79
  }
@@ -123,6 +139,10 @@ async function cfEnableSsh(appName, context) {
123
139
  async function cfRestartApp(appName, context) {
124
140
  await runCf(["restart", appName], context, CF_RESTART_TIMEOUT_MS);
125
141
  }
142
+
143
+ // src/cloud-foundry/ssh.ts
144
+ import { spawn } from "child_process";
145
+ var CF_SSH_SIGNAL_TIMEOUT_MS = 15e3;
126
146
  async function cfSshOneShot(appName, command, context) {
127
147
  return await new Promise((resolve) => {
128
148
  const child = spawn(resolveBin(context), ["ssh", appName, "-c", command], {
@@ -197,7 +217,7 @@ function sessionCfHomeDir(sessionId) {
197
217
  return join(saptoolsDir(), CF_DEBUGGER_HOMES_DIRNAME, sessionId);
198
218
  }
199
219
 
200
- // src/port.ts
220
+ // src/network/ports.ts
201
221
  import { execFile as execFile2 } from "child_process";
202
222
  import { createConnection, createServer } from "net";
203
223
  import { promisify as promisify2 } from "util";
@@ -366,7 +386,7 @@ function resolveApiEndpoint(regionKey, override) {
366
386
  return endpoint;
367
387
  }
368
388
 
369
- // src/state.ts
389
+ // src/session-state/store.ts
370
390
  import { randomUUID } from "crypto";
371
391
  import { mkdir as mkdir2, readFile, rename, writeFile } from "fs/promises";
372
392
  import { hostname as getHostname } from "os";
@@ -421,7 +441,7 @@ async function withFileLock(lockPath, work, options) {
421
441
  }
422
442
  }
423
443
 
424
- // src/state.ts
444
+ // src/session-state/store.ts
425
445
  async function readJsonFile(path) {
426
446
  let raw;
427
447
  try {
@@ -653,13 +673,29 @@ async function removeSession(sessionId) {
653
673
  });
654
674
  }
655
675
 
656
- // src/debugger.ts
676
+ // src/debug-session/constants.ts
657
677
  var DEFAULT_TUNNEL_READY_TIMEOUT_MS = 3e4;
658
678
  var POST_USR1_DELAY_MS = 300;
659
679
  var PORT_CLEANUP_DELAY_MS = 600;
660
680
  var CHILD_SIGTERM_GRACE_MS = 2e3;
661
681
  var PORT_RECLAIM_DELAY_MS = 250;
662
682
  var PID_TERMINATION_POLL_MS = 100;
683
+
684
+ // src/debug-session/orphans.ts
685
+ import { hostname as getHostname2 } from "os";
686
+ async function pruneAndCleanupOrphans() {
687
+ const result = await readAndPruneActiveSessions();
688
+ const host = getHostname2();
689
+ for (const removed of result.removed) {
690
+ if (removed.hostname === host) {
691
+ void killProcessOnPort(removed.localPort);
692
+ }
693
+ }
694
+ return result.sessions;
695
+ }
696
+
697
+ // src/debug-session/processes.ts
698
+ import process3 from "process";
663
699
  function signalPidOrGroup(pid, signal) {
664
700
  const isWindows = process3.platform === "win32";
665
701
  if (!isWindows) {
@@ -699,24 +735,16 @@ async function killProcessGroupOrProc(child, timeoutMs = CHILD_SIGTERM_GRACE_MS)
699
735
  }
700
736
  await terminatePidOrGroup(child.pid, timeoutMs);
701
737
  }
702
- async function pruneAndCleanupOrphans() {
703
- const result = await readAndPruneActiveSessions();
704
- const host = getHostname2();
705
- for (const removed of result.removed) {
706
- if (removed.hostname === host) {
707
- void killProcessOnPort(removed.localPort);
708
- }
709
- }
710
- return result.sessions;
711
- }
738
+
739
+ // src/debug-session/start.ts
712
740
  function checkAbort(signal) {
713
741
  if (signal?.aborted) {
714
742
  throw new CfDebuggerError("ABORTED", "Operation aborted by caller");
715
743
  }
716
744
  }
717
745
  function requireCredentials(options) {
718
- const email = options.email ?? process3.env["SAP_EMAIL"];
719
- const password = options.password ?? process3.env["SAP_PASSWORD"];
746
+ const email = options.email ?? process4.env["SAP_EMAIL"];
747
+ const password = options.password ?? process4.env["SAP_PASSWORD"];
720
748
  if (email === void 0 || email === "") {
721
749
  throw new CfDebuggerError(
722
750
  "MISSING_CREDENTIALS",
@@ -731,15 +759,7 @@ function requireCredentials(options) {
731
759
  }
732
760
  return { email, password };
733
761
  }
734
- async function startDebugger(options) {
735
- const { email, password } = requireCredentials(options);
736
- const apiEndpoint = resolveApiEndpoint(options.region, options.apiEndpoint);
737
- const tunnelReadyTimeoutMs = options.tunnelReadyTimeoutMs ?? DEFAULT_TUNNEL_READY_TIMEOUT_MS;
738
- const emit = (status, message) => {
739
- options.onStatus?.(status, message);
740
- };
741
- checkAbort(options.signal);
742
- await pruneAndCleanupOrphans();
762
+ async function registerSession(options, apiEndpoint) {
743
763
  const registration = await registerNewSession({
744
764
  region: options.region,
745
765
  org: options.org,
@@ -756,20 +776,151 @@ async function startDebugger(options) {
756
776
  `A debugger session is already running for ${sessionKeyString(options)} on port ${registration.existing.localPort.toString()} (pid ${registration.existing.pid.toString()}, sessionId ${registration.existing.sessionId}). Stop it first with \`cf-debugger stop\`.`
757
777
  );
758
778
  }
759
- const session = registration.session;
779
+ return registration.session;
780
+ }
781
+ async function loginAndTarget(options, apiEndpoint, email, password, context, sessionId, emit) {
782
+ emit("logging-in");
783
+ await updateSessionStatus(sessionId, "logging-in");
784
+ await cfLogin(apiEndpoint, email, password, context);
785
+ checkAbort(options.signal);
786
+ emit("targeting");
787
+ await updateSessionStatus(sessionId, "targeting");
788
+ await cfTarget(options.org, options.space, context);
789
+ checkAbort(options.signal);
790
+ }
791
+ async function signalRemoteNode(options, context, sessionId, emit) {
792
+ emit("signaling");
793
+ await updateSessionStatus(sessionId, "signaling");
794
+ const signalResult = await cfSshOneShot(options.app, `kill -s USR1 $(pidof node)`, context);
795
+ if (!isSshDisabledError(signalResult.stderr)) {
796
+ if (signalResult.exitCode === 0) {
797
+ return;
798
+ }
799
+ const detail = signalResult.stderr.trim().length > 0 ? signalResult.stderr.trim() : `exit code ${String(signalResult.exitCode)}`;
800
+ throw new CfDebuggerError(
801
+ "USR1_SIGNAL_FAILED",
802
+ `Failed to send SIGUSR1 to the Node.js process on ${options.app}: ${detail}`,
803
+ signalResult.stderr
804
+ );
805
+ }
806
+ const alreadyEnabled = await cfSshEnabled(options.app, context);
807
+ if (!alreadyEnabled) {
808
+ emit("ssh-enabling", "Enabling SSH on the app");
809
+ await updateSessionStatus(sessionId, "ssh-enabling");
810
+ await cfEnableSsh(options.app, context);
811
+ }
812
+ emit("ssh-restarting", "Restarting app so SSH becomes active");
813
+ await updateSessionStatus(sessionId, "ssh-restarting");
814
+ await cfRestartApp(options.app, context);
815
+ checkAbort(options.signal);
816
+ await retryRemoteSignal(options, context, sessionId, emit);
817
+ }
818
+ async function retryRemoteSignal(options, context, sessionId, emit) {
819
+ emit("signaling");
820
+ await updateSessionStatus(sessionId, "signaling");
821
+ const retrySignalResult = await cfSshOneShot(
822
+ options.app,
823
+ `kill -s USR1 $(pidof node)`,
824
+ context
825
+ );
826
+ if (retrySignalResult.exitCode === 0) {
827
+ return;
828
+ }
829
+ const detail = retrySignalResult.stderr.trim().length > 0 ? retrySignalResult.stderr.trim() : `exit code ${String(retrySignalResult.exitCode)}`;
830
+ throw new CfDebuggerError(
831
+ "USR1_SIGNAL_FAILED",
832
+ `Failed to send SIGUSR1 to the Node.js process on ${options.app} after enabling SSH: ${detail}`,
833
+ retrySignalResult.stderr
834
+ );
835
+ }
836
+ async function waitAfterSignal(signal) {
837
+ await new Promise((resolve) => {
838
+ setTimeout(resolve, POST_USR1_DELAY_MS);
839
+ });
840
+ checkAbort(signal);
841
+ }
842
+ async function ensurePortAvailable(localPort) {
843
+ if (await isPortFree(localPort)) {
844
+ return;
845
+ }
846
+ await killProcessOnPort(localPort);
847
+ await new Promise((resolve) => {
848
+ setTimeout(resolve, PORT_RECLAIM_DELAY_MS);
849
+ });
850
+ if (!await isPortFree(localPort)) {
851
+ throw new CfDebuggerError(
852
+ "PORT_UNAVAILABLE",
853
+ `Local port ${localPort.toString()} is in use and could not be reclaimed for the tunnel.`
854
+ );
855
+ }
856
+ }
857
+ async function openReadyTunnel(options, session, context, tunnelReadyTimeoutMs, onChild) {
858
+ await ensurePortAvailable(session.localPort);
859
+ const child = spawnSshTunnel(options.app, session.localPort, session.remotePort, context);
860
+ onChild(child);
861
+ if (child.pid !== void 0) {
862
+ await updateSessionPid(session.sessionId, child.pid);
863
+ }
864
+ const ready = await probeTunnelReady(session.localPort, tunnelReadyTimeoutMs);
865
+ checkAbort(options.signal);
866
+ if (!ready) {
867
+ throw new CfDebuggerError(
868
+ "TUNNEL_NOT_READY",
869
+ `SSH tunnel on port ${session.localPort.toString()} did not become ready within ${Math.round(tunnelReadyTimeoutMs / 1e3).toString()}s.`
870
+ );
871
+ }
872
+ const listeningPid = await findListeningProcessId(session.localPort);
873
+ const activePid = listeningPid ?? child.pid ?? session.pid;
874
+ if (activePid !== session.pid) {
875
+ await updateSessionPid(session.sessionId, activePid);
876
+ }
877
+ return { child, activePid };
878
+ }
879
+ function attachTunnelEvents(child, markClosed, resolveExit, emit) {
880
+ child.on("close", (code) => {
881
+ markClosed();
882
+ resolveExit(code);
883
+ });
884
+ child.on("error", (err) => {
885
+ emit("error", err.message);
886
+ });
887
+ }
888
+ function createHandle(session, emit, finalize, exitPromise) {
889
+ let disposePromise;
890
+ return {
891
+ session,
892
+ dispose: async () => {
893
+ disposePromise ??= (async () => {
894
+ emit("stopping");
895
+ await updateSessionStatus(session.sessionId, "stopping");
896
+ await finalize();
897
+ })();
898
+ await disposePromise;
899
+ },
900
+ waitForExit: async () => {
901
+ return await exitPromise;
902
+ }
903
+ };
904
+ }
905
+ async function startDebugger(options) {
906
+ const { email, password } = requireCredentials(options);
907
+ const apiEndpoint = resolveApiEndpoint(options.region, options.apiEndpoint);
908
+ const tunnelReadyTimeoutMs = options.tunnelReadyTimeoutMs ?? DEFAULT_TUNNEL_READY_TIMEOUT_MS;
909
+ const emit = (status, message) => {
910
+ options.onStatus?.(status, message);
911
+ };
912
+ checkAbort(options.signal);
913
+ await pruneAndCleanupOrphans();
914
+ const session = await registerSession(options, apiEndpoint);
760
915
  const context = { cfHome: session.cfHomeDir };
761
916
  let child;
762
917
  let tunnelClosed = false;
763
- let exitResolve;
918
+ let exitResolve = (_code) => {
919
+ throw new Error("Exit resolver was used before initialization");
920
+ };
764
921
  const exitPromise = new Promise((resolve) => {
765
922
  exitResolve = resolve;
766
923
  });
767
- const cleanupFilesystem = async () => {
768
- try {
769
- await rm(session.cfHomeDir, { recursive: true, force: true });
770
- } catch {
771
- }
772
- };
773
924
  const finalize = async () => {
774
925
  if (!tunnelClosed) {
775
926
  tunnelClosed = true;
@@ -781,125 +932,37 @@ async function startDebugger(options) {
781
932
  }, PORT_CLEANUP_DELAY_MS);
782
933
  }
783
934
  await removeSession(session.sessionId);
784
- await cleanupFilesystem();
935
+ await cleanupFilesystem(session.cfHomeDir);
785
936
  emit("stopped");
786
937
  };
787
938
  try {
788
939
  await mkdir3(session.cfHomeDir, { recursive: true });
789
- emit("logging-in");
790
- await updateSessionStatus(session.sessionId, "logging-in");
791
- await cfLogin(apiEndpoint, email, password, context);
792
- checkAbort(options.signal);
793
- emit("targeting");
794
- await updateSessionStatus(session.sessionId, "targeting");
795
- await cfTarget(options.org, options.space, context);
796
- checkAbort(options.signal);
940
+ await loginAndTarget(options, apiEndpoint, email, password, context, session.sessionId, emit);
797
941
  await killProcessOnPort(session.localPort);
798
942
  await new Promise((resolve) => {
799
943
  setTimeout(resolve, 200);
800
944
  });
801
- emit("signaling");
802
- await updateSessionStatus(session.sessionId, "signaling");
803
- const signalResult = await cfSshOneShot(
804
- options.app,
805
- `kill -s USR1 $(pidof node)`,
806
- context
807
- );
808
- if (isSshDisabledError(signalResult.stderr)) {
809
- const alreadyEnabled = await cfSshEnabled(options.app, context);
810
- if (!alreadyEnabled) {
811
- emit("ssh-enabling", "Enabling SSH on the app");
812
- await updateSessionStatus(session.sessionId, "ssh-enabling");
813
- await cfEnableSsh(options.app, context);
814
- }
815
- emit("ssh-restarting", "Restarting app so SSH becomes active");
816
- await updateSessionStatus(session.sessionId, "ssh-restarting");
817
- await cfRestartApp(options.app, context);
818
- checkAbort(options.signal);
819
- emit("signaling");
820
- await updateSessionStatus(session.sessionId, "signaling");
821
- const retrySignalResult = await cfSshOneShot(
822
- options.app,
823
- `kill -s USR1 $(pidof node)`,
824
- context
825
- );
826
- if (retrySignalResult.exitCode !== 0) {
827
- const detail = retrySignalResult.stderr.trim().length > 0 ? retrySignalResult.stderr.trim() : `exit code ${String(retrySignalResult.exitCode)}`;
828
- throw new CfDebuggerError(
829
- "USR1_SIGNAL_FAILED",
830
- `Failed to send SIGUSR1 to the Node.js process on ${options.app} after enabling SSH: ${detail}`,
831
- retrySignalResult.stderr
832
- );
833
- }
834
- } else if (signalResult.exitCode !== 0) {
835
- const detail = signalResult.stderr.trim().length > 0 ? signalResult.stderr.trim() : `exit code ${String(signalResult.exitCode)}`;
836
- throw new CfDebuggerError(
837
- "USR1_SIGNAL_FAILED",
838
- `Failed to send SIGUSR1 to the Node.js process on ${options.app}: ${detail}`,
839
- signalResult.stderr
840
- );
841
- }
842
- await new Promise((resolve) => {
843
- setTimeout(resolve, POST_USR1_DELAY_MS);
844
- });
845
- checkAbort(options.signal);
945
+ await signalRemoteNode(options, context, session.sessionId, emit);
946
+ await waitAfterSignal(options.signal);
846
947
  emit("tunneling");
847
948
  await updateSessionStatus(session.sessionId, "tunneling");
848
- if (!await isPortFree(session.localPort)) {
849
- await killProcessOnPort(session.localPort);
850
- await new Promise((resolve) => {
851
- setTimeout(resolve, PORT_RECLAIM_DELAY_MS);
852
- });
853
- if (!await isPortFree(session.localPort)) {
854
- throw new CfDebuggerError(
855
- "PORT_UNAVAILABLE",
856
- `Local port ${session.localPort.toString()} is in use and could not be reclaimed for the tunnel.`
857
- );
949
+ const tunnel = await openReadyTunnel(
950
+ options,
951
+ session,
952
+ context,
953
+ tunnelReadyTimeoutMs,
954
+ (tunnelChild) => {
955
+ child = tunnelChild;
956
+ attachTunnelEvents(tunnelChild, () => {
957
+ tunnelClosed = true;
958
+ }, exitResolve, emit);
858
959
  }
859
- }
860
- child = spawnSshTunnel(options.app, session.localPort, session.remotePort, context);
861
- if (child.pid !== void 0) {
862
- await updateSessionPid(session.sessionId, child.pid);
863
- }
864
- child.on("close", (code) => {
865
- tunnelClosed = true;
866
- exitResolve?.(code);
867
- });
868
- child.on("error", (err) => {
869
- emit("error", err.message);
870
- });
871
- const ready = await probeTunnelReady(session.localPort, tunnelReadyTimeoutMs);
872
- checkAbort(options.signal);
873
- if (!ready) {
874
- throw new CfDebuggerError(
875
- "TUNNEL_NOT_READY",
876
- `SSH tunnel on port ${session.localPort.toString()} did not become ready within ${Math.round(tunnelReadyTimeoutMs / 1e3).toString()}s.`
877
- );
878
- }
879
- const listeningPid = await findListeningProcessId(session.localPort);
880
- const activePid = listeningPid ?? child.pid ?? session.pid;
881
- if (activePid !== session.pid) {
882
- await updateSessionPid(session.sessionId, activePid);
883
- }
960
+ );
961
+ child = tunnel.child;
884
962
  emit("ready");
885
963
  const readySession = await updateSessionStatus(session.sessionId, "ready");
886
- const activeSession = readySession ?? { ...session, pid: activePid, status: "ready" };
887
- let disposePromise;
888
- const handle = {
889
- session: activeSession,
890
- dispose: async () => {
891
- disposePromise ??= (async () => {
892
- emit("stopping");
893
- await updateSessionStatus(session.sessionId, "stopping");
894
- await finalize();
895
- })();
896
- await disposePromise;
897
- },
898
- waitForExit: async () => {
899
- return await exitPromise;
900
- }
901
- };
902
- return handle;
964
+ const activeSession = readySession ?? { ...session, pid: tunnel.activePid, status: "ready" };
965
+ return createHandle(activeSession, emit, finalize, exitPromise);
903
966
  } catch (err) {
904
967
  const message = err instanceof Error ? err.message : String(err);
905
968
  emit("error", message);
@@ -907,6 +970,16 @@ async function startDebugger(options) {
907
970
  throw err;
908
971
  }
909
972
  }
973
+ async function cleanupFilesystem(cfHomeDir) {
974
+ try {
975
+ await rm(cfHomeDir, { recursive: true, force: true });
976
+ } catch {
977
+ }
978
+ }
979
+
980
+ // src/debug-session/sessions.ts
981
+ import { rm as rm2 } from "fs/promises";
982
+ import process5 from "process";
910
983
  async function stopDebugger(options) {
911
984
  const sessions = await pruneAndCleanupOrphans();
912
985
  let target;
@@ -919,7 +992,7 @@ async function stopDebugger(options) {
919
992
  if (target === void 0) {
920
993
  return void 0;
921
994
  }
922
- if (target.pid !== process3.pid) {
995
+ if (target.pid !== process5.pid) {
923
996
  try {
924
997
  await terminatePidOrGroup(target.pid);
925
998
  } catch {
@@ -930,7 +1003,7 @@ async function stopDebugger(options) {
930
1003
  }, PORT_CLEANUP_DELAY_MS);
931
1004
  const removed = await removeSession(target.sessionId);
932
1005
  try {
933
- await rm(target.cfHomeDir, { recursive: true, force: true });
1006
+ await rm2(target.cfHomeDir, { recursive: true, force: true });
934
1007
  } catch {
935
1008
  }
936
1009
  return removed ?? target;
@@ -957,9 +1030,9 @@ async function getSession(key) {
957
1030
  // src/cli.ts
958
1031
  function readRequiredOption(value, flag) {
959
1032
  if (value === void 0 || value === "") {
960
- process4.stderr.write(`Missing required option ${flag}
1033
+ process6.stderr.write(`Missing required option ${flag}
961
1034
  `);
962
- process4.exit(1);
1035
+ process6.exit(1);
963
1036
  }
964
1037
  return value;
965
1038
  }
@@ -969,9 +1042,9 @@ function parseOptionalPort(raw) {
969
1042
  }
970
1043
  const port = Number.parseInt(raw, 10);
971
1044
  if (Number.isNaN(port) || port <= 0 || port > 65535) {
972
- process4.stderr.write(`Invalid port: ${raw}
1045
+ process6.stderr.write(`Invalid port: ${raw}
973
1046
  `);
974
- process4.exit(1);
1047
+ process6.exit(1);
975
1048
  }
976
1049
  return port;
977
1050
  }
@@ -981,16 +1054,16 @@ function parseOptionalTimeout(raw) {
981
1054
  }
982
1055
  const seconds = Number.parseInt(raw, 10);
983
1056
  if (Number.isNaN(seconds) || seconds <= 0) {
984
- process4.stderr.write(`Invalid timeout: ${raw}
1057
+ process6.stderr.write(`Invalid timeout: ${raw}
985
1058
  `);
986
- process4.exit(1);
1059
+ process6.exit(1);
987
1060
  }
988
1061
  return seconds * 1e3;
989
1062
  }
990
1063
  function logStatus(verbose, status, message) {
991
1064
  if (verbose) {
992
1065
  const suffix = message === void 0 ? "" : `: ${message}`;
993
- process4.stdout.write(`[cf-debugger] ${status}${suffix}
1066
+ process6.stdout.write(`[cf-debugger] ${status}${suffix}
994
1067
  `);
995
1068
  }
996
1069
  }
@@ -1005,17 +1078,17 @@ async function handleStart(opts) {
1005
1078
  const abortController = new AbortController();
1006
1079
  const onStartupSignal = (exitCode) => () => {
1007
1080
  abortController.abort();
1008
- process4.stderr.write(`
1081
+ process6.stderr.write(`
1009
1082
  Aborting startup for ${app}...
1010
1083
  `);
1011
1084
  setTimeout(() => {
1012
- process4.exit(exitCode);
1085
+ process6.exit(exitCode);
1013
1086
  }, 5e3).unref();
1014
1087
  };
1015
1088
  const startupSigint = onStartupSignal(130);
1016
1089
  const startupSigterm = onStartupSignal(143);
1017
- process4.on("SIGINT", startupSigint);
1018
- process4.on("SIGTERM", startupSigterm);
1090
+ process6.on("SIGINT", startupSigint);
1091
+ process6.on("SIGTERM", startupSigterm);
1019
1092
  let handle;
1020
1093
  try {
1021
1094
  handle = await startDebugger({
@@ -1032,10 +1105,10 @@ Aborting startup for ${app}...
1032
1105
  }
1033
1106
  });
1034
1107
  } finally {
1035
- process4.off("SIGINT", startupSigint);
1036
- process4.off("SIGTERM", startupSigterm);
1108
+ process6.off("SIGINT", startupSigint);
1109
+ process6.off("SIGTERM", startupSigterm);
1037
1110
  }
1038
- process4.stdout.write(
1111
+ process6.stdout.write(
1039
1112
  `Debugger ready for ${app} (${region}/${org}/${space}).
1040
1113
  Local port: ${handle.session.localPort.toString()}
1041
1114
  Remote port: ${handle.session.remotePort.toString()}
@@ -1047,32 +1120,32 @@ Press Ctrl+C to stop.
1047
1120
  let disposePromise;
1048
1121
  const dispose = async () => {
1049
1122
  disposePromise ??= (async () => {
1050
- process4.stdout.write(`
1123
+ process6.stdout.write(`
1051
1124
  Stopping debugger for ${app}...
1052
1125
  `);
1053
1126
  try {
1054
1127
  await handle.dispose();
1055
1128
  } catch (err) {
1056
1129
  const msg = err instanceof Error ? err.message : String(err);
1057
- process4.stderr.write(`Error during stop: ${msg}
1130
+ process6.stderr.write(`Error during stop: ${msg}
1058
1131
  `);
1059
1132
  }
1060
1133
  })();
1061
1134
  await disposePromise;
1062
1135
  };
1063
- process4.on("SIGINT", () => {
1136
+ process6.on("SIGINT", () => {
1064
1137
  void dispose().then(() => {
1065
- process4.exit(130);
1138
+ process6.exit(130);
1066
1139
  });
1067
1140
  });
1068
- process4.on("SIGTERM", () => {
1141
+ process6.on("SIGTERM", () => {
1069
1142
  void dispose().then(() => {
1070
- process4.exit(143);
1143
+ process6.exit(143);
1071
1144
  });
1072
1145
  });
1073
1146
  const code = await handle.waitForExit();
1074
1147
  await dispose();
1075
- process4.exit(code ?? 0);
1148
+ process6.exit(code ?? 0);
1076
1149
  }
1077
1150
  function resolveKeyFromOpts(opts) {
1078
1151
  if (opts.region !== void 0 && opts.org !== void 0 && opts.space !== void 0 && opts.app !== void 0) {
@@ -1088,7 +1161,7 @@ function resolveKeyFromOpts(opts) {
1088
1161
  async function handleStop(opts) {
1089
1162
  if (opts.all === true) {
1090
1163
  const count = await stopAllDebuggers();
1091
- process4.stdout.write(`Stopped ${count.toString()} session(s).
1164
+ process6.stdout.write(`Stopped ${count.toString()} session(s).
1092
1165
  `);
1093
1166
  return;
1094
1167
  }
@@ -1098,17 +1171,17 @@ async function handleStop(opts) {
1098
1171
  ...key === void 0 ? {} : { key }
1099
1172
  });
1100
1173
  if (result === void 0) {
1101
- process4.stderr.write("No matching session found.\n");
1102
- process4.exit(1);
1174
+ process6.stderr.write("No matching session found.\n");
1175
+ process6.exit(1);
1103
1176
  }
1104
- process4.stdout.write(
1177
+ process6.stdout.write(
1105
1178
  `Stopped session ${result.sessionId} (${result.app}, port ${result.localPort.toString()}).
1106
1179
  `
1107
1180
  );
1108
1181
  }
1109
1182
  async function handleList() {
1110
1183
  const sessions = await listSessions();
1111
- process4.stdout.write(`${JSON.stringify(sessions, null, 2)}
1184
+ process6.stdout.write(`${JSON.stringify(sessions, null, 2)}
1112
1185
  `);
1113
1186
  }
1114
1187
  async function handleStatus(opts) {
@@ -1118,7 +1191,7 @@ async function handleStatus(opts) {
1118
1191
  space: opts.space,
1119
1192
  app: opts.app
1120
1193
  });
1121
- process4.stdout.write(`${JSON.stringify(session ?? null, null, 2)}
1194
+ process6.stdout.write(`${JSON.stringify(session ?? null, null, 2)}
1122
1195
  `);
1123
1196
  }
1124
1197
  async function main(argv) {
@@ -1139,22 +1212,22 @@ async function main(argv) {
1139
1212
  await program.parseAsync([...argv]);
1140
1213
  }
1141
1214
  try {
1142
- await main(process4.argv);
1215
+ await main(process6.argv);
1143
1216
  } catch (err) {
1144
1217
  if (err instanceof CfDebuggerError) {
1145
1218
  if (err.code === "ABORTED") {
1146
- process4.stderr.write(`Aborted: ${err.message}
1219
+ process6.stderr.write(`Aborted: ${err.message}
1147
1220
  `);
1148
- process4.exit(130);
1221
+ process6.exit(130);
1149
1222
  }
1150
- process4.stderr.write(`Error [${err.code}]: ${err.message}
1223
+ process6.stderr.write(`Error [${err.code}]: ${err.message}
1151
1224
  `);
1152
1225
  } else {
1153
1226
  const msg = err instanceof Error ? err.message : String(err);
1154
- process4.stderr.write(`Error: ${msg}
1227
+ process6.stderr.write(`Error: ${msg}
1155
1228
  `);
1156
1229
  }
1157
- process4.exit(1);
1230
+ process6.exit(1);
1158
1231
  }
1159
1232
  export {
1160
1233
  main