openship 0.2.3 → 0.3.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.js +47 -15
- package/dist/server/index.js +292 -73
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1216,7 +1216,13 @@ function findClosingBracket(body, start) {
|
|
|
1216
1216
|
const ch = body[i];
|
|
1217
1217
|
const prev = body[i - 1];
|
|
1218
1218
|
if (inDouble) {
|
|
1219
|
-
if (ch === '"'
|
|
1219
|
+
if (ch === '"') {
|
|
1220
|
+
let backslashRun = 0;
|
|
1221
|
+
for (let j = i - 1; j >= 0 && body[j] === "\\"; j--) {
|
|
1222
|
+
backslashRun++;
|
|
1223
|
+
}
|
|
1224
|
+
if (backslashRun % 2 === 0) inDouble = false;
|
|
1225
|
+
}
|
|
1220
1226
|
continue;
|
|
1221
1227
|
}
|
|
1222
1228
|
if (inSingle) {
|
|
@@ -3840,7 +3846,7 @@ async function runForeground(opts, source) {
|
|
|
3840
3846
|
const uiSpinner = ora("Preparing the dashboard\u2026").start();
|
|
3841
3847
|
try {
|
|
3842
3848
|
const bundle = await ensureDashboard({
|
|
3843
|
-
tag: source ? "local" : opts.uiVersion || `v${"0.
|
|
3849
|
+
tag: source ? "local" : opts.uiVersion || `v${"0.3.0"}`,
|
|
3844
3850
|
onProgress: (received, total) => {
|
|
3845
3851
|
if (total) {
|
|
3846
3852
|
uiSpinner.text = `Downloading dashboard\u2026 ${Math.round(received / total * 100)}%`;
|
|
@@ -7520,7 +7526,9 @@ function assetForPlatform() {
|
|
|
7520
7526
|
return { name: arch === "arm64" ? "Openship-arm64.dmg" : "Openship-x64.dmg", kind: "dmg" };
|
|
7521
7527
|
}
|
|
7522
7528
|
if (platform === "win32") return { name: "Openship-win32-x64.zip", kind: "zip" };
|
|
7523
|
-
if (platform === "linux")
|
|
7529
|
+
if (platform === "linux") {
|
|
7530
|
+
return { name: arch === "arm64" ? "Openship-arm64.AppImage" : "Openship.AppImage", kind: "appimage" };
|
|
7531
|
+
}
|
|
7524
7532
|
throw new Error(`Unsupported platform: ${platform} (${arch})`);
|
|
7525
7533
|
}
|
|
7526
7534
|
function installDmg(dmg) {
|
|
@@ -7715,7 +7723,7 @@ function detectPackageManager2(override) {
|
|
|
7715
7723
|
return hasBun ? "bun" : "npm";
|
|
7716
7724
|
}
|
|
7717
7725
|
var updateCommand = new Command25("update").description("Update the Openship CLI + bundled server to the latest release").option("--check", "Only report the current + latest version; don't install").option("--via <manager>", "Package manager to update with: bun | npm").action(async (opts) => {
|
|
7718
|
-
const current = "0.
|
|
7726
|
+
const current = "0.3.0";
|
|
7719
7727
|
let latest;
|
|
7720
7728
|
try {
|
|
7721
7729
|
latest = (await resolveLatestTag()).replace(/^v/, "");
|
|
@@ -7743,7 +7751,7 @@ var updateCommand = new Command25("update").description("Update the Openship CLI
|
|
|
7743
7751
|
const ref = `openship@${latest}`;
|
|
7744
7752
|
const argv = pm === "bun" ? ["add", "-g", ref] : ["install", "-g", ref];
|
|
7745
7753
|
info(`Updating v${current} \u2192 v${latest} (${cliInstallCommand(pm, latest)})...`);
|
|
7746
|
-
const res = spawnSync6(pm, argv, { stdio: "inherit" });
|
|
7754
|
+
const res = spawnSync6(pm, argv, { stdio: "inherit", shell: process.platform === "win32" });
|
|
7747
7755
|
if (res.status !== 0) {
|
|
7748
7756
|
err(`Update failed (${pm} exited ${res.status ?? "with a signal"}). Reinstall manually: ${cliInstallCommand(pm, latest)}`);
|
|
7749
7757
|
process.exitCode = 1;
|
|
@@ -8025,12 +8033,13 @@ async function promptLocalAdmin() {
|
|
|
8025
8033
|
}
|
|
8026
8034
|
async function streamProvision(port, sessionId, s) {
|
|
8027
8035
|
let ok3 = false;
|
|
8036
|
+
let detail;
|
|
8028
8037
|
try {
|
|
8029
8038
|
const res = await fetch(`http://127.0.0.1:${port}/api/system/self-register/stream?id=${sessionId}`, {
|
|
8030
8039
|
headers: { "X-Internal-Token": ensureInternalToken() },
|
|
8031
8040
|
signal: AbortSignal.timeout(3e5)
|
|
8032
8041
|
});
|
|
8033
|
-
if (!res.ok || !res.body) return false;
|
|
8042
|
+
if (!res.ok || !res.body) return { ok: false };
|
|
8034
8043
|
const reader = res.body.getReader();
|
|
8035
8044
|
const decoder = new TextDecoder();
|
|
8036
8045
|
let buffer = "";
|
|
@@ -8048,23 +8057,29 @@ async function streamProvision(port, sessionId, s) {
|
|
|
8048
8057
|
if (event === "log" && dataRaw) {
|
|
8049
8058
|
try {
|
|
8050
8059
|
const d = JSON.parse(dataRaw);
|
|
8051
|
-
if (d.message)
|
|
8060
|
+
if (d.message) {
|
|
8061
|
+
const msg = String(d.message).replace(/\s+/g, " ");
|
|
8062
|
+
s.message(msg.slice(0, 68));
|
|
8063
|
+
if (d.level === "warn" || d.level === "error") detail = msg;
|
|
8064
|
+
}
|
|
8052
8065
|
} catch {
|
|
8053
8066
|
}
|
|
8054
8067
|
} else if (event === "complete" && dataRaw) {
|
|
8055
8068
|
try {
|
|
8056
|
-
|
|
8069
|
+
const d = JSON.parse(dataRaw);
|
|
8070
|
+
ok3 = d.status === "completed";
|
|
8071
|
+
if (!ok3 && typeof d.error === "string") detail = d.error;
|
|
8057
8072
|
} catch {
|
|
8058
8073
|
}
|
|
8059
8074
|
} else if (event === "end") {
|
|
8060
|
-
return ok3;
|
|
8075
|
+
return { ok: ok3, detail };
|
|
8061
8076
|
}
|
|
8062
8077
|
}
|
|
8063
8078
|
}
|
|
8064
8079
|
} catch {
|
|
8065
|
-
return ok3;
|
|
8080
|
+
return { ok: ok3, detail };
|
|
8066
8081
|
}
|
|
8067
|
-
return ok3;
|
|
8082
|
+
return { ok: ok3, detail };
|
|
8068
8083
|
}
|
|
8069
8084
|
async function runWizard() {
|
|
8070
8085
|
intro2(`${chalk17.bgCyan(chalk17.black(" Openship "))}${chalk17.dim(" setup")}`);
|
|
@@ -8269,7 +8284,7 @@ async function runWizard() {
|
|
|
8269
8284
|
domainPlan = { type: "byo", hostname };
|
|
8270
8285
|
break planning;
|
|
8271
8286
|
}
|
|
8272
|
-
const uiTag = `v${"0.
|
|
8287
|
+
const uiTag = `v${"0.3.0"}`;
|
|
8273
8288
|
const dl = spinner2();
|
|
8274
8289
|
dl.start("Pulling the Openship dist from GitHub");
|
|
8275
8290
|
try {
|
|
@@ -8388,6 +8403,20 @@ async function runWizard() {
|
|
|
8388
8403
|
if (status && !status.canProceedClean && status.occupants?.length) {
|
|
8389
8404
|
const owner = status.occupants.map((o) => o.command ?? `port ${o.port}`).join(", ");
|
|
8390
8405
|
const known = status.classification === "known";
|
|
8406
|
+
const sites = pf.ok && Array.isArray(pf.data?.sites) ? pf.data.sites : [];
|
|
8407
|
+
if (sites.length > 0) {
|
|
8408
|
+
const lines = sites.map((st) => {
|
|
8409
|
+
const host = (st.serverNames ?? []).join(", ") || "(no server_name)";
|
|
8410
|
+
const dest = st.target?.kind === "static" ? `static: ${st.target?.root ?? ""}` : st.target?.url ?? "";
|
|
8411
|
+
return `${chalk17.bold(host)} \u2192 ${chalk17.dim(dest)}${st.ssl ? chalk17.green(" [TLS]") : ""}`;
|
|
8412
|
+
});
|
|
8413
|
+
note(lines.join("\n"), `Detected ${sites.length} site${sites.length === 1 ? "" : "s"} on ${owner}`);
|
|
8414
|
+
}
|
|
8415
|
+
const warns = pf.ok && Array.isArray(pf.data?.warnings) ? pf.data.warnings : [];
|
|
8416
|
+
if (warns.length > 0) {
|
|
8417
|
+
log2.warn(`${warns.length} config item${warns.length === 1 ? "" : "s"} won't migrate automatically:`);
|
|
8418
|
+
for (const w of warns.slice(0, 8)) log2.message(chalk17.dim(`\u2022 ${w}`));
|
|
8419
|
+
}
|
|
8391
8420
|
const choice = ensure(
|
|
8392
8421
|
await select({
|
|
8393
8422
|
message: known ? `An existing reverse proxy (${owner}) is serving ports 80/443.` : `Ports 80/443 are in use by ${owner}, which we couldn't identify.`,
|
|
@@ -8434,10 +8463,13 @@ async function runWizard() {
|
|
|
8434
8463
|
if (res.ok && res.data?.sessionId) {
|
|
8435
8464
|
const s2 = spinner2();
|
|
8436
8465
|
s2.start("Issuing HTTPS certificate (OpenResty + Let's Encrypt)");
|
|
8437
|
-
const done = await streamProvision(port, res.data.sessionId, s2);
|
|
8466
|
+
const { ok: done, detail } = await streamProvision(port, res.data.sessionId, s2);
|
|
8438
8467
|
liveUrl = res.data.url ?? liveUrl;
|
|
8439
8468
|
if (done) s2.stop(`HTTPS ready: ${liveUrl}`);
|
|
8440
|
-
else
|
|
8469
|
+
else {
|
|
8470
|
+
s2.stop("HTTPS isn't ready yet \u2014 it retries on reboot; the site serves over HTTP meanwhile.", 1);
|
|
8471
|
+
if (detail) log2.warn(detail);
|
|
8472
|
+
}
|
|
8441
8473
|
} else {
|
|
8442
8474
|
log2.warn(`Couldn't start domain provisioning: ${res.data?.error || "failed"}`);
|
|
8443
8475
|
}
|
|
@@ -8545,7 +8577,7 @@ ${chalk17.dim("Dashboard".padEnd(11))}${dashUrl}
|
|
|
8545
8577
|
|
|
8546
8578
|
// src/index.ts
|
|
8547
8579
|
var program = new Command27();
|
|
8548
|
-
program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.
|
|
8580
|
+
program.name("openship").description("Openship CLI \u2014 install, run, and manage Openship from your terminal").version("0.3.0").option("--json", "Machine-readable JSON output (stdout data only)").hook("preAction", (thisCommand) => {
|
|
8549
8581
|
if (thisCommand.opts().json) setJsonMode(true);
|
|
8550
8582
|
}).action(async () => {
|
|
8551
8583
|
if (serviceStatus().installed) await runControl();
|
package/dist/server/index.js
CHANGED
|
@@ -4,43 +4,25 @@ var __getProtoOf = Object.getPrototypeOf;
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
6
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
function __accessProp(key) {
|
|
8
|
-
return this[key];
|
|
9
|
-
}
|
|
10
|
-
var __toESMCache_node;
|
|
11
|
-
var __toESMCache_esm;
|
|
12
7
|
var __toESM = (mod, isNodeMode, target) => {
|
|
13
|
-
var canCache = mod != null && typeof mod === "object";
|
|
14
|
-
if (canCache) {
|
|
15
|
-
var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
|
|
16
|
-
var cached = cache.get(mod);
|
|
17
|
-
if (cached)
|
|
18
|
-
return cached;
|
|
19
|
-
}
|
|
20
8
|
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
21
9
|
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
22
10
|
for (let key of __getOwnPropNames(mod))
|
|
23
11
|
if (!__hasOwnProp.call(to, key))
|
|
24
12
|
__defProp(to, key, {
|
|
25
|
-
get:
|
|
13
|
+
get: () => mod[key],
|
|
26
14
|
enumerable: true
|
|
27
15
|
});
|
|
28
|
-
if (canCache)
|
|
29
|
-
cache.set(mod, to);
|
|
30
16
|
return to;
|
|
31
17
|
};
|
|
32
18
|
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
|
|
33
|
-
var __returnValue = (v) => v;
|
|
34
|
-
function __exportSetter(name2, newValue) {
|
|
35
|
-
this[name2] = __returnValue.bind(null, newValue);
|
|
36
|
-
}
|
|
37
19
|
var __export = (target, all) => {
|
|
38
20
|
for (var name2 in all)
|
|
39
21
|
__defProp(target, name2, {
|
|
40
22
|
get: all[name2],
|
|
41
23
|
enumerable: true,
|
|
42
24
|
configurable: true,
|
|
43
|
-
set:
|
|
25
|
+
set: (newValue) => all[name2] = () => newValue
|
|
44
26
|
});
|
|
45
27
|
};
|
|
46
28
|
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
@@ -1166,7 +1148,7 @@ function bytesToBase64Url(bytes) {
|
|
|
1166
1148
|
return b64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
1167
1149
|
}
|
|
1168
1150
|
function slugify(text) {
|
|
1169
|
-
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").replace(/^-+|-+$/g, "")
|
|
1151
|
+
return text.toLowerCase().replace(/[^\w\s-]/g, "").replace(/[\s_]+/g, "-").slice(0, 100).replace(/^-+|-+$/g, "");
|
|
1170
1152
|
}
|
|
1171
1153
|
function normalizeCustomHostname(raw) {
|
|
1172
1154
|
return raw.trim().toLowerCase().replace(/^https?:\/\//, "").replace(/\/+$/, "");
|
|
@@ -1194,11 +1176,11 @@ function generateId(prefix) {
|
|
|
1194
1176
|
return prefix ? `${prefix}_${id}` : id;
|
|
1195
1177
|
}
|
|
1196
1178
|
function formatBytes(bytes, decimals = 2) {
|
|
1197
|
-
if (bytes
|
|
1179
|
+
if (bytes <= 0)
|
|
1198
1180
|
return "0 B";
|
|
1199
1181
|
const k = 1024;
|
|
1200
1182
|
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
1201
|
-
const i2 = Math.floor(Math.log(bytes) / Math.log(k));
|
|
1183
|
+
const i2 = Math.min(Math.max(Math.floor(Math.log(bytes) / Math.log(k)), 0), sizes.length - 1);
|
|
1202
1184
|
return `${parseFloat((bytes / Math.pow(k, i2)).toFixed(decimals))} ${sizes[i2]}`;
|
|
1203
1185
|
}
|
|
1204
1186
|
|
|
@@ -1408,8 +1390,14 @@ function findClosingBracket(body2, start2) {
|
|
|
1408
1390
|
const ch = body2[i2];
|
|
1409
1391
|
const prev = body2[i2 - 1];
|
|
1410
1392
|
if (inDouble) {
|
|
1411
|
-
if (ch === '"'
|
|
1412
|
-
|
|
1393
|
+
if (ch === '"') {
|
|
1394
|
+
let backslashRun = 0;
|
|
1395
|
+
for (let j = i2 - 1;j >= 0 && body2[j] === "\\"; j--) {
|
|
1396
|
+
backslashRun++;
|
|
1397
|
+
}
|
|
1398
|
+
if (backslashRun % 2 === 0)
|
|
1399
|
+
inDouble = false;
|
|
1400
|
+
}
|
|
1413
1401
|
continue;
|
|
1414
1402
|
}
|
|
1415
1403
|
if (inSingle) {
|
|
@@ -12421,15 +12409,17 @@ function certbotInstallPlan(profile) {
|
|
|
12421
12409
|
var OPENRESTY_APT_SOURCES, systemCatalog;
|
|
12422
12410
|
var init_catalog2 = __esm(() => {
|
|
12423
12411
|
OPENRESTY_APT_SOURCES = [
|
|
12412
|
+
'OR_ARCH="$(dpkg --print-architecture 2>/dev/null || echo amd64)"',
|
|
12413
|
+
'if [ "$OR_ARCH" = arm64 ]; then OR_BASE="http://openresty.org/package/arm64/$REPO"; else OR_BASE="http://openresty.org/package/$REPO"; fi',
|
|
12424
12414
|
'REPO_CODENAME="$(lsb_release -sc 2>/dev/null || { . /etc/os-release 2>/dev/null && echo "$VERSION_CODENAME"; })" || REPO_CODENAME=""',
|
|
12425
12415
|
'if [ "$REPO" = debian ]; then OR_FALLBACKS="bookworm bullseye"; else OR_FALLBACKS="noble jammy focal"; fi',
|
|
12426
12416
|
'OR_CODENAME=""',
|
|
12427
12417
|
"for c in $REPO_CODENAME $OR_FALLBACKS; do",
|
|
12428
|
-
' if wget -q --spider --tries=2 --timeout=15 "
|
|
12418
|
+
' if wget -q --spider --tries=2 --timeout=15 "$OR_BASE/dists/$c/Release"; then OR_CODENAME="$c"; break; fi',
|
|
12429
12419
|
"done",
|
|
12430
12420
|
'if [ -z "$OR_CODENAME" ]; then case "$REPO" in debian) OR_CODENAME=bookworm ;; *) OR_CODENAME=noble ;; esac; fi',
|
|
12431
12421
|
'[ "$OR_CODENAME" = "$REPO_CODENAME" ] || echo "[openresty] apt repo has no codename $REPO_CODENAME; using nearest supported LTS $OR_CODENAME" >&2',
|
|
12432
|
-
'echo "deb [signed-by=/usr/share/keyrings/openresty.gpg]
|
|
12422
|
+
'echo "deb [arch=$OR_ARCH signed-by=/usr/share/keyrings/openresty.gpg] $OR_BASE $OR_CODENAME main" > /etc/apt/sources.list.d/openresty.list'
|
|
12433
12423
|
];
|
|
12434
12424
|
systemCatalog = {
|
|
12435
12425
|
checks: {
|
|
@@ -13509,7 +13499,12 @@ async function ensureEdgeClear(executor, config, onLog) {
|
|
|
13509
13499
|
scan = await scanImportableSites(executor, proxy2);
|
|
13510
13500
|
}
|
|
13511
13501
|
const migratable = scan && scan.sites.length > 0;
|
|
13512
|
-
const message = migratable ? `Openship
|
|
13502
|
+
const message = migratable ? `Openship runs its own load balancer (OpenResty) on ports 80 and 443, but ${owner} is ` + `already serving them (${scan.sites.length} site${scan.sites.length === 1 ? "" : "s"}). ` + `Migrate those sites into Openship and take over, just stop it and take over, or cancel?` : known ? `Openship runs its own load balancer (OpenResty) on ports 80 and 443, but ${owner} is ` + `already serving them. Stop it and take over, or cancel and leave it running?` : `Openship runs its own load balancer (OpenResty) on ports 80 and 443, but ${owner} is ` + `already using them and we can't identify it. Stop it and take over, or cancel and leave it running?`;
|
|
13503
|
+
const details = {
|
|
13504
|
+
edge: status,
|
|
13505
|
+
sites: scan?.sites ?? [],
|
|
13506
|
+
warnings: scan?.warnings ?? []
|
|
13507
|
+
};
|
|
13513
13508
|
const action = await config.promptUser({
|
|
13514
13509
|
promptId: "edge_conflict",
|
|
13515
13510
|
title: known ? "Existing reverse proxy detected" : "Ports 80/443 are in use",
|
|
@@ -13519,7 +13514,7 @@ async function ensureEdgeClear(executor, config, onLog) {
|
|
|
13519
13514
|
{ id: "override", label: "Stop it & take over", variant: "danger" },
|
|
13520
13515
|
{ id: "cancel", label: "Cancel", variant: "secondary" }
|
|
13521
13516
|
],
|
|
13522
|
-
details
|
|
13517
|
+
details
|
|
13523
13518
|
});
|
|
13524
13519
|
if (action === "migrate" && scan) {
|
|
13525
13520
|
throw new EdgeMigrateRequested(status, scan.sites, scan.warnings);
|
|
@@ -29125,7 +29120,7 @@ var require_serde = __commonJS((exports) => {
|
|
|
29125
29120
|
}
|
|
29126
29121
|
return value.slice(idx);
|
|
29127
29122
|
};
|
|
29128
|
-
var LazyJsonString = function
|
|
29123
|
+
var LazyJsonString = function LazyJsonString(val) {
|
|
29129
29124
|
const str = Object.assign(new String(val), {
|
|
29130
29125
|
deserializeJSON() {
|
|
29131
29126
|
return JSON.parse(String(val));
|
|
@@ -34442,7 +34437,7 @@ var require_dist_cjs5 = __commonJS((exports) => {
|
|
|
34442
34437
|
return httpRequest;
|
|
34443
34438
|
}
|
|
34444
34439
|
}
|
|
34445
|
-
var createIsIdentityExpiredFunction = (expirationMs) => function
|
|
34440
|
+
var createIsIdentityExpiredFunction = (expirationMs) => function isIdentityExpired(identity2) {
|
|
34446
34441
|
return doesIdentityRequireRefresh(identity2) && identity2.expiration.getTime() - Date.now() < expirationMs;
|
|
34447
34442
|
};
|
|
34448
34443
|
var EXPIRATION_MS = 300000;
|
|
@@ -57255,7 +57250,7 @@ var require_checksum = __commonJS((exports) => {
|
|
|
57255
57250
|
totalBytesRead += slice.size;
|
|
57256
57251
|
}
|
|
57257
57252
|
}
|
|
57258
|
-
var blobHasher = async function
|
|
57253
|
+
var blobHasher = async function blobHasher(hashCtor, blob) {
|
|
57259
57254
|
const hash = new hashCtor;
|
|
57260
57255
|
await blobReader(blob, (chunk) => {
|
|
57261
57256
|
hash.update(chunk);
|
|
@@ -80888,7 +80883,7 @@ var require_lib = __commonJS((exports, module2) => {
|
|
|
80888
80883
|
3793,
|
|
80889
80884
|
7920
|
|
80890
80885
|
];
|
|
80891
|
-
var toUTF8Array = function
|
|
80886
|
+
var toUTF8Array = function toUTF8Array(str) {
|
|
80892
80887
|
var char;
|
|
80893
80888
|
var i2 = 0;
|
|
80894
80889
|
var p = 0;
|
|
@@ -80915,7 +80910,7 @@ var require_lib = __commonJS((exports, module2) => {
|
|
|
80915
80910
|
}
|
|
80916
80911
|
return utf8;
|
|
80917
80912
|
};
|
|
80918
|
-
var generate = module2.exports = function
|
|
80913
|
+
var generate = module2.exports = function generate(str) {
|
|
80919
80914
|
var char;
|
|
80920
80915
|
var i2 = 0;
|
|
80921
80916
|
var start2 = -1;
|
|
@@ -140159,6 +140154,9 @@ var init_infer_result = () => {};
|
|
|
140159
140154
|
|
|
140160
140155
|
// ../../node_modules/kysely/dist/esm/index.js
|
|
140161
140156
|
var init_esm = __esm(() => {
|
|
140157
|
+
init_expression_builder();
|
|
140158
|
+
init_log_once();
|
|
140159
|
+
init_query_id();
|
|
140162
140160
|
init_kysely();
|
|
140163
140161
|
init_query_creator();
|
|
140164
140162
|
init_expression();
|
|
@@ -172653,8 +172651,9 @@ function createProjectRepo(db5) {
|
|
|
172653
172651
|
};
|
|
172654
172652
|
},
|
|
172655
172653
|
async create(data) {
|
|
172656
|
-
const
|
|
172657
|
-
const
|
|
172654
|
+
const { id: providedId, ...rest } = data;
|
|
172655
|
+
const id2 = providedId ?? generateId("proj");
|
|
172656
|
+
const row = { id: id2, ...rest };
|
|
172658
172657
|
await db5.insert(project).values(row);
|
|
172659
172658
|
return { ...row, createdAt: new Date, updatedAt: new Date };
|
|
172660
172659
|
},
|
|
@@ -210866,7 +210865,7 @@ var require_node2 = __commonJS((exports) => {
|
|
|
210866
210865
|
readString16 = readString2(3);
|
|
210867
210866
|
readString32 = readString2(5);
|
|
210868
210867
|
function readString2(headerLength) {
|
|
210869
|
-
return function
|
|
210868
|
+
return function readString(length) {
|
|
210870
210869
|
let string10 = strings[stringPosition++];
|
|
210871
210870
|
if (string10 == null) {
|
|
210872
210871
|
if (bundledStrings$1)
|
|
@@ -230130,12 +230129,12 @@ var require_expression = __commonJS((exports, module2) => {
|
|
|
230130
230129
|
}
|
|
230131
230130
|
return resultArr.join(" ");
|
|
230132
230131
|
};
|
|
230133
|
-
CronExpression.parse = function
|
|
230132
|
+
CronExpression.parse = function parse(expression2, options) {
|
|
230134
230133
|
var self2 = this;
|
|
230135
230134
|
if (typeof options === "function") {
|
|
230136
230135
|
options = {};
|
|
230137
230136
|
}
|
|
230138
|
-
function
|
|
230137
|
+
function parse17(expression3, options2) {
|
|
230139
230138
|
if (!options2) {
|
|
230140
230139
|
options2 = {};
|
|
230141
230140
|
}
|
|
@@ -230191,7 +230190,7 @@ var require_expression = __commonJS((exports, module2) => {
|
|
|
230191
230190
|
return val2;
|
|
230192
230191
|
}
|
|
230193
230192
|
}
|
|
230194
|
-
return
|
|
230193
|
+
return parse17(expression2, options);
|
|
230195
230194
|
};
|
|
230196
230195
|
CronExpression.fieldsToExpression = function fieldsToExpression(fields, options) {
|
|
230197
230196
|
function validateConstraints(field2, values2, constraints) {
|
|
@@ -230255,13 +230254,13 @@ var require_parser3 = __commonJS((exports, module2) => {
|
|
|
230255
230254
|
throw new Error("Invalid entry: " + entry);
|
|
230256
230255
|
}
|
|
230257
230256
|
};
|
|
230258
|
-
CronParser.parseExpression = function
|
|
230257
|
+
CronParser.parseExpression = function parseExpression(expression2, options) {
|
|
230259
230258
|
return CronExpression.parse(expression2, options);
|
|
230260
230259
|
};
|
|
230261
230260
|
CronParser.fieldsToExpression = function fieldsToExpression(fields, options) {
|
|
230262
230261
|
return CronExpression.fieldsToExpression(fields, options);
|
|
230263
230262
|
};
|
|
230264
|
-
CronParser.parseString = function
|
|
230263
|
+
CronParser.parseString = function parseString(data) {
|
|
230265
230264
|
var blocks = data.split(`
|
|
230266
230265
|
`);
|
|
230267
230266
|
var response = {
|
|
@@ -231852,7 +231851,7 @@ var require_sandbox = __commonJS((exports) => {
|
|
|
231852
231851
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
231853
231852
|
var enums_1 = require_enums();
|
|
231854
231853
|
var sandbox = (processFile, childPool) => {
|
|
231855
|
-
return async function
|
|
231854
|
+
return async function process(job2, token, signal) {
|
|
231856
231855
|
let child;
|
|
231857
231856
|
let msgHandler;
|
|
231858
231857
|
let exitHandler;
|
|
@@ -239477,6 +239476,48 @@ async function createProductionProject(data, slug, organizationId) {
|
|
|
239477
239476
|
throw err2;
|
|
239478
239477
|
}
|
|
239479
239478
|
}
|
|
239479
|
+
async function createServicesProjectWithId(opts) {
|
|
239480
|
+
await assertProjectQuota(opts.organizationId);
|
|
239481
|
+
const slug = await uniqueProjectSlug(opts.organizationId, opts.slug);
|
|
239482
|
+
const group = await repos.projectGroup.create({
|
|
239483
|
+
organizationId: opts.organizationId,
|
|
239484
|
+
name: opts.name,
|
|
239485
|
+
slug,
|
|
239486
|
+
gitProvider: opts.gitProvider ?? undefined,
|
|
239487
|
+
gitOwner: opts.gitOwner ?? undefined,
|
|
239488
|
+
gitRepo: opts.gitRepo ?? undefined,
|
|
239489
|
+
gitUrl: projectGitUrl(opts.gitOwner, opts.gitRepo)
|
|
239490
|
+
});
|
|
239491
|
+
try {
|
|
239492
|
+
const routing2 = deriveNextProjectRouteState({ slug }, { slug });
|
|
239493
|
+
const created = await repos.project.create({
|
|
239494
|
+
id: opts.id,
|
|
239495
|
+
organizationId: opts.organizationId,
|
|
239496
|
+
groupId: group.id,
|
|
239497
|
+
name: opts.name,
|
|
239498
|
+
slug,
|
|
239499
|
+
environmentName: "Production",
|
|
239500
|
+
environmentSlug: "production",
|
|
239501
|
+
environmentType: "production",
|
|
239502
|
+
gitProvider: opts.gitProvider ?? "github",
|
|
239503
|
+
gitOwner: opts.gitOwner ?? undefined,
|
|
239504
|
+
gitRepo: opts.gitRepo ?? undefined,
|
|
239505
|
+
gitBranch: opts.gitBranch ?? "main",
|
|
239506
|
+
gitUrl: projectGitUrl(opts.gitOwner, opts.gitRepo),
|
|
239507
|
+
autoDeploy: !!opts.autoDeploy,
|
|
239508
|
+
framework: "unknown",
|
|
239509
|
+
packageManager: "npm",
|
|
239510
|
+
hasServer: true,
|
|
239511
|
+
hasBuild: opts.hasBuild ?? false,
|
|
239512
|
+
runtimeMode: opts.runtimeMode === "bare" ? "bare" : "docker"
|
|
239513
|
+
});
|
|
239514
|
+
await persistProjectRouteState(created.id, routing2.publicEndpoints);
|
|
239515
|
+
return created;
|
|
239516
|
+
} catch (err2) {
|
|
239517
|
+
await repos.projectGroup.softDelete(group.id).catch(() => {});
|
|
239518
|
+
throw err2;
|
|
239519
|
+
}
|
|
239520
|
+
}
|
|
239480
239521
|
async function uniqueProjectSlug(organizationId, baseSlug) {
|
|
239481
239522
|
let slug = baseSlug;
|
|
239482
239523
|
let suffix = 2;
|
|
@@ -255152,8 +255193,11 @@ async function triggerDeployment(ctx2, data) {
|
|
|
255152
255193
|
if (!reuse) {
|
|
255153
255194
|
snapshot.buildStrategy = await resolveStrategy(snapshot.framework, snapshot.buildStrategy, { deployTarget: snapshot.deployTarget });
|
|
255154
255195
|
}
|
|
255196
|
+
const { useServicePipeline, servicePreflightServices } = await resolveServicePipelineMode(project2, snapshot);
|
|
255155
255197
|
await runDeploymentPreflight(snapshot, routeState, {
|
|
255156
255198
|
ctx: ctx2,
|
|
255199
|
+
composeServices: servicePreflightServices,
|
|
255200
|
+
multiService: useServicePipeline,
|
|
255157
255201
|
gitOwner: project2.gitOwner,
|
|
255158
255202
|
projectId: project2.id
|
|
255159
255203
|
});
|
|
@@ -260195,6 +260239,22 @@ async function runEnsure(progress, options) {
|
|
|
260195
260239
|
return { ok: false, reason: "migrate_failed" };
|
|
260196
260240
|
return { ok: true };
|
|
260197
260241
|
}
|
|
260242
|
+
if (!options?.edgeTakeover) {
|
|
260243
|
+
const status = await probeEdge2(executor);
|
|
260244
|
+
if (!status.canProceedClean && status.occupants.length > 0) {
|
|
260245
|
+
const owner = status.occupants.map((o4) => o4.command ?? `port ${o4.port}`).join(", ");
|
|
260246
|
+
let siteCount = 0;
|
|
260247
|
+
try {
|
|
260248
|
+
const proxy2 = status.occupants.find((o4) => o4.proxy)?.proxy;
|
|
260249
|
+
if (proxy2 && canImportProxy2(proxy2)) {
|
|
260250
|
+
siteCount = (await scanImportableSites2(executor, proxy2)).sites.length;
|
|
260251
|
+
}
|
|
260252
|
+
} catch {}
|
|
260253
|
+
const sitesNote = siteCount > 0 ? ` serving ${siteCount} site${siteCount === 1 ? "" : "s"}` : "";
|
|
260254
|
+
log7(`An existing proxy (${owner})${sitesNote} is using ports 80 and 443. Openship needs its own ` + `load balancer (OpenResty) there for managed HTTPS — left it running. Re-run setup and choose ` + `migrate or take-over to continue.`, "warn");
|
|
260255
|
+
return { ok: false, reason: "edge_conflict", occupants: owner, siteCount };
|
|
260256
|
+
}
|
|
260257
|
+
}
|
|
260198
260258
|
const installerConfig = options?.edgeTakeover ? { edgePolicy: { mode: "takeover", stopTargets: [] } } : undefined;
|
|
260199
260259
|
const system2 = new SystemManager2("bare", { executor, installerConfig });
|
|
260200
260260
|
await system2.ensureFeature("ssl", (entry) => log7(entry.message));
|
|
@@ -267880,9 +267940,51 @@ function reconcileStack(opts) {
|
|
|
267880
267940
|
networks: networks.map((n3) => ({ name: n3.name, driver: n3.driver })),
|
|
267881
267941
|
warnings,
|
|
267882
267942
|
adoptable: services.length > 0,
|
|
267883
|
-
alreadyManaged
|
|
267943
|
+
alreadyManaged,
|
|
267944
|
+
openshipProjects: opts.openshipProjects ?? []
|
|
267884
267945
|
};
|
|
267885
267946
|
}
|
|
267947
|
+
function reconcileOpenshipProjects(opts) {
|
|
267948
|
+
const { managedDetails, manifestById, knownHereIds, imageDefaults, imageCmds } = opts;
|
|
267949
|
+
const byProject = new Map;
|
|
267950
|
+
for (const d2 of managedDetails) {
|
|
267951
|
+
const projectId = d2.labels["openship.project"];
|
|
267952
|
+
if (!projectId)
|
|
267953
|
+
continue;
|
|
267954
|
+
if (d2.labels["openship.build"])
|
|
267955
|
+
continue;
|
|
267956
|
+
const list9 = byProject.get(projectId) ?? [];
|
|
267957
|
+
list9.push(d2);
|
|
267958
|
+
byProject.set(projectId, list9);
|
|
267959
|
+
}
|
|
267960
|
+
const out2 = [];
|
|
267961
|
+
for (const [projectId, details] of byProject) {
|
|
267962
|
+
const entry = manifestById?.get(projectId);
|
|
267963
|
+
const services = details.map((d2) => {
|
|
267964
|
+
const svc = toDiscoveredService(d2, undefined, imageDefaults?.get(d2.image ?? ""), imageCmds?.get(d2.image ?? ""));
|
|
267965
|
+
const serviceLabel = d2.labels["openship.service"];
|
|
267966
|
+
return serviceLabel ? { ...svc, name: serviceLabel } : svc;
|
|
267967
|
+
});
|
|
267968
|
+
const deploymentId = details.find((d2) => d2.labels["openship.deployment"])?.labels["openship.deployment"] ?? entry?.deployment?.id;
|
|
267969
|
+
out2.push({
|
|
267970
|
+
projectId,
|
|
267971
|
+
knownHere: knownHereIds.has(projectId),
|
|
267972
|
+
suggestedName: entry?.name || entry?.slug || details.find((d2) => d2.composeProject)?.composeProject || `openship-${projectId.replace(/^proj_/, "").slice(0, 8)}`,
|
|
267973
|
+
slug: entry?.slug,
|
|
267974
|
+
domains: entry?.domains,
|
|
267975
|
+
source: entry ? {
|
|
267976
|
+
gitProvider: entry.gitProvider,
|
|
267977
|
+
gitOwner: entry.gitOwner,
|
|
267978
|
+
gitRepo: entry.gitRepo,
|
|
267979
|
+
gitBranch: entry.gitBranch
|
|
267980
|
+
} : undefined,
|
|
267981
|
+
runtimeMode: entry?.runtimeMode ?? undefined,
|
|
267982
|
+
deploymentId,
|
|
267983
|
+
services
|
|
267984
|
+
});
|
|
267985
|
+
}
|
|
267986
|
+
return out2;
|
|
267987
|
+
}
|
|
267886
267988
|
var ENV_DENYLIST, EDGE_PORTS2;
|
|
267887
267989
|
var init_docker_reconcile = __esm(() => {
|
|
267888
267990
|
init_src2();
|
|
@@ -267964,8 +268066,12 @@ async function discoverServerStack(serverId, organizationId, onProgress) {
|
|
|
267964
268066
|
const isOpenshipOwned = (labels) => Object.keys(labels).some((k4) => k4 === "openship" || k4.startsWith("openship."));
|
|
267965
268067
|
const managed = containers.filter((c2) => isOpenshipOwned(c2.labels));
|
|
267966
268068
|
const candidates = containers.filter((c2) => !isOpenshipOwned(c2.labels));
|
|
268069
|
+
const managedApp = managed.filter((c2) => c2.labels["openship.project"] && !c2.labels["openship.build"]);
|
|
267967
268070
|
step(`Inspecting ${candidates.length} container(s)…`);
|
|
267968
|
-
const details =
|
|
268071
|
+
const [details, managedDetails] = await Promise.all([
|
|
268072
|
+
mapLimit(candidates, 5, (c2) => rt2.inspectContainer(c2.id)).then((d2) => d2.filter((x6) => x6 !== null)),
|
|
268073
|
+
mapLimit(managedApp, 5, (c2) => rt2.inspectContainer(c2.id)).then((d2) => d2.filter((x6) => x6 !== null))
|
|
268074
|
+
]);
|
|
267969
268075
|
const groups = new Map;
|
|
267970
268076
|
for (const d2 of details) {
|
|
267971
268077
|
const key = d2.composeProject ?? "";
|
|
@@ -267975,22 +268081,47 @@ async function discoverServerStack(serverId, organizationId, onProgress) {
|
|
|
267975
268081
|
}
|
|
267976
268082
|
step("Reading compose files…");
|
|
267977
268083
|
const declared = await readComposeDeclarations(serverId, groups);
|
|
267978
|
-
const uniqueImages = [
|
|
268084
|
+
const uniqueImages = [
|
|
268085
|
+
...new Set([...details, ...managedDetails].map((d2) => d2.image).filter(Boolean))
|
|
268086
|
+
];
|
|
267979
268087
|
const imageInfoPairs = await mapLimit(uniqueImages, 4, async (ref) => {
|
|
267980
268088
|
const [env6, cmd] = await Promise.all([rt2.inspectImageEnv(ref), rt2.inspectImageCmd(ref)]);
|
|
267981
268089
|
return [ref, { env: new Set(env6), cmd }];
|
|
267982
268090
|
});
|
|
267983
268091
|
const imageDefaults = new Map(imageInfoPairs.map(([ref, v3]) => [ref, v3.env]));
|
|
267984
268092
|
const imageCmds = new Map(imageInfoPairs.map(([ref, v3]) => [ref, v3.cmd]));
|
|
268093
|
+
let openshipProjects = [];
|
|
268094
|
+
let alreadyManaged = 0;
|
|
268095
|
+
const projectIds = [...new Set(managedApp.map((c2) => c2.labels["openship.project"]).filter(Boolean))];
|
|
268096
|
+
if (projectIds.length > 0) {
|
|
268097
|
+
step("Recovering Openship projects…");
|
|
268098
|
+
const manifest = await sshManager.withExecutor(serverId, (exec3) => readManifest2(exec3)).catch(() => null);
|
|
268099
|
+
const manifestById = manifest ? new Map(manifest.projects.map((p4) => [p4.id, p4])) : null;
|
|
268100
|
+
const knownHereIds = new Set;
|
|
268101
|
+
await Promise.all(projectIds.map(async (id2) => {
|
|
268102
|
+
const row = await repos.project.findByIdInOrganization(id2, organizationId);
|
|
268103
|
+
if (row)
|
|
268104
|
+
knownHereIds.add(id2);
|
|
268105
|
+
}));
|
|
268106
|
+
openshipProjects = reconcileOpenshipProjects({
|
|
268107
|
+
managedDetails,
|
|
268108
|
+
manifestById,
|
|
268109
|
+
knownHereIds,
|
|
268110
|
+
imageDefaults,
|
|
268111
|
+
imageCmds
|
|
268112
|
+
});
|
|
268113
|
+
alreadyManaged = managedApp.filter((c2) => knownHereIds.has(c2.labels["openship.project"])).length;
|
|
268114
|
+
}
|
|
267985
268115
|
return reconcileStack({
|
|
267986
268116
|
serverId,
|
|
267987
268117
|
details,
|
|
267988
268118
|
volumes,
|
|
267989
268119
|
networks,
|
|
267990
268120
|
declared,
|
|
267991
|
-
alreadyManaged
|
|
268121
|
+
alreadyManaged,
|
|
267992
268122
|
imageDefaults,
|
|
267993
|
-
imageCmds
|
|
268123
|
+
imageCmds,
|
|
268124
|
+
openshipProjects
|
|
267994
268125
|
});
|
|
267995
268126
|
} finally {
|
|
267996
268127
|
await rt2.dispose();
|
|
@@ -267998,9 +268129,11 @@ async function discoverServerStack(serverId, organizationId, onProgress) {
|
|
|
267998
268129
|
}
|
|
267999
268130
|
var init_docker_inspect_service = __esm(async () => {
|
|
268000
268131
|
init_compose_parser();
|
|
268132
|
+
init_openship_manifest();
|
|
268001
268133
|
init_docker_reconcile();
|
|
268002
268134
|
init_docker_reconcile();
|
|
268003
268135
|
await __promiseAll([
|
|
268136
|
+
init_src3(),
|
|
268004
268137
|
init_deployment_runtime(),
|
|
268005
268138
|
init_ssh_manager()
|
|
268006
268139
|
]);
|
|
@@ -268031,28 +268164,7 @@ function normalizeHostPorts(ports, claimed) {
|
|
|
268031
268164
|
});
|
|
268032
268165
|
return { ports: out2, droppedDuplicates };
|
|
268033
268166
|
}
|
|
268034
|
-
|
|
268035
|
-
const { serverId, organizationId, projectName, serviceNames, sameServer, volumeStrategies } = opts;
|
|
268036
|
-
const stack = await discoverServerStack(serverId, organizationId);
|
|
268037
|
-
const selected = new Set(serviceNames);
|
|
268038
|
-
const chosen = stack.services.filter((s4) => selected.has(s4.name) && !s4.proxyKind);
|
|
268039
|
-
if (chosen.length === 0) {
|
|
268040
|
-
throw new Error("None of the selected services were found on the server.");
|
|
268041
|
-
}
|
|
268042
|
-
if (!sameServer) {
|
|
268043
|
-
const built = chosen.filter((s4) => Boolean(s4.build)).map((s4) => s4.name);
|
|
268044
|
-
if (built.length > 0) {
|
|
268045
|
-
throw new Error(`Cross-server migration can't move locally-built images yet (${built.join(", ")}). ` + `Take these over in place (migrate to the same server), or rebuild them from a registry image. Cross-server for built images is coming soon.`);
|
|
268046
|
-
}
|
|
268047
|
-
}
|
|
268048
|
-
const anyBuild = chosen.some((s4) => !s4.image && Boolean(s4.build));
|
|
268049
|
-
const ensureBody = {
|
|
268050
|
-
name: projectName,
|
|
268051
|
-
projectType: "services",
|
|
268052
|
-
hasServer: true,
|
|
268053
|
-
hasBuild: anyBuild
|
|
268054
|
-
};
|
|
268055
|
-
const { project_id, created } = await ensureProject(ensureBody, organizationId);
|
|
268167
|
+
function buildAdoptedServiceRows(chosen, selected) {
|
|
268056
268168
|
const nameCounts = new Map;
|
|
268057
268169
|
const firstUnique = new Map;
|
|
268058
268170
|
const uniqueNames = chosen.map((s4) => {
|
|
@@ -268064,7 +268176,7 @@ async function adoptServerStack(opts) {
|
|
|
268064
268176
|
return unique;
|
|
268065
268177
|
});
|
|
268066
268178
|
const claimedHostPorts = new Set;
|
|
268067
|
-
|
|
268179
|
+
return chosen.map((s4, i3) => {
|
|
268068
268180
|
const { ports, droppedDuplicates } = normalizeHostPorts(s4.ports, claimedHostPorts);
|
|
268069
268181
|
if (droppedDuplicates.length > 0) {
|
|
268070
268182
|
s4.warnings.push(`Host port(s) ${droppedDuplicates.join(", ")} already published by another service — ` + `kept ${uniqueNames[i3]} on the internal network only (reachable as ${uniqueNames[i3]}:<port>).`);
|
|
@@ -268084,6 +268196,30 @@ async function adoptServerStack(opts) {
|
|
|
268084
268196
|
advanced: s4.healthcheck ? { healthcheck: s4.healthcheck } : undefined
|
|
268085
268197
|
};
|
|
268086
268198
|
});
|
|
268199
|
+
}
|
|
268200
|
+
async function adoptServerStack(opts) {
|
|
268201
|
+
const { serverId, organizationId, projectName, serviceNames, sameServer, volumeStrategies } = opts;
|
|
268202
|
+
const stack = await discoverServerStack(serverId, organizationId);
|
|
268203
|
+
const selected = new Set(serviceNames);
|
|
268204
|
+
const chosen = stack.services.filter((s4) => selected.has(s4.name) && !s4.proxyKind);
|
|
268205
|
+
if (chosen.length === 0) {
|
|
268206
|
+
throw new Error("None of the selected services were found on the server.");
|
|
268207
|
+
}
|
|
268208
|
+
if (!sameServer) {
|
|
268209
|
+
const built = chosen.filter((s4) => Boolean(s4.build)).map((s4) => s4.name);
|
|
268210
|
+
if (built.length > 0) {
|
|
268211
|
+
throw new Error(`Cross-server migration can't move locally-built images yet (${built.join(", ")}). ` + `Take these over in place (migrate to the same server), or rebuild them from a registry image. Cross-server for built images is coming soon.`);
|
|
268212
|
+
}
|
|
268213
|
+
}
|
|
268214
|
+
const anyBuild = chosen.some((s4) => !s4.image && Boolean(s4.build));
|
|
268215
|
+
const ensureBody = {
|
|
268216
|
+
name: projectName,
|
|
268217
|
+
projectType: "services",
|
|
268218
|
+
hasServer: true,
|
|
268219
|
+
hasBuild: anyBuild
|
|
268220
|
+
};
|
|
268221
|
+
const { project_id, created } = await ensureProject(ensureBody, organizationId);
|
|
268222
|
+
const parsed = buildAdoptedServiceRows(chosen, selected);
|
|
268087
268223
|
const createdServices = await repos.service.syncFromCompose(project_id, parsed);
|
|
268088
268224
|
for (const svc of createdServices) {
|
|
268089
268225
|
const copy = Boolean(sameServer) && volumeStrategies?.[svc.name] === "copy";
|
|
@@ -268099,13 +268235,66 @@ async function adoptServerStack(opts) {
|
|
|
268099
268235
|
adopted: chosen.map((s4) => s4.name)
|
|
268100
268236
|
};
|
|
268101
268237
|
}
|
|
268238
|
+
async function reimportOpenshipProject(opts) {
|
|
268239
|
+
const { serverId, organizationId, projectId, projectName, serviceNames } = opts;
|
|
268240
|
+
if (!PROJECT_ID_RE.test(projectId)) {
|
|
268241
|
+
throw new Error("Invalid Openship project id.");
|
|
268242
|
+
}
|
|
268243
|
+
const existing = await repos.project.findById(projectId);
|
|
268244
|
+
if (existing) {
|
|
268245
|
+
throw new Error("A project with this id already exists here — nothing to re-import.");
|
|
268246
|
+
}
|
|
268247
|
+
const stack = await discoverServerStack(serverId, organizationId);
|
|
268248
|
+
const group = stack.openshipProjects.find((p4) => p4.projectId === projectId);
|
|
268249
|
+
if (!group) {
|
|
268250
|
+
throw new Error("That Openship project was not found on the server.");
|
|
268251
|
+
}
|
|
268252
|
+
if (group.knownHere) {
|
|
268253
|
+
throw new Error("That Openship project is already managed by this instance.");
|
|
268254
|
+
}
|
|
268255
|
+
const selected = serviceNames?.length ? new Set(serviceNames) : new Set(group.services.map((s4) => s4.name));
|
|
268256
|
+
const chosen = group.services.filter((s4) => selected.has(s4.name) && !s4.proxyKind);
|
|
268257
|
+
if (chosen.length === 0) {
|
|
268258
|
+
throw new Error("None of the selected services were found on the server.");
|
|
268259
|
+
}
|
|
268260
|
+
const name2 = projectName?.trim() || group.suggestedName;
|
|
268261
|
+
const anyBuild = chosen.some((s4) => !s4.image && Boolean(s4.build));
|
|
268262
|
+
const created = await createServicesProjectWithId({
|
|
268263
|
+
id: projectId,
|
|
268264
|
+
name: name2,
|
|
268265
|
+
slug: group.slug || slugify(name2),
|
|
268266
|
+
organizationId,
|
|
268267
|
+
hasBuild: anyBuild,
|
|
268268
|
+
runtimeMode: group.runtimeMode === "bare" ? "bare" : "docker",
|
|
268269
|
+
gitProvider: group.source?.gitProvider ?? undefined,
|
|
268270
|
+
gitOwner: group.source?.gitOwner ?? undefined,
|
|
268271
|
+
gitRepo: group.source?.gitRepo ?? undefined,
|
|
268272
|
+
gitBranch: group.source?.gitBranch ?? undefined
|
|
268273
|
+
});
|
|
268274
|
+
const parsed = buildAdoptedServiceRows(chosen, selected);
|
|
268275
|
+
const createdServices = await repos.service.syncFromCompose(created.id, parsed);
|
|
268276
|
+
for (const svc of createdServices) {
|
|
268277
|
+
if (svc.namespaceVolumes !== false) {
|
|
268278
|
+
await repos.service.update(svc.id, { namespaceVolumes: false });
|
|
268279
|
+
}
|
|
268280
|
+
}
|
|
268281
|
+
return {
|
|
268282
|
+
projectId: created.id,
|
|
268283
|
+
slug: created.slug,
|
|
268284
|
+
reimported: chosen.map((s4) => s4.name),
|
|
268285
|
+
deferredDeployment: true
|
|
268286
|
+
};
|
|
268287
|
+
}
|
|
268288
|
+
var PROJECT_ID_RE;
|
|
268102
268289
|
var init_migrate_service = __esm(async () => {
|
|
268290
|
+
init_src();
|
|
268103
268291
|
init_docker_reconcile();
|
|
268104
268292
|
await __promiseAll([
|
|
268105
268293
|
init_src3(),
|
|
268106
268294
|
init_project_crud_service(),
|
|
268107
268295
|
init_docker_inspect_service()
|
|
268108
268296
|
]);
|
|
268297
|
+
PROJECT_ID_RE = /^proj_[A-Za-z0-9]+$/;
|
|
268109
268298
|
});
|
|
268110
268299
|
|
|
268111
268300
|
// ../api/src/modules/migration/migration-preflight.ts
|
|
@@ -268679,6 +268868,35 @@ async function adoptServer(c2) {
|
|
|
268679
268868
|
return c2.json({ error: `Adopt failed: ${safeErrorMessage(err2)}` }, 502);
|
|
268680
268869
|
}
|
|
268681
268870
|
}
|
|
268871
|
+
async function reimportServer(c2) {
|
|
268872
|
+
const body2 = await c2.req.json();
|
|
268873
|
+
const { serverId, projectId, projectName, serviceNames } = body2;
|
|
268874
|
+
if (!serverId)
|
|
268875
|
+
return c2.json({ error: "serverId is required" }, 400);
|
|
268876
|
+
if (!projectId?.trim())
|
|
268877
|
+
return c2.json({ error: "projectId is required" }, 400);
|
|
268878
|
+
const ctx2 = getRequestContext(c2);
|
|
268879
|
+
await permission.assert(ctx2, {
|
|
268880
|
+
resourceType: "server",
|
|
268881
|
+
resourceId: serverId,
|
|
268882
|
+
action: "write"
|
|
268883
|
+
});
|
|
268884
|
+
if (!await isServerInOrg(ctx2, serverId)) {
|
|
268885
|
+
return c2.json({ error: "Server not found" }, 404);
|
|
268886
|
+
}
|
|
268887
|
+
try {
|
|
268888
|
+
const result2 = await reimportOpenshipProject({
|
|
268889
|
+
serverId,
|
|
268890
|
+
organizationId: ctx2.organizationId,
|
|
268891
|
+
projectId: projectId.trim(),
|
|
268892
|
+
projectName: projectName?.trim() || undefined,
|
|
268893
|
+
serviceNames: Array.isArray(serviceNames) ? serviceNames : undefined
|
|
268894
|
+
});
|
|
268895
|
+
return c2.json({ success: true, ...result2 });
|
|
268896
|
+
} catch (err2) {
|
|
268897
|
+
return c2.json({ error: `Re-import failed: ${safeErrorMessage(err2)}` }, 502);
|
|
268898
|
+
}
|
|
268899
|
+
}
|
|
268682
268900
|
async function previewMigration(c2) {
|
|
268683
268901
|
const body2 = await c2.req.json();
|
|
268684
268902
|
const sourceServerId = body2.sourceServerId;
|
|
@@ -268821,6 +269039,7 @@ var init_migration_routes = __esm(async () => {
|
|
|
268821
269039
|
r26.post("/scan", { tag: "server:write", collection: true }, scanServer2);
|
|
268822
269040
|
r26.get("/scan/stream", { tag: "server:write", collection: true }, scanServerStream);
|
|
268823
269041
|
r26.post("/adopt", { tag: "server:write", collection: true }, adoptServer);
|
|
269042
|
+
r26.post("/reimport", { tag: "server:write", collection: true }, reimportServer);
|
|
268824
269043
|
r26.post("/preview", { tag: "server:write", collection: true }, previewMigration);
|
|
268825
269044
|
r26.post("/migrate", { tag: "server:write", collection: true }, startMigration);
|
|
268826
269045
|
r26.get("/migrations/:id", { tag: "server:read", collection: true }, getMigration);
|
|
@@ -278693,6 +278912,7 @@ var deploymentRoutes = r4.hono;
|
|
|
278693
278912
|
|
|
278694
278913
|
// ../api/src/modules/domains/domain.routes.ts
|
|
278695
278914
|
init_dist2();
|
|
278915
|
+
|
|
278696
278916
|
// ../../node_modules/@sinclair/typebox/build/esm/errors/function.mjs
|
|
278697
278917
|
function DefaultErrorFunction(error101) {
|
|
278698
278918
|
switch (error101.errorType) {
|
|
@@ -279970,7 +280190,6 @@ function Errors(...args2) {
|
|
|
279970
280190
|
const iterator = args2.length === 3 ? Visit6(args2[0], args2[1], "", args2[2]) : Visit6(args2[0], [], "", args2[1]);
|
|
279971
280191
|
return new ValueErrorIterator(iterator);
|
|
279972
280192
|
}
|
|
279973
|
-
|
|
279974
280193
|
// ../../node_modules/@sinclair/typebox/build/esm/value/assert/assert.mjs
|
|
279975
280194
|
var __classPrivateFieldSet = function(receiver, state, value, kind, f3) {
|
|
279976
280195
|
if (kind === "m")
|
|
@@ -284822,7 +285041,7 @@ import { hostname as hostname6, userInfo } from "node:os";
|
|
|
284822
285041
|
// ../api/package.json
|
|
284823
285042
|
var package_default = {
|
|
284824
285043
|
name: "@repo/api",
|
|
284825
|
-
version: "0.
|
|
285044
|
+
version: "0.3.0",
|
|
284826
285045
|
license: "Apache-2.0",
|
|
284827
285046
|
private: true,
|
|
284828
285047
|
type: "module",
|