feat(runtime): wire automatic Tailscale HTTPS lifecycle (PAP-17051)

Persist private lease state, reserve app/HMR pairs before spawn, bind Paperclip previews to loopback, publish only after validating HTTPS, and reconcile or clean up every lifecycle path.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
DottaandPaperclip committed 2026-08-16 19:26:07 +00:00
1 parent 1696e17c67
commit 831a2097ec
11 files changed
+677 -90

No files matched your search

+6 -1
View File
@@ -90,6 +90,7 @@ const tailscaleAuthFlagNames = new Set([
let tailscaleAuth = false;
let bindMode: BindMode | null = null;
let bindHost: string | null = null;
const managedRuntimeExposure = process.env.PAPERCLIP_MANAGED_RUNTIME_EXPOSURE === "tailscale_https";
const forwardedArgs: string[] = [];
for (let index = 0; index < cliArgs.length; index += 1) {
@@ -133,6 +134,10 @@ if (!bindMode && process.env.npm_config_bind && BIND_MODES.includes(process.env.
if (!bindHost && process.env.npm_config_bind_host) {
bindHost = process.env.npm_config_bind_host;
}
if (managedRuntimeExposure) {
bindMode = "custom";
bindHost = "127.0.0.1";
}
if (bindMode === "custom" && !bindHost) {
console.error("[paperclip] --bind custom requires --bind-host <host>");
process.exit(1);
@@ -174,7 +179,7 @@ if (tailscaleAuth || bindMode) {
} else {
env.PAPERCLIP_DEPLOYMENT_MODE = "authenticated";
env.PAPERCLIP_DEPLOYMENT_EXPOSURE = "private";
env.PAPERCLIP_AUTH_BASE_URL_MODE = "auto";
env.PAPERCLIP_AUTH_BASE_URL_MODE = managedRuntimeExposure ? "explicit" : "auto";
console.log(
`[paperclip] dev mode: authenticated/private (bind=${effectiveBind}${bindHost ? `:${bindHost}` : ""})`,
);