@specific.dev/cli 0.1.87 → 0.1.89
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/admin/404/index.html +1 -1
- package/dist/admin/404.html +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.__PAGE__.txt +1 -1
- package/dist/admin/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/__next._full.txt +1 -1
- package/dist/admin/__next._head.txt +1 -1
- package/dist/admin/__next._index.txt +1 -1
- package/dist/admin/__next._tree.txt +1 -1
- package/dist/admin/_not-found/__next._full.txt +1 -1
- package/dist/admin/_not-found/__next._head.txt +1 -1
- package/dist/admin/_not-found/__next._index.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/admin/_not-found/__next._not-found.txt +1 -1
- package/dist/admin/_not-found/__next._tree.txt +1 -1
- package/dist/admin/_not-found/index.html +1 -1
- package/dist/admin/_not-found/index.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.__PAGE__.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.databases.txt +1 -1
- package/dist/admin/databases/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/databases/__next._full.txt +1 -1
- package/dist/admin/databases/__next._head.txt +1 -1
- package/dist/admin/databases/__next._index.txt +1 -1
- package/dist/admin/databases/__next._tree.txt +1 -1
- package/dist/admin/databases/index.html +1 -1
- package/dist/admin/databases/index.txt +1 -1
- package/dist/admin/fullscreen/__next._full.txt +1 -1
- package/dist/admin/fullscreen/__next._head.txt +1 -1
- package/dist/admin/fullscreen/__next._index.txt +1 -1
- package/dist/admin/fullscreen/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._full.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._head.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._index.txt +1 -1
- package/dist/admin/fullscreen/databases/__next._tree.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.__PAGE__.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.databases.txt +1 -1
- package/dist/admin/fullscreen/databases/__next.fullscreen.txt +1 -1
- package/dist/admin/fullscreen/databases/index.html +1 -1
- package/dist/admin/fullscreen/databases/index.txt +1 -1
- package/dist/admin/fullscreen/index.html +1 -1
- package/dist/admin/fullscreen/index.txt +1 -1
- package/dist/admin/index.html +1 -1
- package/dist/admin/index.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.__PAGE__.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.mail.txt +1 -1
- package/dist/admin/mail/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/mail/__next._full.txt +1 -1
- package/dist/admin/mail/__next._head.txt +1 -1
- package/dist/admin/mail/__next._index.txt +1 -1
- package/dist/admin/mail/__next._tree.txt +1 -1
- package/dist/admin/mail/index.html +1 -1
- package/dist/admin/mail/index.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.__PAGE__.txt +1 -1
- package/dist/admin/workflows/__next.!KGRlZmF1bHQp.workflows.txt +1 -1
- package/dist/admin/workflows/__next._full.txt +1 -1
- package/dist/admin/workflows/__next._head.txt +1 -1
- package/dist/admin/workflows/__next._index.txt +1 -1
- package/dist/admin/workflows/__next._tree.txt +1 -1
- package/dist/admin/workflows/index.html +1 -1
- package/dist/admin/workflows/index.txt +1 -1
- package/dist/cli.js +210 -121
- package/dist/postinstall.js +1 -1
- package/package.json +1 -1
- /package/dist/admin/_next/static/{gTSwsUHBTwlXnncoAFB77 → QGNtzZ5y-zIMtO9d5ZuTF}/_buildManifest.js +0 -0
- /package/dist/admin/_next/static/{gTSwsUHBTwlXnncoAFB77 → QGNtzZ5y-zIMtO9d5ZuTF}/_clientMiddlewareManifest.json +0 -0
- /package/dist/admin/_next/static/{gTSwsUHBTwlXnncoAFB77 → QGNtzZ5y-zIMtO9d5ZuTF}/_ssgManifest.js +0 -0
package/dist/cli.js
CHANGED
|
@@ -185203,6 +185203,7 @@ import * as path7 from "path";
|
|
|
185203
185203
|
import { fileURLToPath } from "url";
|
|
185204
185204
|
import httpProxy from "http-proxy";
|
|
185205
185205
|
import * as net2 from "net";
|
|
185206
|
+
import * as net3 from "net";
|
|
185206
185207
|
import { spawn as spawn3 } from "child_process";
|
|
185207
185208
|
import { readFile as readFile2, writeFile as writeFile2, mkdir } from "fs/promises";
|
|
185208
185209
|
import { existsSync as existsSync8 } from "fs";
|
|
@@ -185210,7 +185211,7 @@ import * as path8 from "path";
|
|
|
185210
185211
|
import * as crypto from "crypto";
|
|
185211
185212
|
import * as http2 from "http";
|
|
185212
185213
|
import * as crypto2 from "crypto";
|
|
185213
|
-
import * as
|
|
185214
|
+
import * as net4 from "net";
|
|
185214
185215
|
import * as fs8 from "fs";
|
|
185215
185216
|
import * as path9 from "path";
|
|
185216
185217
|
import { spawn as spawn4 } from "child_process";
|
|
@@ -185220,7 +185221,7 @@ import * as path10 from "path";
|
|
|
185220
185221
|
import { spawnSync } from "child_process";
|
|
185221
185222
|
import * as fs10 from "fs";
|
|
185222
185223
|
import * as path11 from "path";
|
|
185223
|
-
import * as
|
|
185224
|
+
import * as net5 from "net";
|
|
185224
185225
|
import { spawn as spawn5 } from "child_process";
|
|
185225
185226
|
import * as fs11 from "fs";
|
|
185226
185227
|
import * as path12 from "path";
|
|
@@ -185238,11 +185239,11 @@ import * as fs14 from "fs";
|
|
|
185238
185239
|
import * as path14 from "path";
|
|
185239
185240
|
import { generateSlug } from "random-word-slugs";
|
|
185240
185241
|
import { EventEmitter as EventEmitter2 } from "node:events";
|
|
185241
|
-
import * as
|
|
185242
|
+
import * as net6 from "node:net";
|
|
185242
185243
|
import * as fs15 from "fs";
|
|
185243
185244
|
import * as path15 from "path";
|
|
185244
185245
|
import * as os6 from "os";
|
|
185245
|
-
import * as
|
|
185246
|
+
import * as net7 from "net";
|
|
185246
185247
|
import { EventEmitter as EventEmitter22 } from "events";
|
|
185247
185248
|
import { execSync as execSync4 } from "child_process";
|
|
185248
185249
|
import * as path17 from "path";
|
|
@@ -370228,6 +370229,7 @@ var adminDir = path7.join(__dirname, "admin");
|
|
|
370228
370229
|
var _embeddedAdmin = null;
|
|
370229
370230
|
var HTTP_PORT = 80;
|
|
370230
370231
|
var HTTPS_PORT = 443;
|
|
370232
|
+
var FALLBACK_HTTPS_PORT = 3443;
|
|
370231
370233
|
var DOMAIN_SUFFIX = ".spcf.localhost";
|
|
370232
370234
|
var ADMIN_DOMAIN = "spcf.localhost";
|
|
370233
370235
|
var DRIZZLE_GATEWAY_PREFIX = "__drizzle_gateway";
|
|
@@ -370246,7 +370248,23 @@ var MIME_TYPES = {
|
|
|
370246
370248
|
".woff2": "font/woff2",
|
|
370247
370249
|
".txt": "text/plain"
|
|
370248
370250
|
};
|
|
370249
|
-
|
|
370251
|
+
function isPortAvailable(port) {
|
|
370252
|
+
return new Promise((resolve52) => {
|
|
370253
|
+
const server = net2.createServer();
|
|
370254
|
+
server.once("error", () => resolve52(false));
|
|
370255
|
+
server.once("listening", () => {
|
|
370256
|
+
server.close(() => resolve52(true));
|
|
370257
|
+
});
|
|
370258
|
+
server.listen(port, "0.0.0.0");
|
|
370259
|
+
});
|
|
370260
|
+
}
|
|
370261
|
+
async function probeHttpsPort() {
|
|
370262
|
+
for (const port of [HTTPS_PORT, FALLBACK_HTTPS_PORT]) {
|
|
370263
|
+
if (await isPortAvailable(port)) return port;
|
|
370264
|
+
}
|
|
370265
|
+
return 0;
|
|
370266
|
+
}
|
|
370267
|
+
async function startHttpProxy(services, certificate, getState, instanceKey = "default", preferredHttpsPort) {
|
|
370250
370268
|
const serviceMap = /* @__PURE__ */ new Map();
|
|
370251
370269
|
const adminPortMap = /* @__PURE__ */ new Map();
|
|
370252
370270
|
const drizzleGatewayPortMap = /* @__PURE__ */ new Map();
|
|
@@ -370348,11 +370366,11 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
|
|
|
370348
370366
|
return sendNotFound(res, null, serviceMap);
|
|
370349
370367
|
}
|
|
370350
370368
|
const mapKey = buildMapKey(route.serviceName, route.key);
|
|
370351
|
-
const
|
|
370352
|
-
if (!
|
|
370369
|
+
const targetPort2 = serviceMap.get(mapKey);
|
|
370370
|
+
if (!targetPort2) {
|
|
370353
370371
|
return sendNotFound(res, route.serviceName, serviceMap);
|
|
370354
370372
|
}
|
|
370355
|
-
proxy.web(req, res, { target: `http://127.0.0.1:${
|
|
370373
|
+
proxy.web(req, res, { target: `http://127.0.0.1:${targetPort2}` });
|
|
370356
370374
|
};
|
|
370357
370375
|
const handleUpgrade = (req, socket, head) => {
|
|
370358
370376
|
const host = req.headers.host || "";
|
|
@@ -370389,108 +370407,145 @@ async function startHttpProxy(services, certificate, getState, instanceKey = "de
|
|
|
370389
370407
|
return;
|
|
370390
370408
|
}
|
|
370391
370409
|
const mapKey = buildMapKey(route.serviceName, route.key);
|
|
370392
|
-
const
|
|
370393
|
-
if (!
|
|
370410
|
+
const targetPort2 = serviceMap.get(mapKey);
|
|
370411
|
+
if (!targetPort2) {
|
|
370394
370412
|
socket.end("HTTP/1.1 404 Not Found\r\n\r\n");
|
|
370395
370413
|
return;
|
|
370396
370414
|
}
|
|
370397
|
-
proxy.ws(req, socket, head, { target: `http://127.0.0.1:${
|
|
370415
|
+
proxy.ws(req, socket, head, { target: `http://127.0.0.1:${targetPort2}` });
|
|
370398
370416
|
};
|
|
370399
|
-
const httpServer = http.createServer(handleRequest);
|
|
370400
|
-
httpServer.on("upgrade", handleUpgrade);
|
|
370401
|
-
let httpsServer = https.createServer(
|
|
370402
|
-
{
|
|
370403
|
-
key: defaultKey,
|
|
370404
|
-
cert: defaultCert
|
|
370405
|
-
},
|
|
370406
|
-
handleRequest
|
|
370407
|
-
);
|
|
370408
|
-
httpsServer.on("upgrade", handleUpgrade);
|
|
370409
370417
|
const createHttpsServer = (key, cert) => {
|
|
370410
370418
|
const server = https.createServer({ key, cert }, handleRequest);
|
|
370411
370419
|
server.on("upgrade", handleUpgrade);
|
|
370412
370420
|
return server;
|
|
370413
370421
|
};
|
|
370414
|
-
|
|
370415
|
-
let
|
|
370416
|
-
|
|
370417
|
-
|
|
370418
|
-
|
|
370419
|
-
|
|
370420
|
-
|
|
370421
|
-
|
|
370422
|
-
|
|
370423
|
-
|
|
370424
|
-
|
|
370425
|
-
|
|
370426
|
-
|
|
370427
|
-
|
|
370428
|
-
|
|
370429
|
-
|
|
370430
|
-
|
|
370431
|
-
|
|
370432
|
-
|
|
370433
|
-
|
|
370434
|
-
|
|
370435
|
-
|
|
370436
|
-
|
|
370437
|
-
|
|
370438
|
-
|
|
370439
|
-
|
|
370440
|
-
|
|
370441
|
-
|
|
370442
|
-
|
|
370443
|
-
|
|
370422
|
+
const makeInstance = (httpsServer, actualHttpsPort, httpServer, actualHttpPort) => {
|
|
370423
|
+
let currentHttpsServer = httpsServer;
|
|
370424
|
+
return {
|
|
370425
|
+
httpPort: actualHttpPort ?? 0,
|
|
370426
|
+
httpsPort: actualHttpsPort,
|
|
370427
|
+
updateServices,
|
|
370428
|
+
updateCertificate(newCert) {
|
|
370429
|
+
if (typeof currentHttpsServer.setSecureContext === "function") {
|
|
370430
|
+
currentHttpsServer.setSecureContext({
|
|
370431
|
+
key: newCert.key,
|
|
370432
|
+
cert: newCert.cert
|
|
370433
|
+
});
|
|
370434
|
+
writeLog("proxy", "Certificate updated");
|
|
370435
|
+
} else {
|
|
370436
|
+
const oldServer = currentHttpsServer;
|
|
370437
|
+
currentHttpsServer = createHttpsServer(newCert.key, newCert.cert);
|
|
370438
|
+
currentHttpsServer.listen(actualHttpsPort, "0.0.0.0", () => {
|
|
370439
|
+
writeLog("proxy", "Certificate updated (server restarted)");
|
|
370440
|
+
});
|
|
370441
|
+
oldServer.closeAllConnections?.();
|
|
370442
|
+
oldServer.close();
|
|
370443
|
+
}
|
|
370444
|
+
},
|
|
370445
|
+
async stop() {
|
|
370446
|
+
return new Promise((resolve52) => {
|
|
370447
|
+
const serverCount = httpServer ? 2 : 1;
|
|
370448
|
+
let closed = 0;
|
|
370449
|
+
const onClose = () => {
|
|
370450
|
+
closed++;
|
|
370451
|
+
if (closed === serverCount) {
|
|
370452
|
+
clearTimeout(forceCloseTimeout);
|
|
370453
|
+
resolve52();
|
|
370444
370454
|
}
|
|
370445
|
-
}
|
|
370446
|
-
|
|
370447
|
-
|
|
370448
|
-
|
|
370449
|
-
|
|
370450
|
-
|
|
370451
|
-
|
|
370452
|
-
|
|
370453
|
-
resolve62();
|
|
370454
|
-
}
|
|
370455
|
-
};
|
|
370456
|
-
httpServer.close(onClose);
|
|
370457
|
-
httpsServer.close(onClose);
|
|
370458
|
-
const forceCloseTimeout = setTimeout(() => {
|
|
370459
|
-
httpServer.closeAllConnections?.();
|
|
370460
|
-
httpsServer.closeAllConnections?.();
|
|
370461
|
-
resolve62();
|
|
370462
|
-
}, 2e3);
|
|
370463
|
-
});
|
|
370464
|
-
}
|
|
370455
|
+
};
|
|
370456
|
+
currentHttpsServer.close(onClose);
|
|
370457
|
+
httpServer?.close(onClose);
|
|
370458
|
+
const forceCloseTimeout = setTimeout(() => {
|
|
370459
|
+
currentHttpsServer.closeAllConnections?.();
|
|
370460
|
+
httpServer?.closeAllConnections?.();
|
|
370461
|
+
resolve52();
|
|
370462
|
+
}, 2e3);
|
|
370465
370463
|
});
|
|
370466
370464
|
}
|
|
370467
370465
|
};
|
|
370468
|
-
|
|
370469
|
-
|
|
370470
|
-
|
|
370471
|
-
|
|
370472
|
-
|
|
370473
|
-
|
|
370474
|
-
|
|
370475
|
-
|
|
370476
|
-
|
|
370477
|
-
|
|
370478
|
-
|
|
370479
|
-
|
|
370480
|
-
|
|
370481
|
-
|
|
370482
|
-
|
|
370483
|
-
httpServer.on("
|
|
370484
|
-
httpsServer.
|
|
370485
|
-
|
|
370486
|
-
|
|
370487
|
-
|
|
370466
|
+
};
|
|
370467
|
+
const useStandardPorts = !preferredHttpsPort || preferredHttpsPort === HTTPS_PORT;
|
|
370468
|
+
if (useStandardPorts) {
|
|
370469
|
+
try {
|
|
370470
|
+
return await startStandardProxy();
|
|
370471
|
+
} catch (err) {
|
|
370472
|
+
const isPortError = err instanceof Error && (err.message.includes("already in use") || err.message.includes("Cannot bind to port"));
|
|
370473
|
+
if (!isPortError) throw err;
|
|
370474
|
+
writeLog("proxy", `Standard ports unavailable (${err instanceof Error ? err.message : err}), falling back to HTTPS-only`);
|
|
370475
|
+
}
|
|
370476
|
+
}
|
|
370477
|
+
const targetPort = preferredHttpsPort && preferredHttpsPort !== HTTPS_PORT ? preferredHttpsPort : FALLBACK_HTTPS_PORT;
|
|
370478
|
+
return startFallbackProxy(targetPort);
|
|
370479
|
+
function startStandardProxy() {
|
|
370480
|
+
const httpServer = http.createServer(handleRequest);
|
|
370481
|
+
httpServer.on("upgrade", handleUpgrade);
|
|
370482
|
+
const httpsServer = https.createServer(
|
|
370483
|
+
{ key: defaultKey, cert: defaultCert },
|
|
370484
|
+
handleRequest
|
|
370485
|
+
);
|
|
370486
|
+
httpsServer.on("upgrade", handleUpgrade);
|
|
370487
|
+
return new Promise((resolve52, reject) => {
|
|
370488
|
+
let httpStarted = false;
|
|
370489
|
+
let httpsStarted = false;
|
|
370490
|
+
let failed = false;
|
|
370491
|
+
const checkReady = () => {
|
|
370492
|
+
if (failed) return;
|
|
370493
|
+
if (httpStarted && httpsStarted) {
|
|
370494
|
+
writeLog("proxy", `HTTP/HTTPS proxy started on ports ${HTTP_PORT}/${HTTPS_PORT}`);
|
|
370495
|
+
resolve52(makeInstance(httpsServer, HTTPS_PORT, httpServer, HTTP_PORT));
|
|
370496
|
+
}
|
|
370497
|
+
};
|
|
370498
|
+
const handleError = (port) => (err) => {
|
|
370499
|
+
if (failed) return;
|
|
370500
|
+
failed = true;
|
|
370501
|
+
httpServer.close(() => {
|
|
370502
|
+
});
|
|
370503
|
+
httpsServer.close(() => {
|
|
370504
|
+
});
|
|
370505
|
+
if (err.code === "EACCES" || err.code === "EADDRINUSE") {
|
|
370506
|
+
reject(new Error(`Port ${port} is already in use`));
|
|
370507
|
+
} else {
|
|
370508
|
+
reject(err);
|
|
370509
|
+
}
|
|
370510
|
+
};
|
|
370511
|
+
httpServer.on("error", handleError(HTTP_PORT));
|
|
370512
|
+
httpsServer.on("error", handleError(HTTPS_PORT));
|
|
370513
|
+
httpServer.listen(HTTP_PORT, "0.0.0.0", () => {
|
|
370514
|
+
httpStarted = true;
|
|
370515
|
+
checkReady();
|
|
370516
|
+
});
|
|
370517
|
+
httpsServer.listen(HTTPS_PORT, "0.0.0.0", () => {
|
|
370518
|
+
httpsStarted = true;
|
|
370519
|
+
checkReady();
|
|
370520
|
+
});
|
|
370488
370521
|
});
|
|
370489
|
-
|
|
370490
|
-
|
|
370491
|
-
|
|
370522
|
+
}
|
|
370523
|
+
function startFallbackProxy(port) {
|
|
370524
|
+
const httpsServer = https.createServer(
|
|
370525
|
+
{ key: defaultKey, cert: defaultCert },
|
|
370526
|
+
handleRequest
|
|
370527
|
+
);
|
|
370528
|
+
httpsServer.on("upgrade", handleUpgrade);
|
|
370529
|
+
return new Promise((resolve52, reject) => {
|
|
370530
|
+
const tryPort = (p) => {
|
|
370531
|
+
httpsServer.removeAllListeners("error");
|
|
370532
|
+
httpsServer.on("error", (err) => {
|
|
370533
|
+
if ((err.code === "EADDRINUSE" || err.code === "EACCES") && p !== 0) {
|
|
370534
|
+
tryPort(0);
|
|
370535
|
+
} else {
|
|
370536
|
+
reject(err);
|
|
370537
|
+
}
|
|
370538
|
+
});
|
|
370539
|
+
httpsServer.listen(p, "0.0.0.0", () => {
|
|
370540
|
+
const addr = httpsServer.address();
|
|
370541
|
+
const actualPort = typeof addr === "object" && addr ? addr.port : p;
|
|
370542
|
+
writeLog("proxy", `HTTPS proxy started on port ${actualPort} (fallback mode)`);
|
|
370543
|
+
resolve52(makeInstance(httpsServer, actualPort));
|
|
370544
|
+
});
|
|
370545
|
+
};
|
|
370546
|
+
tryPort(port);
|
|
370492
370547
|
});
|
|
370493
|
-
}
|
|
370548
|
+
}
|
|
370494
370549
|
}
|
|
370495
370550
|
function extractServiceAndKey(host) {
|
|
370496
370551
|
const hostname2 = host.split(":")[0];
|
|
@@ -370866,7 +370921,7 @@ async function waitForTcpPort2(host, port, timeoutMs = 3e4) {
|
|
|
370866
370921
|
}
|
|
370867
370922
|
function checkTcpPort2(host, port) {
|
|
370868
370923
|
return new Promise((resolve52) => {
|
|
370869
|
-
const socket = new
|
|
370924
|
+
const socket = new net3.Socket();
|
|
370870
370925
|
socket.setTimeout(1e3);
|
|
370871
370926
|
socket.on("connect", () => {
|
|
370872
370927
|
socket.destroy();
|
|
@@ -371104,7 +371159,7 @@ async function waitForTcpPort3(host, port, timeoutMs = 3e4) {
|
|
|
371104
371159
|
}
|
|
371105
371160
|
function checkTcpPort3(host, port) {
|
|
371106
371161
|
return new Promise((resolve52) => {
|
|
371107
|
-
const socket = new
|
|
371162
|
+
const socket = new net4.Socket();
|
|
371108
371163
|
socket.setTimeout(1e3);
|
|
371109
371164
|
socket.on("connect", () => {
|
|
371110
371165
|
socket.destroy();
|
|
@@ -371498,7 +371553,7 @@ async function waitForTcpPort4(host, port, timeoutMs = 3e4) {
|
|
|
371498
371553
|
}
|
|
371499
371554
|
function checkTcpPort4(host, port) {
|
|
371500
371555
|
return new Promise((resolve52) => {
|
|
371501
|
-
const socket = new
|
|
371556
|
+
const socket = new net5.Socket();
|
|
371502
371557
|
socket.setTimeout(1e3);
|
|
371503
371558
|
socket.on("connect", () => {
|
|
371504
371559
|
socket.destroy();
|
|
@@ -372269,7 +372324,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
372269
372324
|
}
|
|
372270
372325
|
}
|
|
372271
372326
|
addPoolConnection() {
|
|
372272
|
-
const remote =
|
|
372327
|
+
const remote = net6.connect({ host: this.tunnelHost, port: this.info.port });
|
|
372273
372328
|
remote.setKeepAlive(true, 3e4);
|
|
372274
372329
|
this.pool.add(remote);
|
|
372275
372330
|
remote.once("data", (firstChunk) => {
|
|
@@ -372284,7 +372339,7 @@ var TunnelClientImpl = class extends EventEmitter2 {
|
|
|
372284
372339
|
remote.on("close", () => this.onIdleClose(remote, errored));
|
|
372285
372340
|
}
|
|
372286
372341
|
pipeToLocal(remote, firstChunk) {
|
|
372287
|
-
const local =
|
|
372342
|
+
const local = net6.connect({ host: "127.0.0.1", port: this.localPort }, () => {
|
|
372288
372343
|
local.write(firstChunk);
|
|
372289
372344
|
remote.pipe(local);
|
|
372290
372345
|
local.pipe(remote);
|
|
@@ -372375,7 +372430,7 @@ var ProxyRegistryManager = class {
|
|
|
372375
372430
|
*/
|
|
372376
372431
|
isProxyListening(port, timeoutMs = 1e3) {
|
|
372377
372432
|
return new Promise((resolve52) => {
|
|
372378
|
-
const socket = new
|
|
372433
|
+
const socket = new net7.Socket();
|
|
372379
372434
|
let resolved = false;
|
|
372380
372435
|
const cleanup = () => {
|
|
372381
372436
|
if (!resolved) {
|
|
@@ -372402,11 +372457,12 @@ var ProxyRegistryManager = class {
|
|
|
372402
372457
|
/**
|
|
372403
372458
|
* Check if the proxy owner is healthy (process running AND proxy listening).
|
|
372404
372459
|
*/
|
|
372405
|
-
async isProxyOwnerHealthy(
|
|
372406
|
-
if (!this.isProcessRunning(pid)) {
|
|
372460
|
+
async isProxyOwnerHealthy(owner) {
|
|
372461
|
+
if (!this.isProcessRunning(owner.pid)) {
|
|
372407
372462
|
return false;
|
|
372408
372463
|
}
|
|
372409
|
-
const
|
|
372464
|
+
const port = owner.httpsPort ?? 443;
|
|
372465
|
+
const isListening = await this.isProxyListening(port);
|
|
372410
372466
|
return isListening;
|
|
372411
372467
|
}
|
|
372412
372468
|
async acquireLock(timeoutMs = 5e3) {
|
|
@@ -372457,13 +372513,13 @@ var ProxyRegistryManager = class {
|
|
|
372457
372513
|
* Try to claim ownership of the proxy.
|
|
372458
372514
|
* Returns true if this process is now the owner.
|
|
372459
372515
|
*/
|
|
372460
|
-
async claimProxyOwnership(key) {
|
|
372516
|
+
async claimProxyOwnership(key, httpsPort) {
|
|
372461
372517
|
const releaseLock = await this.acquireLock();
|
|
372462
372518
|
try {
|
|
372463
372519
|
if (fs15.existsSync(this.ownerPath)) {
|
|
372464
372520
|
const content = fs15.readFileSync(this.ownerPath, "utf-8");
|
|
372465
372521
|
const ownerFile2 = JSON.parse(content);
|
|
372466
|
-
if (await this.isProxyOwnerHealthy(ownerFile2.owner
|
|
372522
|
+
if (await this.isProxyOwnerHealthy(ownerFile2.owner)) {
|
|
372467
372523
|
return false;
|
|
372468
372524
|
}
|
|
372469
372525
|
}
|
|
@@ -372472,7 +372528,8 @@ var ProxyRegistryManager = class {
|
|
|
372472
372528
|
owner: {
|
|
372473
372529
|
pid: process.pid,
|
|
372474
372530
|
key,
|
|
372475
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
372531
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
372532
|
+
httpsPort
|
|
372476
372533
|
}
|
|
372477
372534
|
};
|
|
372478
372535
|
this.writeFileAtomic(this.ownerPath, ownerFile);
|
|
@@ -372514,7 +372571,7 @@ var ProxyRegistryManager = class {
|
|
|
372514
372571
|
try {
|
|
372515
372572
|
const content = fs15.readFileSync(this.ownerPath, "utf-8");
|
|
372516
372573
|
const ownerFile = JSON.parse(content);
|
|
372517
|
-
if (!await this.isProxyOwnerHealthy(ownerFile.owner
|
|
372574
|
+
if (!await this.isProxyOwnerHealthy(ownerFile.owner)) {
|
|
372518
372575
|
return null;
|
|
372519
372576
|
}
|
|
372520
372577
|
return ownerFile.owner;
|
|
@@ -372530,6 +372587,20 @@ var ProxyRegistryManager = class {
|
|
|
372530
372587
|
isProxyOwner() {
|
|
372531
372588
|
return this.isOwner;
|
|
372532
372589
|
}
|
|
372590
|
+
/**
|
|
372591
|
+
* Get the HTTPS port used by the current proxy owner.
|
|
372592
|
+
* Returns 443 if unknown.
|
|
372593
|
+
*/
|
|
372594
|
+
getProxyHttpsPort() {
|
|
372595
|
+
try {
|
|
372596
|
+
if (!fs15.existsSync(this.ownerPath)) return 443;
|
|
372597
|
+
const content = fs15.readFileSync(this.ownerPath, "utf-8");
|
|
372598
|
+
const ownerFile = JSON.parse(content);
|
|
372599
|
+
return ownerFile.owner.httpsPort ?? 443;
|
|
372600
|
+
} catch {
|
|
372601
|
+
return 443;
|
|
372602
|
+
}
|
|
372603
|
+
}
|
|
372533
372604
|
/**
|
|
372534
372605
|
* Register services for a key.
|
|
372535
372606
|
*/
|
|
@@ -372649,13 +372720,13 @@ var ProxyRegistryManager = class {
|
|
|
372649
372720
|
* Attempt to become the proxy owner (election).
|
|
372650
372721
|
* This is called when the current owner is detected as dead.
|
|
372651
372722
|
*/
|
|
372652
|
-
async attemptElection(key) {
|
|
372723
|
+
async attemptElection(key, httpsPort) {
|
|
372653
372724
|
const releaseLock = await this.acquireLock();
|
|
372654
372725
|
try {
|
|
372655
372726
|
if (fs15.existsSync(this.ownerPath)) {
|
|
372656
372727
|
const content = fs15.readFileSync(this.ownerPath, "utf-8");
|
|
372657
372728
|
const ownerFile2 = JSON.parse(content);
|
|
372658
|
-
if (await this.isProxyOwnerHealthy(ownerFile2.owner
|
|
372729
|
+
if (await this.isProxyOwnerHealthy(ownerFile2.owner)) {
|
|
372659
372730
|
return false;
|
|
372660
372731
|
}
|
|
372661
372732
|
fs15.unlinkSync(this.ownerPath);
|
|
@@ -372665,7 +372736,8 @@ var ProxyRegistryManager = class {
|
|
|
372665
372736
|
owner: {
|
|
372666
372737
|
pid: process.pid,
|
|
372667
372738
|
key,
|
|
372668
|
-
startedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
372739
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
372740
|
+
httpsPort
|
|
372669
372741
|
}
|
|
372670
372742
|
};
|
|
372671
372743
|
this.writeFileAtomic(this.ownerPath, ownerFile);
|
|
@@ -373503,6 +373575,9 @@ Add them to the config block in specific.local`
|
|
|
373503
373575
|
}
|
|
373504
373576
|
}
|
|
373505
373577
|
}
|
|
373578
|
+
const existingOwner = await proxyRegistry.getProxyOwner();
|
|
373579
|
+
const expectedHttpsPort = existingOwner ? existingOwner.httpsPort ?? 443 : await probeHttpsPort();
|
|
373580
|
+
const portSuffix = expectedHttpsPort !== 443 && expectedHttpsPort !== 0 ? `:${expectedHttpsPort}` : "";
|
|
373506
373581
|
const publicUrls = /* @__PURE__ */ new Map();
|
|
373507
373582
|
let subdomainAllocator;
|
|
373508
373583
|
if (this.tunnelEnabled && exposedServices.length > 0) {
|
|
@@ -373521,7 +373596,7 @@ Add them to the config block in specific.local`
|
|
|
373521
373596
|
} else {
|
|
373522
373597
|
const keySuffix = this.instanceKey === "default" ? "" : `.${this.instanceKey}`;
|
|
373523
373598
|
for (const svc of exposedServices) {
|
|
373524
|
-
publicUrls.set(svc.name, `${svc.name}${keySuffix}.spcf.localhost`);
|
|
373599
|
+
publicUrls.set(svc.name, `${svc.name}${keySuffix}.spcf.localhost${portSuffix}`);
|
|
373525
373600
|
}
|
|
373526
373601
|
}
|
|
373527
373602
|
const runningServices = [];
|
|
@@ -373740,7 +373815,7 @@ Add them to the config block in specific.local`
|
|
|
373740
373815
|
this.emit("adminReady", `http://localhost:${adminServer.port}`);
|
|
373741
373816
|
} else {
|
|
373742
373817
|
const adminHost = this.instanceKey === "default" ? "" : `${this.instanceKey}.`;
|
|
373743
|
-
this.emit("adminReady", `https://${adminHost}spcf.localhost`);
|
|
373818
|
+
this.emit("adminReady", `https://${adminHost}spcf.localhost${portSuffix}`);
|
|
373744
373819
|
await proxyRegistry.registerServices(
|
|
373745
373820
|
this.instanceKey,
|
|
373746
373821
|
adminServer.port,
|
|
@@ -373752,7 +373827,8 @@ Add them to the config block in specific.local`
|
|
|
373752
373827
|
`Registered ${serviceInfos.length} services with proxy registry`
|
|
373753
373828
|
);
|
|
373754
373829
|
const becameProxyOwner = await proxyRegistry.claimProxyOwnership(
|
|
373755
|
-
this.instanceKey
|
|
373830
|
+
this.instanceKey,
|
|
373831
|
+
expectedHttpsPort
|
|
373756
373832
|
);
|
|
373757
373833
|
if (becameProxyOwner) {
|
|
373758
373834
|
this.systemLog(
|
|
@@ -373773,7 +373849,8 @@ Add them to the config block in specific.local`
|
|
|
373773
373849
|
exposedServices,
|
|
373774
373850
|
certificate,
|
|
373775
373851
|
getState,
|
|
373776
|
-
this.instanceKey
|
|
373852
|
+
this.instanceKey,
|
|
373853
|
+
expectedHttpsPort
|
|
373777
373854
|
);
|
|
373778
373855
|
this.proxy = proxy;
|
|
373779
373856
|
const knownKeys = new Set(registeredKeys);
|
|
@@ -373839,8 +373916,10 @@ Add them to the config block in specific.local`
|
|
|
373839
373916
|
this.systemLog(
|
|
373840
373917
|
"Proxy owner died, attempting election"
|
|
373841
373918
|
);
|
|
373919
|
+
const previousPort = proxyRegistry.getProxyHttpsPort();
|
|
373842
373920
|
const won = await proxyRegistry.attemptElection(
|
|
373843
|
-
this.instanceKey
|
|
373921
|
+
this.instanceKey,
|
|
373922
|
+
previousPort
|
|
373844
373923
|
);
|
|
373845
373924
|
if (won) {
|
|
373846
373925
|
this.systemLog(
|
|
@@ -373866,7 +373945,8 @@ Add them to the config block in specific.local`
|
|
|
373866
373945
|
exposedServices,
|
|
373867
373946
|
certificate,
|
|
373868
373947
|
getState,
|
|
373869
|
-
this.instanceKey
|
|
373948
|
+
this.instanceKey,
|
|
373949
|
+
previousPort
|
|
373870
373950
|
);
|
|
373871
373951
|
this.proxy = proxy;
|
|
373872
373952
|
this.registryWatcherCleanup = proxyRegistry.watchRegistry(
|
|
@@ -374383,7 +374463,7 @@ function trackEvent(event, properties) {
|
|
|
374383
374463
|
event,
|
|
374384
374464
|
properties: {
|
|
374385
374465
|
...properties,
|
|
374386
|
-
cli_version: "0.1.
|
|
374466
|
+
cli_version: "0.1.89",
|
|
374387
374467
|
platform: process.platform,
|
|
374388
374468
|
node_version: process.version,
|
|
374389
374469
|
project_id: getProjectId()
|
|
@@ -376154,6 +376234,15 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
376154
376234
|
return /* @__PURE__ */ React6.createElement(Text6, { key: svc.name }, /* @__PURE__ */ React6.createElement(Text6, { color: isReady ? "green" : "gray" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, svc.name, portInfo));
|
|
376155
376235
|
}), /* @__PURE__ */ React6.createElement(Text6, null, " ")), /* @__PURE__ */ React6.createElement(Box6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "blue" }, /* @__PURE__ */ React6.createElement(Spinner4, { type: "dots" })), /* @__PURE__ */ React6.createElement(Text6, null, " Starting...")));
|
|
376156
376236
|
}
|
|
376237
|
+
const portSuffix = (() => {
|
|
376238
|
+
if (!state.adminUrl || !state.adminUrl.startsWith("https://")) return "";
|
|
376239
|
+
try {
|
|
376240
|
+
const p = new URL(state.adminUrl).port;
|
|
376241
|
+
return p ? `:${p}` : "";
|
|
376242
|
+
} catch {
|
|
376243
|
+
return "";
|
|
376244
|
+
}
|
|
376245
|
+
})();
|
|
376157
376246
|
const staticItems = [
|
|
376158
376247
|
{
|
|
376159
376248
|
key: "title",
|
|
@@ -376202,7 +376291,7 @@ function DevUI({ instanceKey, tunnelEnabled }) {
|
|
|
376202
376291
|
const proxyName = endpoint.name === "default" ? svc.name : `${svc.name}-${endpoint.name}`;
|
|
376203
376292
|
return {
|
|
376204
376293
|
key: `svc-${svc.name}-${endpoint.name}`,
|
|
376205
|
-
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, displayName), port ? endpoint.public ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", proxyName, instanceKey === "default" ? "" : `.${instanceKey}`, ".spcf.localhost"), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")")) : /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")") : null)
|
|
376294
|
+
content: /* @__PURE__ */ React6.createElement(Text6, null, /* @__PURE__ */ React6.createElement(Text6, { color: "green" }, " \u25CF "), /* @__PURE__ */ React6.createElement(Text6, null, displayName), port ? endpoint.public ? /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, null, " \u2192 "), /* @__PURE__ */ React6.createElement(Text6, { bold: true }, "https://", proxyName, instanceKey === "default" ? "" : `.${instanceKey}`, ".spcf.localhost", portSuffix), /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")")) : /* @__PURE__ */ React6.createElement(Text6, { dimColor: true }, " (localhost:", port, ")") : null)
|
|
376206
376295
|
};
|
|
376207
376296
|
});
|
|
376208
376297
|
}),
|
|
@@ -377998,7 +378087,7 @@ function compareVersions(a, b) {
|
|
|
377998
378087
|
return 0;
|
|
377999
378088
|
}
|
|
378000
378089
|
async function checkForUpdate() {
|
|
378001
|
-
const currentVersion = "0.1.
|
|
378090
|
+
const currentVersion = "0.1.89";
|
|
378002
378091
|
const response = await fetch(`${BINARIES_BASE_URL}/latest?t=${Date.now()}`);
|
|
378003
378092
|
if (!response.ok) {
|
|
378004
378093
|
throw new Error(`Failed to check for updates: HTTP ${response.status}`);
|
|
@@ -378197,7 +378286,7 @@ function updateCommand() {
|
|
|
378197
378286
|
var program = new Command();
|
|
378198
378287
|
var env = "production";
|
|
378199
378288
|
var envLabel = env !== "production" ? `[${env.toUpperCase()}] ` : "";
|
|
378200
|
-
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.
|
|
378289
|
+
program.name("specific").description(`${envLabel}Infrastructure-as-code for coding agents`).version("0.1.89").enablePositionalOptions();
|
|
378201
378290
|
program.command("init").description("Initialize project for use with a coding agent").option("--agent <name...>", "Agents to configure (cursor, claude, codex, other)").action((options2) => initCommand(options2));
|
|
378202
378291
|
program.command("docs [topic]").description("Fetch LLM-optimized documentation").action(docsCommand);
|
|
378203
378292
|
program.command("check").description("Validate specific.hcl configuration").action(checkCommand);
|
package/dist/postinstall.js
CHANGED
|
@@ -182883,7 +182883,7 @@ function trackEvent(event, properties) {
|
|
|
182883
182883
|
event,
|
|
182884
182884
|
properties: {
|
|
182885
182885
|
...properties,
|
|
182886
|
-
cli_version: "0.1.
|
|
182886
|
+
cli_version: "0.1.89",
|
|
182887
182887
|
platform: process.platform,
|
|
182888
182888
|
node_version: process.version,
|
|
182889
182889
|
project_id: getProjectId()
|
package/package.json
CHANGED
/package/dist/admin/_next/static/{gTSwsUHBTwlXnncoAFB77 → QGNtzZ5y-zIMtO9d5ZuTF}/_buildManifest.js
RENAMED
|
File without changes
|
|
File without changes
|
/package/dist/admin/_next/static/{gTSwsUHBTwlXnncoAFB77 → QGNtzZ5y-zIMtO9d5ZuTF}/_ssgManifest.js
RENAMED
|
File without changes
|