@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/README.md +5 -5
- package/dist/cli.js +319 -107
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +40 -14
- package/dist/index.js +77 -11
- package/dist/index.js.map +1 -1
- package/dist/vite.js +12 -0
- package/dist/vite.js.map +1 -1
- package/docs/localghost.1.md +16 -0
- package/package.json +1 -1
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.
|
|
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((
|
|
848
|
-
const timeout = setTimeout(
|
|
847
|
+
return new Promise((resolve5) => {
|
|
848
|
+
const timeout = setTimeout(resolve5, ms);
|
|
849
849
|
const stop = () => {
|
|
850
850
|
clearTimeout(timeout);
|
|
851
|
-
|
|
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((
|
|
1699
|
+
return new Promise((resolve5) => {
|
|
1700
1700
|
const server = createServer();
|
|
1701
1701
|
server.once("error", () => {
|
|
1702
|
-
|
|
1702
|
+
resolve5(false);
|
|
1703
1703
|
});
|
|
1704
1704
|
server.once("listening", () => {
|
|
1705
|
-
server.close(() =>
|
|
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((
|
|
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
|
|
2965
|
+
import { dirname as dirname5, join as join10 } from "path";
|
|
2901
2966
|
var LOCALGHOST_PACKAGE_NAME = "@hamedb89/localghost";
|
|
2902
|
-
var LOCALGHOST_VERSION = "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(
|
|
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,
|