@hamedb89/localghost 0.4.0 → 0.5.0

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.d.ts CHANGED
@@ -543,18 +543,6 @@ declare function packageRunCommand(packageManager: PackageManager, script: strin
543
543
  declare function packageAddCommand(packageManager: PackageManager, packageName?: string): string;
544
544
  declare function initLocalghost(options?: InitOptions): InitResult;
545
545
 
546
- type FindAvailablePortOptions = {
547
- host?: string;
548
- maxAttempts?: number;
549
- };
550
- declare function isPortAvailable(port: number, host?: string): Promise<boolean>;
551
- declare function findAvailablePort(startPort: number, options?: FindAvailablePortOptions): Promise<number>;
552
-
553
- type ProcessSignal = NodeJS.Signals;
554
- type ProcessKiller = (pid: number, signal: ProcessSignal) => void;
555
- declare function signalManagedProcessPid(pid: number | undefined, signal: ProcessSignal, killProcess?: ProcessKiller): boolean;
556
- declare function signalManagedProcess(child: Pick<ChildProcess, "pid" | "kill" | "killed">, signal: ProcessSignal): boolean;
557
-
558
546
  declare const LOCALGHOST_REGISTRY_FILE = "registry.json";
559
547
  declare const LOCALGHOST_REGISTRY_LOCK_FILE = "registry.lock";
560
548
  type PortAvailabilityCheck = (port: number, host?: string) => boolean | Promise<boolean>;
@@ -599,12 +587,18 @@ type AcquireLocalghostPortOptions = {
599
587
  leaseTtlMs?: number;
600
588
  host?: string;
601
589
  };
590
+ type RenewLocalghostPortOptions = {
591
+ projectCwd?: string;
592
+ instanceKey: string;
593
+ leaseTtlMs?: number;
594
+ };
602
595
  type LocalghostRegistry = {
603
596
  root: string;
604
597
  registryPath: string;
605
598
  lockPath: string;
606
599
  ownerToken: string;
607
600
  acquirePort(options: AcquireLocalghostPortOptions): Promise<LocalghostLease>;
601
+ renewPort(options: RenewLocalghostPortOptions): Promise<LocalghostLease | undefined>;
608
602
  releasePort(options: {
609
603
  projectCwd?: string;
610
604
  instanceKey: string;
@@ -618,6 +612,38 @@ declare function getLocalghostRegistryRoot(env?: NodeJS.ProcessEnv): string;
618
612
  declare function canonicalizeLocalghostProjectCwd(cwd?: string): string;
619
613
  declare function createLocalghostRegistry(options?: LocalghostRegistryOptions): LocalghostRegistry;
620
614
 
615
+ type LocalghostTestSessionOptions = {
616
+ cwd?: string;
617
+ instanceKey: string;
618
+ services: Record<string, {
619
+ startPort: number;
620
+ maxAttempts?: number;
621
+ host?: string;
622
+ }>;
623
+ leaseTtlMs?: number;
624
+ };
625
+ type LocalghostTestSession = {
626
+ instanceKey: string;
627
+ ports: Record<string, number>;
628
+ leases: LocalghostLease[];
629
+ renew: () => Promise<void>;
630
+ startHeartbeat: (intervalMs?: number) => NodeJS.Timeout;
631
+ release: () => Promise<void>;
632
+ };
633
+ declare function createLocalghostTestSession(options: LocalghostTestSessionOptions): Promise<LocalghostTestSession>;
634
+
635
+ type FindAvailablePortOptions = {
636
+ host?: string;
637
+ maxAttempts?: number;
638
+ };
639
+ declare function isPortAvailable(port: number, host?: string): Promise<boolean>;
640
+ declare function findAvailablePort(startPort: number, options?: FindAvailablePortOptions): Promise<number>;
641
+
642
+ type ProcessSignal = NodeJS.Signals;
643
+ type ProcessKiller = (pid: number, signal: ProcessSignal) => void;
644
+ declare function signalManagedProcessPid(pid: number | undefined, signal: ProcessSignal, killProcess?: ProcessKiller): boolean;
645
+ declare function signalManagedProcess(child: Pick<ChildProcess, "pid" | "kill" | "killed">, signal: ProcessSignal): boolean;
646
+
621
647
  type DomainRoute = {
622
648
  host: string;
623
649
  port: number;
@@ -685,7 +711,7 @@ type CreateVercelGhostTunnelHandlerOptions = {
685
711
  declare function createVercelGhostTunnelHandler(options: CreateVercelGhostTunnelHandlerOptions): (request: VercelGhostTunnelRequestLike, response: VercelGhostTunnelResponseLike) => Promise<void>;
686
712
 
687
713
  declare const LOCALGHOST_PACKAGE_NAME = "@hamedb89/localghost";
688
- declare const LOCALGHOST_VERSION = "0.4.0";
714
+ declare const LOCALGHOST_VERSION = "0.5.0";
689
715
  declare const UPDATE_CHECK_CACHE_TTL_MS: number;
690
716
  declare const UPDATE_CHECK_NOTIFY_TTL_MS: number;
691
717
  declare const UPDATE_CHECK_TIMEOUT_MS = 900;
@@ -722,4 +748,4 @@ declare function maybeNotifyAboutUpdate(options?: {
722
748
  disabled?: boolean;
723
749
  }): Promise<void>;
724
750
 
725
- export { type AcquireLocalghostPortOptions, type ActiveRelayRoute, type CaddyModeOptions, type CaddyProcessKiller, type CaddyProcessStopResult, ConfigPattern, type ConstructGhostTunnelIpUrlInput, ConstructGhostTunnelUrlInput, type CreateVercelGhostTunnelHandlerOptions, DEFAULT_GHOST_TUNNEL_IP_TRANSPORT_TTL_SECONDS, DEFAULT_GHOST_TUNNEL_RESPONSE_TTL_SECONDS, DEFAULT_GHOST_TUNNEL_TRANSPORT_QUERY_PARAM, DEFAULT_RELAY_ALLOWED_TARGET_HOSTS, DEFAULT_RELAY_BLOCKED_PORTS, DEFAULT_RELAY_LIMITS, DEFAULT_RELAY_TARGET_POLICY, type DetectedDevCommand, type DetectedDevService, DevHostEntry, type DoctorOptions, type DoctorResult, type DomainRoute, type DomainRouteOptions, type FindAvailablePortOptions, type GhostTunnelAgent, type GhostTunnelAgentOptions, GhostTunnelConfig, type GhostTunnelHttpResponse, type GhostTunnelIpTransportClaim, GhostTunnelOptions, type GhostTunnelQueuedRequest, type GhostTunnelQueuedResponse, GhostTunnelRoute, type GhostTunnelRouteHeartbeat, type GhostTunnelStore, type GhostTunnelStoreEnv, GhostTunnelTransportConfig, GhostTunnelTransportOptions, type InitOptions, type InitResult, LOCALGHOST_ACTIVITY_VERSION, LOCALGHOST_AGENT_GUIDE, LOCALGHOST_GHOST_TUNNEL_FILE, LOCALGHOST_PACKAGE_NAME, LOCALGHOST_REGISTRY_FILE, LOCALGHOST_REGISTRY_LOCK_FILE, LOCALGHOST_STATE_FILE, LOCALGHOST_VERSION, type LocalghostActivity, type LocalghostContext, type LocalghostContextOptions, type LocalghostEnvironment, type LocalghostLease, type LocalghostPackageManager, type LocalghostProjectConfig, type LocalghostProjectConfigResult, type LocalghostRegistry, type LocalghostRegistryData, type LocalghostRegistryEntry, type LocalghostRegistryOptions, type LocalghostRunMode, type LocalghostRunRecord, type LocalghostServiceOptions, type LocalghostSetupRecord, type LocalghostState, type LocalghostStateAction, type PackageManager, type PortAvailabilityCheck, ReadDevHostsOptions, type ReadGhostTunnelOptions, type RedisGhostTunnelEnvResolution, type RedisGhostTunnelStoreOptions, type RegisterLocalghostRunInput, type RegisterLocalghostSetupInput, type RelayAccessMode, type RelayLimits, type RelayLocalTarget, type RelayOfflineResponse, type RelayProtocol, type RelayRouteClaim, type RelayRouteRegistrationInput, type RelayTargetPolicy, type RemoveSystemHostsResult, type ResolveGhostTunnelIpRedirectInput, type ResolveGhostTunnelRequestInput, ResolvedDevHostsPath, type ResolvedGhostTunnelIpRedirect, type ResolvedGhostTunnelRequest, type ServeGhostTunnelLocalRequestInput, type SignedGhostTunnelIpTransportClaim, type SignedRelayRouteClaim, UPDATE_CHECK_CACHE_TTL_MS, UPDATE_CHECK_NOTIFY_TTL_MS, UPDATE_CHECK_TIMEOUT_MS, type UpdateCheckCache, type UpdateCheckResult, type UpdateSystemHostsResult, type VercelGhostTunnelRequestLike, type VercelGhostTunnelResponseLike, type WriteLocalghostStateInput, assertExactRelayHost, assertLocalDevelopment, assertRelayLocalTarget, authenticateRelayAgentToken, canonicalizeLocalghostProjectCwd, checkCaddy, checkForUpdate, compareVersions, constructGhostTunnelIpUrl, createGhostTunnelQueuedRequest, createGhostTunnelRouteHeartbeat, createLocalghostRegistry, createMemoryGhostTunnelStore, createRedisGhostTunnelStore, createRedisGhostTunnelStoreFromEnv, createRelayRouteRegistration, createVercelGhostTunnelHandler, decodeGhostTunnelBody, defineLocalghostConfig, detectDevCommand, detectDevPackageManager, detectDevServices, detectPackageManager, encodeGhostTunnelBody, findAvailablePort, findGhostTunnelEntry, formatDetectedDevCommand, formatDetectedDevServices, formatDomainRoutes, formatGhostTunnel, formatLocalghostAgentGuide, formatUpdateMessage, getCaddyfilePath, getDomainRoutes, getGhostTunnelPath, getLocalghostActivityPath, getLocalghostRegistryRoot, getLocalghostStatePath, getProductionEnvKeys, getProductionReason, getSystemHostsPath, getUpdateCheckCachePath, initLocalghost, isNewerVersion, isPortAvailable, isProcessRunning, isProductionLike, isRelayRouteActive, isUpdateCheckDisabled, listGhostTunnelEntries, listLocalghostRuns, listLocalghostSetups, markUpdateNotified, maybeNotifyAboutUpdate, packageAddCommand, packageRunCommand, patchLocalghostState, pruneLocalghostActivity, readGhostTunnelEntries, readLocalghostActivity, readLocalghostProjectConfig, readLocalghostState, redactRelayHeaders, redactRelayLogUrl, registerLocalghostRun, registerLocalghostSetup, removeManagedBlock, removeSystemHosts, renderCaddyfile, renderCompactLocalghostBanner, renderGhostTunnelRelayOfflineResponse, renderGhostTunnelRouteMissingResponse, renderHostsBlock, renderLocalghostBanner, renderRelayOfflineResponse, resolveGhostTunnelIpRedirect, resolveGhostTunnelPath, resolveGhostTunnelRequest, resolveLocalghostContext, resolveRedisGhostTunnelEnv, runCaddy, runDoctor, serveGhostTunnelLocalRequest, shouldNotifyAboutUpdate, signGhostTunnelIpTransportClaim, signRelayRouteClaim, signalManagedProcess, signalManagedProcessPid, startCaddy, startGhostTunnelAgent, stopCaddyProcesses, stripRelayForwardHeaders, trustCaddy, unregisterLocalghostRun, unregisterLocalghostSetup, updateSystemHosts, upsertManagedBlock, validateCaddyfile, verifyGhostTunnelIpTransportClaim, verifyRelayRouteClaim, writeCaddyfile, writeLocalghostActivity, writeLocalghostState };
751
+ export { type AcquireLocalghostPortOptions, type ActiveRelayRoute, type CaddyModeOptions, type CaddyProcessKiller, type CaddyProcessStopResult, ConfigPattern, type ConstructGhostTunnelIpUrlInput, ConstructGhostTunnelUrlInput, type CreateVercelGhostTunnelHandlerOptions, DEFAULT_GHOST_TUNNEL_IP_TRANSPORT_TTL_SECONDS, DEFAULT_GHOST_TUNNEL_RESPONSE_TTL_SECONDS, DEFAULT_GHOST_TUNNEL_TRANSPORT_QUERY_PARAM, DEFAULT_RELAY_ALLOWED_TARGET_HOSTS, DEFAULT_RELAY_BLOCKED_PORTS, DEFAULT_RELAY_LIMITS, DEFAULT_RELAY_TARGET_POLICY, type DetectedDevCommand, type DetectedDevService, DevHostEntry, type DoctorOptions, type DoctorResult, type DomainRoute, type DomainRouteOptions, type FindAvailablePortOptions, type GhostTunnelAgent, type GhostTunnelAgentOptions, GhostTunnelConfig, type GhostTunnelHttpResponse, type GhostTunnelIpTransportClaim, GhostTunnelOptions, type GhostTunnelQueuedRequest, type GhostTunnelQueuedResponse, GhostTunnelRoute, type GhostTunnelRouteHeartbeat, type GhostTunnelStore, type GhostTunnelStoreEnv, GhostTunnelTransportConfig, GhostTunnelTransportOptions, type InitOptions, type InitResult, LOCALGHOST_ACTIVITY_VERSION, LOCALGHOST_AGENT_GUIDE, LOCALGHOST_GHOST_TUNNEL_FILE, LOCALGHOST_PACKAGE_NAME, LOCALGHOST_REGISTRY_FILE, LOCALGHOST_REGISTRY_LOCK_FILE, LOCALGHOST_STATE_FILE, LOCALGHOST_VERSION, type LocalghostActivity, type LocalghostContext, type LocalghostContextOptions, type LocalghostEnvironment, type LocalghostLease, type LocalghostPackageManager, type LocalghostProjectConfig, type LocalghostProjectConfigResult, type LocalghostRegistry, type LocalghostRegistryData, type LocalghostRegistryEntry, type LocalghostRegistryOptions, type LocalghostRunMode, type LocalghostRunRecord, type LocalghostServiceOptions, type LocalghostSetupRecord, type LocalghostState, type LocalghostStateAction, type LocalghostTestSession, type LocalghostTestSessionOptions, type PackageManager, type PortAvailabilityCheck, ReadDevHostsOptions, type ReadGhostTunnelOptions, type RedisGhostTunnelEnvResolution, type RedisGhostTunnelStoreOptions, type RegisterLocalghostRunInput, type RegisterLocalghostSetupInput, type RelayAccessMode, type RelayLimits, type RelayLocalTarget, type RelayOfflineResponse, type RelayProtocol, type RelayRouteClaim, type RelayRouteRegistrationInput, type RelayTargetPolicy, type RemoveSystemHostsResult, type ResolveGhostTunnelIpRedirectInput, type ResolveGhostTunnelRequestInput, ResolvedDevHostsPath, type ResolvedGhostTunnelIpRedirect, type ResolvedGhostTunnelRequest, type ServeGhostTunnelLocalRequestInput, type SignedGhostTunnelIpTransportClaim, type SignedRelayRouteClaim, UPDATE_CHECK_CACHE_TTL_MS, UPDATE_CHECK_NOTIFY_TTL_MS, UPDATE_CHECK_TIMEOUT_MS, type UpdateCheckCache, type UpdateCheckResult, type UpdateSystemHostsResult, type VercelGhostTunnelRequestLike, type VercelGhostTunnelResponseLike, type WriteLocalghostStateInput, assertExactRelayHost, assertLocalDevelopment, assertRelayLocalTarget, authenticateRelayAgentToken, canonicalizeLocalghostProjectCwd, checkCaddy, checkForUpdate, compareVersions, constructGhostTunnelIpUrl, createGhostTunnelQueuedRequest, createGhostTunnelRouteHeartbeat, createLocalghostRegistry, createLocalghostTestSession, createMemoryGhostTunnelStore, createRedisGhostTunnelStore, createRedisGhostTunnelStoreFromEnv, createRelayRouteRegistration, createVercelGhostTunnelHandler, decodeGhostTunnelBody, defineLocalghostConfig, detectDevCommand, detectDevPackageManager, detectDevServices, detectPackageManager, encodeGhostTunnelBody, findAvailablePort, findGhostTunnelEntry, formatDetectedDevCommand, formatDetectedDevServices, formatDomainRoutes, formatGhostTunnel, formatLocalghostAgentGuide, formatUpdateMessage, getCaddyfilePath, getDomainRoutes, getGhostTunnelPath, getLocalghostActivityPath, getLocalghostRegistryRoot, getLocalghostStatePath, getProductionEnvKeys, getProductionReason, getSystemHostsPath, getUpdateCheckCachePath, initLocalghost, isNewerVersion, isPortAvailable, isProcessRunning, isProductionLike, isRelayRouteActive, isUpdateCheckDisabled, listGhostTunnelEntries, listLocalghostRuns, listLocalghostSetups, markUpdateNotified, maybeNotifyAboutUpdate, packageAddCommand, packageRunCommand, patchLocalghostState, pruneLocalghostActivity, readGhostTunnelEntries, readLocalghostActivity, readLocalghostProjectConfig, readLocalghostState, redactRelayHeaders, redactRelayLogUrl, registerLocalghostRun, registerLocalghostSetup, removeManagedBlock, removeSystemHosts, renderCaddyfile, renderCompactLocalghostBanner, renderGhostTunnelRelayOfflineResponse, renderGhostTunnelRouteMissingResponse, renderHostsBlock, renderLocalghostBanner, renderRelayOfflineResponse, resolveGhostTunnelIpRedirect, resolveGhostTunnelPath, resolveGhostTunnelRequest, resolveLocalghostContext, resolveRedisGhostTunnelEnv, runCaddy, runDoctor, serveGhostTunnelLocalRequest, shouldNotifyAboutUpdate, signGhostTunnelIpTransportClaim, signRelayRouteClaim, signalManagedProcess, signalManagedProcessPid, startCaddy, startGhostTunnelAgent, stopCaddyProcesses, stripRelayForwardHeaders, trustCaddy, unregisterLocalghostRun, unregisterLocalghostSetup, updateSystemHosts, upsertManagedBlock, validateCaddyfile, verifyGhostTunnelIpTransportClaim, verifyRelayRouteClaim, writeCaddyfile, writeLocalghostActivity, writeLocalghostState };
package/dist/index.js CHANGED
@@ -844,11 +844,11 @@ function isStopped(signal, localSignal) {
844
844
  }
845
845
  function wait(ms, signal, localSignal) {
846
846
  if (isStopped(signal, localSignal)) return Promise.resolve();
847
- return new Promise((resolve4) => {
848
- const timeout = setTimeout(resolve4, ms);
847
+ return new Promise((resolve5) => {
848
+ const timeout = setTimeout(resolve5, ms);
849
849
  const stop = () => {
850
850
  clearTimeout(timeout);
851
- resolve4();
851
+ resolve5();
852
852
  };
853
853
  signal?.addEventListener("abort", stop, { once: true });
854
854
  localSignal.addEventListener("abort", stop, { once: true });
@@ -1696,13 +1696,13 @@ import { pathToFileURL } from "url";
1696
1696
  // src/port.ts
1697
1697
  import { createServer } from "net";
1698
1698
  async function isPortAvailable(port, host = "127.0.0.1") {
1699
- return new Promise((resolve4) => {
1699
+ return new Promise((resolve5) => {
1700
1700
  const server = createServer();
1701
1701
  server.once("error", () => {
1702
- resolve4(false);
1702
+ resolve5(false);
1703
1703
  });
1704
1704
  server.once("listening", () => {
1705
- server.close(() => resolve4(true));
1705
+ server.close(() => resolve5(true));
1706
1706
  });
1707
1707
  server.listen(port, host);
1708
1708
  });
@@ -1888,6 +1888,18 @@ function createLocalghostRegistry(options = {}) {
1888
1888
  return lease;
1889
1889
  });
1890
1890
  },
1891
+ async renewPort(renewOptions) {
1892
+ const projectCwd = canonicalizeLocalghostProjectCwd(renewOptions.projectCwd ?? cwd);
1893
+ return withLock(async (registry) => {
1894
+ const lease = registry.leases.find(
1895
+ (candidate) => candidate.projectCwd === projectCwd && candidate.instanceKey === renewOptions.instanceKey && candidate.ownerToken === ownerToken
1896
+ );
1897
+ if (!lease || lease.expiresAt <= now() || !isRunning(lease.pid)) return void 0;
1898
+ lease.expiresAt = now() + (renewOptions.leaseTtlMs ?? 30 * 60 * 1e3);
1899
+ await writeRegistry(registry);
1900
+ return lease;
1901
+ });
1902
+ },
1891
1903
  async releasePort(releaseOptions) {
1892
1904
  const projectCwd = canonicalizeLocalghostProjectCwd(releaseOptions.projectCwd ?? cwd);
1893
1905
  return withLock(async (registry) => {
@@ -2429,7 +2441,7 @@ async function removeSystemHosts(projectName) {
2429
2441
 
2430
2442
  // src/init.ts
2431
2443
  import { existsSync as existsSync5, readFileSync as readFileSync6, writeFileSync as writeFileSync4 } from "fs";
2432
- import { join as join8 } from "path";
2444
+ import { dirname as dirname4, join as join8, resolve as resolve4 } from "path";
2433
2445
  function detectPackageManager(cwd = process.cwd()) {
2434
2446
  if (existsSync5(join8(cwd, "pnpm-lock.yaml"))) return "pnpm";
2435
2447
  if (existsSync5(join8(cwd, "yarn.lock"))) return "yarn";
@@ -2561,6 +2573,59 @@ function initLocalghost(options = {}) {
2561
2573
  };
2562
2574
  }
2563
2575
 
2576
+ // src/test-session.ts
2577
+ async function createLocalghostTestSession(options) {
2578
+ if (!options.instanceKey) throw new Error("instanceKey is required");
2579
+ const registry = createLocalghostRegistry(options.cwd ? { cwd: options.cwd } : {});
2580
+ const leases = [];
2581
+ const ports = {};
2582
+ const leaseTtlMs = options.leaseTtlMs ?? 30 * 60 * 1e3;
2583
+ if (!Number.isFinite(leaseTtlMs) || leaseTtlMs < 1e3) throw new Error("leaseTtlMs must be at least 1000 milliseconds.");
2584
+ try {
2585
+ for (const [name, service] of Object.entries(options.services)) {
2586
+ const lease = await registry.acquirePort({
2587
+ ...options.cwd ? { projectCwd: options.cwd } : {},
2588
+ instanceKey: `test:${options.instanceKey}:${name}`,
2589
+ startPort: service.startPort,
2590
+ ...service.maxAttempts !== void 0 ? { maxAttempts: service.maxAttempts } : {},
2591
+ ...service.host !== void 0 ? { host: service.host } : {},
2592
+ leaseTtlMs,
2593
+ reservedPorts: Object.values(ports)
2594
+ });
2595
+ leases.push(lease);
2596
+ ports[name] = lease.port;
2597
+ }
2598
+ } catch (error) {
2599
+ await Promise.all(leases.map((lease) => registry.releasePort({ projectCwd: lease.projectCwd, instanceKey: lease.instanceKey })));
2600
+ throw error;
2601
+ }
2602
+ let released = false;
2603
+ const renew = async () => {
2604
+ if (released) return;
2605
+ await Promise.all(leases.map(async (lease) => {
2606
+ const renewed = await registry.renewPort({ projectCwd: lease.projectCwd, instanceKey: lease.instanceKey, leaseTtlMs });
2607
+ if (!renewed) throw new Error(`Localghost test lease expired: ${lease.instanceKey}`);
2608
+ }));
2609
+ };
2610
+ return {
2611
+ instanceKey: options.instanceKey,
2612
+ ports,
2613
+ leases,
2614
+ renew,
2615
+ startHeartbeat(intervalMs = Math.max(1e3, Math.floor(leaseTtlMs / 3))) {
2616
+ if (!Number.isFinite(intervalMs) || intervalMs < 1e3) throw new Error("Heartbeat interval must be at least 1000 milliseconds.");
2617
+ const timer = setInterval(() => void renew().catch(() => void 0), intervalMs);
2618
+ timer.unref();
2619
+ return timer;
2620
+ },
2621
+ async release() {
2622
+ if (released) return;
2623
+ released = true;
2624
+ await Promise.all(leases.map((lease) => registry.releasePort({ projectCwd: lease.projectCwd, instanceKey: lease.instanceKey })));
2625
+ }
2626
+ };
2627
+ }
2628
+
2564
2629
  // src/process.ts
2565
2630
  function signalManagedProcessPid(pid, signal, killProcess = (value, processSignal) => process.kill(value, processSignal)) {
2566
2631
  if (typeof pid !== "number" || !Number.isInteger(pid) || pid < 1) return false;
@@ -2796,7 +2861,7 @@ async function waitForTunnelResponse(input) {
2796
2861
  await input.store.cleanup(input.requestId);
2797
2862
  return response;
2798
2863
  }
2799
- await new Promise((resolve4) => setTimeout(resolve4, input.pollIntervalMs));
2864
+ await new Promise((resolve5) => setTimeout(resolve5, input.pollIntervalMs));
2800
2865
  }
2801
2866
  return null;
2802
2867
  }
@@ -2897,9 +2962,9 @@ function createVercelGhostTunnelHandler(options) {
2897
2962
  // src/update-check.ts
2898
2963
  import { existsSync as existsSync7, mkdirSync as mkdirSync3, readFileSync as readFileSync7, writeFileSync as writeFileSync5 } from "fs";
2899
2964
  import { homedir as homedir3 } from "os";
2900
- import { dirname as dirname4, join as join10 } from "path";
2965
+ import { dirname as dirname5, join as join10 } from "path";
2901
2966
  var LOCALGHOST_PACKAGE_NAME = "@hamedb89/localghost";
2902
- var LOCALGHOST_VERSION = "0.4.0";
2967
+ var LOCALGHOST_VERSION = "0.5.0";
2903
2968
  var UPDATE_CHECK_CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
2904
2969
  var UPDATE_CHECK_NOTIFY_TTL_MS = 24 * 60 * 60 * 1e3;
2905
2970
  var UPDATE_CHECK_TIMEOUT_MS = 900;
@@ -2924,7 +2989,7 @@ function readCache(path = getUpdateCheckCachePath()) {
2924
2989
  }
2925
2990
  function writeCache(cache, path = getUpdateCheckCachePath()) {
2926
2991
  try {
2927
- mkdirSync3(dirname4(path), { recursive: true });
2992
+ mkdirSync3(dirname5(path), { recursive: true });
2928
2993
  writeFileSync5(path, `${JSON.stringify(cache, null, 2)}
2929
2994
  `, "utf8");
2930
2995
  } catch {
@@ -3097,6 +3162,7 @@ export {
3097
3162
  createGhostTunnelQueuedRequest,
3098
3163
  createGhostTunnelRouteHeartbeat,
3099
3164
  createLocalghostRegistry,
3165
+ createLocalghostTestSession,
3100
3166
  createMemoryGhostTunnelStore,
3101
3167
  createRedisGhostTunnelStore,
3102
3168
  createRedisGhostTunnelStoreFromEnv,