openship 0.4.8 → 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 +1 -0
- package/dist/{bare-JY5Y5ELU.js → bare-VRGE5MXH.js} +7 -7
- package/dist/{chunk-TGIINPVM.js → chunk-6LKHXB6T.js} +22 -7
- package/dist/{chunk-2D3I5G6P.js → chunk-6PIYRG5I.js} +23 -3
- package/dist/{chunk-BBHX7T4R.js → chunk-BS2AXYZX.js} +401 -76
- package/dist/{chunk-SJIFLLX4.js → chunk-CUJXGK7R.js} +321 -85
- package/dist/{chunk-VFINNTUL.js → chunk-EAAGSQXN.js} +23 -8
- package/dist/{chunk-4Z5QO7N6.js → chunk-I6PSTQIR.js} +2 -2
- package/dist/{chunk-5NYUCONN.js → chunk-JLKKYUZA.js} +31 -49
- package/dist/{chunk-XPPZ7B2J.js → chunk-K2RPVGPN.js} +2 -2
- package/dist/{chunk-MZ2WEHHY.js → chunk-KNTJ7PSF.js} +1 -1
- package/dist/{chunk-L2VOGB2X.js → chunk-KZOBYJUW.js} +1 -1
- package/dist/{chunk-GKHUSZCD.js → chunk-NNPEG6HM.js} +1 -1
- package/dist/{chunk-SLTYVHU7.js → chunk-NXFIRK2Z.js} +381 -72
- package/dist/{chunk-FXTBHTWY.js → chunk-RB35YN3J.js} +271 -35
- package/dist/{chunk-6APULWSU.js → chunk-UMQP7SYT.js} +429 -66
- package/dist/{chunk-V6AN6XLZ.js → chunk-V7BZMGOT.js} +123 -45
- package/dist/{chunk-VDMQJHPI.js → chunk-YWMODKWL.js} +67 -4
- package/dist/{chunk-OXWDY22G.js → chunk-ZCOQJCZO.js} +1 -1
- package/dist/{cloud-KYWY3RP4.js → cloud-3M2WZ624.js} +12 -12
- package/dist/{detect-AZLOHUFX.js → detect-BAJMY6KM.js} +3 -3
- package/dist/{docker-LODK5Y2S.js → docker-2NGBRJFJ.js} +9 -7
- package/dist/{docker-edge-executor-VHW3JPJS.js → docker-edge-executor-5I4M5QT7.js} +1 -1
- package/dist/{edge-import-ABUDKKJI.js → edge-import-RIWNEIXQ.js} +21 -19
- package/dist/{ensure-container-edge-SW6HENSG.js → ensure-container-edge-3NSYKHRX.js} +6 -6
- package/dist/{executor-XJ6RP4Q2.js → executor-LOYMPU67.js} +3 -3
- package/dist/index.js +269 -331
- package/dist/{nginx-3L4SIBJA.js → nginx-QE4DOM5J.js} +4 -4
- package/dist/{openresty-lua-4WLGDSER.js → openresty-lua-BTAKECCF.js} +2 -2
- package/dist/server/index.js +51643 -45322
- package/dist/server/migrations/0073_project_volumes_object_storage.sql +3 -0
- package/dist/server/migrations/0074_project_compose_path.sql +1 -0
- package/dist/server/migrations/0075_service_command_argv.sql +1 -0
- package/dist/server/migrations/0076_rollback_retention.sql +17 -0
- package/dist/server/migrations/0077_domain_redirect.sql +13 -0
- package/dist/server/migrations/0078_grant_source_scope.sql +30 -0
- package/dist/server/migrations/0079_project_readiness.sql +18 -0
- package/dist/server/migrations/0080_deployment_error_classification.sql +26 -0
- package/dist/server/migrations/0081_project_readiness_repair.sql +34 -0
- package/dist/server/migrations/meta/_journal.json +63 -0
- package/dist/{setup-NU6T2PDU.js → setup-KELALK7H.js} +7 -7
- package/package.json +1 -1
|
@@ -52,8 +52,15 @@ var LANGUAGES = {
|
|
|
52
52
|
},
|
|
53
53
|
php: {
|
|
54
54
|
name: "PHP",
|
|
55
|
-
buildImage: "php:8.
|
|
56
|
-
|
|
55
|
+
buildImage: "php:8.4-cli",
|
|
56
|
+
// FrankenPHP, not php:*-fpm. An fpm image is a FastCGI backend, not a
|
|
57
|
+
// process host: it ships no web server, and pairing it with an apt nginx
|
|
58
|
+
// means two processes under a shell that swallows SIGTERM — a container stop
|
|
59
|
+
// then kills in-flight work instead of draining it. FrankenPHP is ONE
|
|
60
|
+
// process that owns both the HTTP server and PHP, so signals land where they
|
|
61
|
+
// should with no supervision tree, it runs fine as a non-root user, and its
|
|
62
|
+
// docroot convention (`/app/public`) is already the layout our recipes emit.
|
|
63
|
+
runtimeImage: "dunglas/frankenphp:1-php8.4-bookworm",
|
|
57
64
|
packageManagers: ["composer"],
|
|
58
65
|
requiredTools: ["php", "composer"]
|
|
59
66
|
},
|
|
@@ -515,18 +522,28 @@ var STACKS = {
|
|
|
515
522
|
}
|
|
516
523
|
},
|
|
517
524
|
// ── PHP ────────────────────────────────────────────────────────────────────
|
|
518
|
-
// PHP stacks
|
|
519
|
-
//
|
|
520
|
-
//
|
|
521
|
-
//
|
|
525
|
+
// PHP stacks serve `public/` from FrankenPHP (see LANGUAGES.php). `exec` hands
|
|
526
|
+
// the container's PID to frankenphp so SIGTERM drains in-flight requests
|
|
527
|
+
// instead of being swallowed by the shell; SERVER_NAME carries the injected
|
|
528
|
+
// $PORT (a bare `:port` also keeps Caddy's automatic HTTPS out of the way —
|
|
529
|
+
// TLS terminates at the edge). No build command: `composer install` is the
|
|
530
|
+
// INSTALL step, and the build step is where a JS asset pipeline goes (the
|
|
531
|
+
// detector fills it in when the repo has one).
|
|
522
532
|
laravel: {
|
|
523
533
|
name: "Laravel",
|
|
524
534
|
language: "php",
|
|
525
535
|
category: "fullstack",
|
|
526
536
|
outputDirectory: "public",
|
|
527
537
|
defaultPort: 8e3,
|
|
528
|
-
defaultBuildCommand: "
|
|
529
|
-
defaultStartCommand: "
|
|
538
|
+
defaultBuildCommand: "",
|
|
539
|
+
defaultStartCommand: 'SERVER_NAME=":$PORT" exec frankenphp run --config /etc/frankenphp/Caddyfile --adapter caddyfile',
|
|
540
|
+
// Everything a stock Laravel app writes lives here: uploads
|
|
541
|
+
// (storage/app), sessions + cache when the drivers are `file`, and the
|
|
542
|
+
// framework's own scratch space. `database/` is deliberately NOT persisted —
|
|
543
|
+
// it holds migrations, so mounting over it would hide the ones a later
|
|
544
|
+
// release adds. A SQLite app should point DB_DATABASE at a persisted path or
|
|
545
|
+
// (better) use a database service.
|
|
546
|
+
persistentPaths: ["storage"],
|
|
530
547
|
detection: {
|
|
531
548
|
rootMarkers: ["artisan", "composer.json"],
|
|
532
549
|
deps: ["laravel/framework"]
|
|
@@ -538,8 +555,10 @@ var STACKS = {
|
|
|
538
555
|
category: "fullstack",
|
|
539
556
|
outputDirectory: "public",
|
|
540
557
|
defaultPort: 8e3,
|
|
541
|
-
defaultBuildCommand: "
|
|
542
|
-
defaultStartCommand: "
|
|
558
|
+
defaultBuildCommand: "",
|
|
559
|
+
defaultStartCommand: 'SERVER_NAME=":$PORT" exec frankenphp run --config /etc/frankenphp/Caddyfile --adapter caddyfile',
|
|
560
|
+
// No persistentPaths: Symfony's `var/` is cache + logs, both regenerated,
|
|
561
|
+
// and it has no convention for where user uploads land.
|
|
543
562
|
detection: {
|
|
544
563
|
rootMarkers: ["composer.json", "symfony.lock"],
|
|
545
564
|
deps: ["symfony/framework-bundle"]
|
|
@@ -778,6 +797,9 @@ var STACK_ROOT_MARKERS = new Set(
|
|
|
778
797
|
Object.values(STACKS).flatMap((stack) => stack.detection?.rootMarkers ?? []).map((marker) => marker.toLowerCase())
|
|
779
798
|
);
|
|
780
799
|
function packageManagerEnsureCommand(packageManager) {
|
|
800
|
+
if (packageManager === "bun") {
|
|
801
|
+
return `(command -v bun >/dev/null 2>&1 || npm i -g bun) >/dev/null 2>&1 || true`;
|
|
802
|
+
}
|
|
781
803
|
if (packageManager !== "pnpm" && packageManager !== "yarn") return "";
|
|
782
804
|
return `(corepack enable ${packageManager} || corepack enable || npm i -g ${packageManager}) >/dev/null 2>&1 || true`;
|
|
783
805
|
}
|
|
@@ -841,6 +863,22 @@ var STACK_ICONS = {
|
|
|
841
863
|
"docker-compose": `${DI}/docker/docker-original.svg`
|
|
842
864
|
};
|
|
843
865
|
|
|
866
|
+
// ../../packages/core/src/volumes.ts
|
|
867
|
+
var APP_DIR = "/app";
|
|
868
|
+
var MODE_SUFFIX = /:(ro|rw|z|Z|nocopy)$/;
|
|
869
|
+
function appVolumeTargets(volumes, appDir = APP_DIR) {
|
|
870
|
+
const out = [];
|
|
871
|
+
for (const spec of volumes) {
|
|
872
|
+
const body = spec.replace(MODE_SUFFIX, "");
|
|
873
|
+
const idx = body.indexOf(":");
|
|
874
|
+
if (idx < 0) continue;
|
|
875
|
+
const target = body.slice(idx + 1);
|
|
876
|
+
if (!target.startsWith(`${appDir}/`)) continue;
|
|
877
|
+
out.push(target.slice(appDir.length + 1));
|
|
878
|
+
}
|
|
879
|
+
return out;
|
|
880
|
+
}
|
|
881
|
+
|
|
844
882
|
// ../../packages/core/src/constants.ts
|
|
845
883
|
var DEFAULT_IMAGE_REGISTRY = "ghcr.io/oblien";
|
|
846
884
|
var PLANS = {
|
|
@@ -1017,7 +1055,35 @@ var SYSTEM = {
|
|
|
1017
1055
|
/** Maximum length of the error message stored in DB */
|
|
1018
1056
|
MAX_ERROR_MESSAGE_LENGTH: 512,
|
|
1019
1057
|
/** Default restart policy for production containers */
|
|
1020
|
-
DEFAULT_RESTART_POLICY: "always"
|
|
1058
|
+
DEFAULT_RESTART_POLICY: "always",
|
|
1059
|
+
/**
|
|
1060
|
+
* How long a just-started container is watched before a deploy may call
|
|
1061
|
+
* itself ready. Container-create succeeding proves nothing: a bad start
|
|
1062
|
+
* command exits within milliseconds and `restart: always` hides it behind a
|
|
1063
|
+
* bounce loop. Measured from each container's OWN start time, so a stack
|
|
1064
|
+
* whose earlier services have already been up this long waits only for the
|
|
1065
|
+
* last one.
|
|
1066
|
+
*/
|
|
1067
|
+
STABILIZE_WINDOW_MS: 15e3,
|
|
1068
|
+
/** Inspect poll interval inside that window. */
|
|
1069
|
+
STABILIZE_POLL_MS: 1e3,
|
|
1070
|
+
/**
|
|
1071
|
+
* Restarts within the window that mean "crash loop" rather than "waited for
|
|
1072
|
+
* a dependency and recovered". Docker's restart backoff (100ms doubling)
|
|
1073
|
+
* takes an instantly-exiting process past this in ~2s, while a service that
|
|
1074
|
+
* times out waiting on a slow database manages one or two.
|
|
1075
|
+
*/
|
|
1076
|
+
STABILIZE_CRASH_RESTARTS: 3,
|
|
1077
|
+
/** Log lines folded into the failure message, so diagnosing needs no SSH. */
|
|
1078
|
+
STABILIZE_LOG_TAIL_LINES: 20,
|
|
1079
|
+
/**
|
|
1080
|
+
* Readiness-probe budget when a project OPTS IN to the health check. Only
|
|
1081
|
+
* reached with `readiness.enabled` — an unconfigured deploy runs no probe
|
|
1082
|
+
* at all, so this never sits on the default critical path.
|
|
1083
|
+
*/
|
|
1084
|
+
READINESS_TIMEOUT_MS: 45e3,
|
|
1085
|
+
/** Readiness-probe poll interval. */
|
|
1086
|
+
READINESS_INTERVAL_MS: 1e3
|
|
1021
1087
|
},
|
|
1022
1088
|
// ── SSE / Build Streaming ────────────────────────────────────────────
|
|
1023
1089
|
SSE: {
|
|
@@ -1071,11 +1137,12 @@ var SYSTEM = {
|
|
|
1071
1137
|
/** Port range */
|
|
1072
1138
|
MIN_PORT: 1,
|
|
1073
1139
|
MAX_PORT: 65535,
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
MAX_MEMORY_MB: 8192
|
|
1140
|
+
// Resource bounds deliberately do NOT live here. They belong to
|
|
1141
|
+
// ./resources.ts, which is the single source of truth: the floors
|
|
1142
|
+
// (MIN_CPU_CORES / MIN_MEMORY_MB) plus the rule that the UPPER bound is the
|
|
1143
|
+
// target machine's probed capacity, not a constant. The unread
|
|
1144
|
+
// MAX_CPU_CORES: 4 / MAX_MEMORY_MB: 8192 pair that used to sit here encoded
|
|
1145
|
+
// exactly the fixed ceiling that made a large self-hosted box unusable.
|
|
1079
1146
|
/** Pagination */
|
|
1080
1147
|
DEFAULT_PAGE: 1,
|
|
1081
1148
|
DEFAULT_PER_PAGE: 20,
|
|
@@ -1083,6 +1150,41 @@ var SYSTEM = {
|
|
|
1083
1150
|
}
|
|
1084
1151
|
};
|
|
1085
1152
|
|
|
1153
|
+
// ../../packages/core/src/utils.ts
|
|
1154
|
+
var REDIRECT_STATUSES = [301, 302, 307, 308];
|
|
1155
|
+
var DEFAULT_REDIRECT_STATUS = 301;
|
|
1156
|
+
function resolveRedirectStatus(status) {
|
|
1157
|
+
return REDIRECT_STATUSES.includes(status) ? status : DEFAULT_REDIRECT_STATUS;
|
|
1158
|
+
}
|
|
1159
|
+
function isValidEmail(value) {
|
|
1160
|
+
const email3 = value?.trim() ?? "";
|
|
1161
|
+
if (!email3 || email3.length > 254) return false;
|
|
1162
|
+
return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/.test(email3);
|
|
1163
|
+
}
|
|
1164
|
+
function formatBytes(bytes, decimals = 2) {
|
|
1165
|
+
if (bytes <= 0) return "0 B";
|
|
1166
|
+
const k = 1024;
|
|
1167
|
+
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
1168
|
+
const i = Math.min(Math.max(Math.floor(Math.log(bytes) / Math.log(k)), 0), sizes.length - 1);
|
|
1169
|
+
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`;
|
|
1170
|
+
}
|
|
1171
|
+
function withTimeout(promise2, ms, message) {
|
|
1172
|
+
if (!ms) return promise2;
|
|
1173
|
+
return new Promise((resolve, reject) => {
|
|
1174
|
+
const timer = setTimeout(() => reject(new Error(message)), ms);
|
|
1175
|
+
promise2.then(
|
|
1176
|
+
(v) => {
|
|
1177
|
+
clearTimeout(timer);
|
|
1178
|
+
resolve(v);
|
|
1179
|
+
},
|
|
1180
|
+
(e) => {
|
|
1181
|
+
clearTimeout(timer);
|
|
1182
|
+
reject(e);
|
|
1183
|
+
}
|
|
1184
|
+
);
|
|
1185
|
+
});
|
|
1186
|
+
}
|
|
1187
|
+
|
|
1086
1188
|
// ../../packages/core/src/errors.ts
|
|
1087
1189
|
var AppError = class extends Error {
|
|
1088
1190
|
constructor(message, statusCode = 500, code) {
|
|
@@ -1106,6 +1208,12 @@ function safeErrorMessage(err) {
|
|
|
1106
1208
|
return String(err).slice(0, 2e3);
|
|
1107
1209
|
}
|
|
1108
1210
|
|
|
1211
|
+
// ../../packages/core/src/types.ts
|
|
1212
|
+
var OPENSHIP_READINESS_FAILURE_ACTIONS = [
|
|
1213
|
+
"warn",
|
|
1214
|
+
"fail"
|
|
1215
|
+
];
|
|
1216
|
+
|
|
1109
1217
|
// ../../packages/core/src/openship-config/schema.ts
|
|
1110
1218
|
var OPENSHIP_RUNTIMES = ["bare", "docker"];
|
|
1111
1219
|
var OPENSHIP_PRODUCTION_MODES = [
|
|
@@ -1121,6 +1229,7 @@ var OPENSHIP_RESTARTS = [
|
|
|
1121
1229
|
"unless-stopped"
|
|
1122
1230
|
];
|
|
1123
1231
|
var OPENSHIP_RESOURCE_TIERS = [
|
|
1232
|
+
"unlimited",
|
|
1124
1233
|
"micro",
|
|
1125
1234
|
"low",
|
|
1126
1235
|
"medium",
|
|
@@ -1133,12 +1242,14 @@ var TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
1133
1242
|
"framework",
|
|
1134
1243
|
"packageManager",
|
|
1135
1244
|
"rootDirectory",
|
|
1245
|
+
"composePath",
|
|
1136
1246
|
"installCommand",
|
|
1137
1247
|
"buildCommand",
|
|
1138
1248
|
"startCommand",
|
|
1139
1249
|
"outputDirectory",
|
|
1140
1250
|
"buildImage",
|
|
1141
1251
|
"productionPaths",
|
|
1252
|
+
"volumes",
|
|
1142
1253
|
"runtime",
|
|
1143
1254
|
"productionMode",
|
|
1144
1255
|
"port",
|
|
@@ -1146,6 +1257,7 @@ var TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
|
|
|
1146
1257
|
"domains",
|
|
1147
1258
|
"routes",
|
|
1148
1259
|
"resources",
|
|
1260
|
+
"readiness",
|
|
1149
1261
|
"services",
|
|
1150
1262
|
"monorepo"
|
|
1151
1263
|
]);
|
|
@@ -1320,12 +1432,28 @@ function parseResources(ctx, v, path) {
|
|
|
1320
1432
|
}
|
|
1321
1433
|
const r = {
|
|
1322
1434
|
tier: ctx.enumOf(v.tier, `${path}.tier`, OPENSHIP_RESOURCE_TIERS),
|
|
1323
|
-
cpuCores: ctx.int(v.cpuCores, `${path}.cpuCores`, 0
|
|
1324
|
-
memoryMb: ctx.int(v.memoryMb, `${path}.memoryMb`,
|
|
1325
|
-
diskMb: ctx.int(v.diskMb, `${path}.diskMb`,
|
|
1435
|
+
cpuCores: ctx.int(v.cpuCores, `${path}.cpuCores`, 0, 1024),
|
|
1436
|
+
memoryMb: ctx.int(v.memoryMb, `${path}.memoryMb`, 0, 4194304),
|
|
1437
|
+
diskMb: ctx.int(v.diskMb, `${path}.diskMb`, 0, 204800)
|
|
1326
1438
|
};
|
|
1327
1439
|
return r;
|
|
1328
1440
|
}
|
|
1441
|
+
function parseReadiness(ctx, v, path) {
|
|
1442
|
+
if (v === void 0) return void 0;
|
|
1443
|
+
if (!ctx.isObj(v)) {
|
|
1444
|
+
ctx.err(path, "must be an object");
|
|
1445
|
+
return void 0;
|
|
1446
|
+
}
|
|
1447
|
+
return {
|
|
1448
|
+
enabled: ctx.bool(v.enabled, `${path}.enabled`),
|
|
1449
|
+
path: ctx.str(v.path, `${path}.path`),
|
|
1450
|
+
port: ctx.int(v.port, `${path}.port`, 1, 65535),
|
|
1451
|
+
timeoutSeconds: ctx.int(v.timeoutSeconds, `${path}.timeoutSeconds`, 1, 600),
|
|
1452
|
+
stabilization: ctx.bool(v.stabilization, `${path}.stabilization`),
|
|
1453
|
+
stabilizationSeconds: ctx.int(v.stabilizationSeconds, `${path}.stabilizationSeconds`, 1, 600),
|
|
1454
|
+
onFailure: ctx.enumOf(v.onFailure, `${path}.onFailure`, OPENSHIP_READINESS_FAILURE_ACTIONS)
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1329
1457
|
function parseHealthcheck(ctx, v, path) {
|
|
1330
1458
|
if (v === void 0) return void 0;
|
|
1331
1459
|
if (!ctx.isObj(v)) {
|
|
@@ -1374,7 +1502,9 @@ function parseServices(ctx, v, path) {
|
|
|
1374
1502
|
exposed: ctx.bool(item.exposed, `${p}.exposed`),
|
|
1375
1503
|
exposedPort: ctx.str(item.exposedPort, `${p}.exposedPort`),
|
|
1376
1504
|
domain: ctx.str(item.domain, `${p}.domain`),
|
|
1377
|
-
healthcheck: parseHealthcheck(ctx, item.healthcheck, `${p}.healthcheck`)
|
|
1505
|
+
healthcheck: parseHealthcheck(ctx, item.healthcheck, `${p}.healthcheck`),
|
|
1506
|
+
readiness: parseReadiness(ctx, item.readiness, `${p}.readiness`),
|
|
1507
|
+
resources: parseResources(ctx, item.resources, `${p}.resources`)
|
|
1378
1508
|
});
|
|
1379
1509
|
});
|
|
1380
1510
|
return out;
|
|
@@ -1458,12 +1588,14 @@ function parseOpenshipConfig(raw) {
|
|
|
1458
1588
|
framework: ctx.enumOf(raw.framework, "framework", STACK_IDS),
|
|
1459
1589
|
packageManager: parsePackageManager(ctx, raw.packageManager, "packageManager"),
|
|
1460
1590
|
rootDirectory: ctx.str(raw.rootDirectory, "rootDirectory"),
|
|
1591
|
+
composePath: ctx.str(raw.composePath, "composePath"),
|
|
1461
1592
|
installCommand: ctx.str(raw.installCommand, "installCommand"),
|
|
1462
1593
|
buildCommand: ctx.str(raw.buildCommand, "buildCommand"),
|
|
1463
1594
|
startCommand: ctx.str(raw.startCommand, "startCommand"),
|
|
1464
1595
|
outputDirectory: ctx.str(raw.outputDirectory, "outputDirectory"),
|
|
1465
1596
|
buildImage: ctx.str(raw.buildImage, "buildImage"),
|
|
1466
1597
|
productionPaths: ctx.strArray(raw.productionPaths, "productionPaths"),
|
|
1598
|
+
volumes: ctx.strArray(raw.volumes, "volumes"),
|
|
1467
1599
|
runtime: ctx.enumOf(raw.runtime, "runtime", OPENSHIP_RUNTIMES),
|
|
1468
1600
|
productionMode: ctx.enumOf(raw.productionMode, "productionMode", OPENSHIP_PRODUCTION_MODES),
|
|
1469
1601
|
port: ctx.int(raw.port, "port", 1, 65535),
|
|
@@ -1471,6 +1603,7 @@ function parseOpenshipConfig(raw) {
|
|
|
1471
1603
|
domains: parseDomains(ctx, raw.domains, "domains"),
|
|
1472
1604
|
routes: parseRoutes(ctx, raw.routes, "routes"),
|
|
1473
1605
|
resources: parseResources(ctx, raw.resources, "resources"),
|
|
1606
|
+
readiness: parseReadiness(ctx, raw.readiness, "readiness"),
|
|
1474
1607
|
services: parseServices(ctx, raw.services, "services"),
|
|
1475
1608
|
monorepo: parseMonorepo(ctx, raw.monorepo, "monorepo")
|
|
1476
1609
|
};
|
|
@@ -1888,34 +2021,57 @@ function sanitizeProxySettings(input) {
|
|
|
1888
2021
|
return Object.keys(out).length > 0 ? out : void 0;
|
|
1889
2022
|
}
|
|
1890
2023
|
|
|
1891
|
-
// ../../packages/core/src/
|
|
1892
|
-
function
|
|
1893
|
-
|
|
1894
|
-
if (!email3 || email3.length > 254) return false;
|
|
1895
|
-
return /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/.test(email3);
|
|
1896
|
-
}
|
|
1897
|
-
function formatBytes(bytes, decimals = 2) {
|
|
1898
|
-
if (bytes <= 0) return "0 B";
|
|
1899
|
-
const k = 1024;
|
|
1900
|
-
const sizes = ["B", "KB", "MB", "GB", "TB"];
|
|
1901
|
-
const i = Math.min(Math.max(Math.floor(Math.log(bytes) / Math.log(k)), 0), sizes.length - 1);
|
|
1902
|
-
return `${parseFloat((bytes / Math.pow(k, i)).toFixed(decimals))} ${sizes[i]}`;
|
|
2024
|
+
// ../../packages/core/src/object-storage.ts
|
|
2025
|
+
function isAwsS3Endpoint(endpoint2) {
|
|
2026
|
+
return !endpoint2 || endpoint2.includes(".amazonaws.com");
|
|
1903
2027
|
}
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
2028
|
+
|
|
2029
|
+
// ../../packages/core/src/shell-split.ts
|
|
2030
|
+
function shellSplitWords(value) {
|
|
2031
|
+
const words = [];
|
|
2032
|
+
let current = "";
|
|
2033
|
+
let quoted = false;
|
|
2034
|
+
let inSingle = false;
|
|
2035
|
+
let inDouble = false;
|
|
2036
|
+
let escaped = false;
|
|
2037
|
+
for (const char of value.trim()) {
|
|
2038
|
+
if (escaped) {
|
|
2039
|
+
current += char;
|
|
2040
|
+
escaped = false;
|
|
2041
|
+
continue;
|
|
2042
|
+
}
|
|
2043
|
+
if (char === "\\" && !inSingle) {
|
|
2044
|
+
escaped = true;
|
|
2045
|
+
continue;
|
|
2046
|
+
}
|
|
2047
|
+
if (char === "'" && !inDouble) {
|
|
2048
|
+
inSingle = !inSingle;
|
|
2049
|
+
quoted = true;
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
if (char === '"' && !inSingle) {
|
|
2053
|
+
inDouble = !inDouble;
|
|
2054
|
+
quoted = true;
|
|
2055
|
+
continue;
|
|
2056
|
+
}
|
|
2057
|
+
if (/\s/.test(char) && !inSingle && !inDouble) {
|
|
2058
|
+
if (current || quoted) {
|
|
2059
|
+
words.push(current);
|
|
2060
|
+
current = "";
|
|
2061
|
+
quoted = false;
|
|
1916
2062
|
}
|
|
1917
|
-
|
|
1918
|
-
|
|
2063
|
+
continue;
|
|
2064
|
+
}
|
|
2065
|
+
current += char;
|
|
2066
|
+
}
|
|
2067
|
+
if (escaped) current += "\\";
|
|
2068
|
+
if (current || quoted) words.push(current);
|
|
2069
|
+
return words;
|
|
2070
|
+
}
|
|
2071
|
+
function commandToArgv(command) {
|
|
2072
|
+
if (command == null) return null;
|
|
2073
|
+
if (Array.isArray(command)) return command.map((part) => String(part));
|
|
2074
|
+
return shellSplitWords(command);
|
|
1919
2075
|
}
|
|
1920
2076
|
|
|
1921
2077
|
// ../../packages/core/src/runtime-config.ts
|
|
@@ -1977,6 +2133,36 @@ var dashboardRuntimeOrigins = Object.values(DASHBOARD_RUNTIME_TARGETS).flatMap(
|
|
|
1977
2133
|
({ dashboard, api }) => [dashboard, api]
|
|
1978
2134
|
);
|
|
1979
2135
|
|
|
2136
|
+
// ../../packages/core/src/resources.ts
|
|
2137
|
+
var RESOURCE_TIER_ORDER = ["micro", "low", "medium", "high"];
|
|
2138
|
+
var ALL_RESOURCE_TIERS = [
|
|
2139
|
+
"unlimited",
|
|
2140
|
+
...RESOURCE_TIER_ORDER,
|
|
2141
|
+
"custom"
|
|
2142
|
+
];
|
|
2143
|
+
var CLOUD_RESOURCE_TIER_IDS = [
|
|
2144
|
+
...RESOURCE_TIER_ORDER,
|
|
2145
|
+
"custom"
|
|
2146
|
+
];
|
|
2147
|
+
function hasCpuLimit(r) {
|
|
2148
|
+
return typeof r?.cpuCores === "number" && r.cpuCores > 0;
|
|
2149
|
+
}
|
|
2150
|
+
function hasMemoryLimit(r) {
|
|
2151
|
+
return typeof r?.memoryMb === "number" && r.memoryMb > 0;
|
|
2152
|
+
}
|
|
2153
|
+
function formatMemoryMb(mb) {
|
|
2154
|
+
if (!mb || mb <= 0) return "no limit";
|
|
2155
|
+
if (mb >= 1024) return `${(mb / 1024).toFixed(mb % 1024 === 0 ? 0 : 1)} GB`;
|
|
2156
|
+
return `${mb} MB`;
|
|
2157
|
+
}
|
|
2158
|
+
function formatCpuCores(cores) {
|
|
2159
|
+
if (!cores || cores <= 0) return "no limit";
|
|
2160
|
+
return `${cores} vCPU`;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
// ../../packages/core/src/rollback-window.ts
|
|
2164
|
+
var ROLLBACK_DISK_BUDGET_CAP_BYTES = 20 * 1024 * 1024 * 1024;
|
|
2165
|
+
|
|
1980
2166
|
// ../../packages/core/src/workspaces/toml-helpers.ts
|
|
1981
2167
|
function extractStringArrayFromSection(content, sectionPath, key) {
|
|
1982
2168
|
const sectionHeader = new RegExp(
|
|
@@ -2158,14 +2344,33 @@ var goWorkspaceDetector = {
|
|
|
2158
2344
|
};
|
|
2159
2345
|
|
|
2160
2346
|
// ../../packages/core/src/workspaces/gradle.ts
|
|
2347
|
+
function readIncludeArgs(content, start) {
|
|
2348
|
+
let i = start;
|
|
2349
|
+
while (content[i] === " " || content[i] === " ") i++;
|
|
2350
|
+
if (content[i] === "(") {
|
|
2351
|
+
let depth = 0;
|
|
2352
|
+
for (let j = i; j < content.length; j++) {
|
|
2353
|
+
if (content[j] === "(") depth++;
|
|
2354
|
+
else if (content[j] === ")" && --depth === 0) return content.slice(i + 1, j);
|
|
2355
|
+
}
|
|
2356
|
+
return content.slice(i + 1);
|
|
2357
|
+
}
|
|
2358
|
+
let args = "";
|
|
2359
|
+
for (; ; ) {
|
|
2360
|
+
const newline = content.indexOf("\n", i);
|
|
2361
|
+
const line = newline === -1 ? content.slice(i) : content.slice(i, newline);
|
|
2362
|
+
args += line;
|
|
2363
|
+
if (newline === -1 || !line.trimEnd().endsWith(",")) return args;
|
|
2364
|
+
i = newline + 1;
|
|
2365
|
+
}
|
|
2366
|
+
}
|
|
2161
2367
|
function parseGradleSettings(content) {
|
|
2162
2368
|
const cleaned = content.replace(/\/\*[\s\S]*?\*\//g, "").split("\n").map((line) => line.replace(/\/\/.*$/, "")).join("\n");
|
|
2163
2369
|
const paths = [];
|
|
2164
|
-
const includePattern = /
|
|
2370
|
+
const includePattern = /\binclude\b/g;
|
|
2165
2371
|
let match;
|
|
2166
2372
|
while ((match = includePattern.exec(cleaned)) !== null) {
|
|
2167
|
-
const args = match[
|
|
2168
|
-
if (/^Build\b/.test(args)) continue;
|
|
2373
|
+
const args = readIncludeArgs(cleaned, match.index + match[0].length);
|
|
2169
2374
|
const stringPattern = /"([^"]+)"|'([^']+)'/g;
|
|
2170
2375
|
let stringMatch;
|
|
2171
2376
|
while ((stringMatch = stringPattern.exec(args)) !== null) {
|
|
@@ -2190,9 +2395,49 @@ var gradleWorkspaceDetector = {
|
|
|
2190
2395
|
parseSubProjects: parseGradleSettings
|
|
2191
2396
|
};
|
|
2192
2397
|
|
|
2398
|
+
// ../../packages/core/src/workspaces/comments.ts
|
|
2399
|
+
function stripJsonComments(content) {
|
|
2400
|
+
let out = "";
|
|
2401
|
+
let inString = false;
|
|
2402
|
+
for (let i = 0; i < content.length; i++) {
|
|
2403
|
+
const ch = content[i];
|
|
2404
|
+
if (inString) {
|
|
2405
|
+
out += ch;
|
|
2406
|
+
if (ch === "\\") {
|
|
2407
|
+
out += content[++i] ?? "";
|
|
2408
|
+
continue;
|
|
2409
|
+
}
|
|
2410
|
+
if (ch === '"') inString = false;
|
|
2411
|
+
continue;
|
|
2412
|
+
}
|
|
2413
|
+
if (ch === '"') {
|
|
2414
|
+
inString = true;
|
|
2415
|
+
out += ch;
|
|
2416
|
+
continue;
|
|
2417
|
+
}
|
|
2418
|
+
if (ch === "/" && content[i + 1] === "/") {
|
|
2419
|
+
const newline = content.indexOf("\n", i);
|
|
2420
|
+
if (newline === -1) break;
|
|
2421
|
+
i = newline - 1;
|
|
2422
|
+
continue;
|
|
2423
|
+
}
|
|
2424
|
+
if (ch === "/" && content[i + 1] === "*") {
|
|
2425
|
+
const end = content.indexOf("*/", i + 2);
|
|
2426
|
+
if (end === -1) break;
|
|
2427
|
+
i = end + 1;
|
|
2428
|
+
continue;
|
|
2429
|
+
}
|
|
2430
|
+
out += ch;
|
|
2431
|
+
}
|
|
2432
|
+
return out;
|
|
2433
|
+
}
|
|
2434
|
+
function stripXmlComments(content) {
|
|
2435
|
+
return content.replace(/<!--[\s\S]*?-->/g, "");
|
|
2436
|
+
}
|
|
2437
|
+
|
|
2193
2438
|
// ../../packages/core/src/workspaces/maven.ts
|
|
2194
2439
|
function parsePomXml(content) {
|
|
2195
|
-
const modulesBlock = content.match(/<modules\b[^>]*>([\s\S]*?)<\/modules>/i);
|
|
2440
|
+
const modulesBlock = stripXmlComments(content).match(/<modules\b[^>]*>([\s\S]*?)<\/modules>/i);
|
|
2196
2441
|
if (!modulesBlock) return [];
|
|
2197
2442
|
const moduleEntries = modulesBlock[1].matchAll(/<module\b[^>]*>\s*([\s\S]*?)\s*<\/module>/gi);
|
|
2198
2443
|
const paths = [];
|
|
@@ -2289,7 +2534,7 @@ var uvWorkspaceDetector = {
|
|
|
2289
2534
|
function parseRushJson(content) {
|
|
2290
2535
|
let parsed = null;
|
|
2291
2536
|
try {
|
|
2292
|
-
parsed = JSON.parse(content);
|
|
2537
|
+
parsed = JSON.parse(stripJsonComments(content));
|
|
2293
2538
|
} catch {
|
|
2294
2539
|
return [];
|
|
2295
2540
|
}
|
|
@@ -2367,8 +2612,11 @@ var dockerLanguageDetector = {
|
|
|
2367
2612
|
// ../../packages/core/src/languages/elixir.ts
|
|
2368
2613
|
function parseMixExs2(content) {
|
|
2369
2614
|
const deps = {};
|
|
2370
|
-
for (const
|
|
2371
|
-
|
|
2615
|
+
for (const line of content.split("\n")) {
|
|
2616
|
+
if (line.trim().startsWith("#")) continue;
|
|
2617
|
+
for (const m of line.matchAll(/\{:([\w]+),/g)) {
|
|
2618
|
+
deps[m[1]] = "*";
|
|
2619
|
+
}
|
|
2372
2620
|
}
|
|
2373
2621
|
return deps;
|
|
2374
2622
|
}
|
|
@@ -2416,6 +2664,34 @@ function clampPort(raw) {
|
|
|
2416
2664
|
const port = parseInt(raw, 10);
|
|
2417
2665
|
return port > 0 && port <= 65535 ? port : null;
|
|
2418
2666
|
}
|
|
2667
|
+
var YAML_PORT_RE = /^port:\s*["']?(\d{2,5})/;
|
|
2668
|
+
function springYamlPort(yml) {
|
|
2669
|
+
const inline = yml.match(/^server:\s*\{[^}]*\bport:\s*["']?(\d{2,5})/m);
|
|
2670
|
+
if (inline) return inline[1];
|
|
2671
|
+
let inServer = false;
|
|
2672
|
+
let childIndent = null;
|
|
2673
|
+
for (const raw of yml.split("\n")) {
|
|
2674
|
+
const trimmed2 = raw.trim();
|
|
2675
|
+
if (!trimmed2 || trimmed2.startsWith("#")) continue;
|
|
2676
|
+
const indent = raw.length - raw.trimStart().length;
|
|
2677
|
+
if (inServer) {
|
|
2678
|
+
if (indent > 0) {
|
|
2679
|
+
if (childIndent === null) childIndent = indent;
|
|
2680
|
+
if (indent === childIndent) {
|
|
2681
|
+
const m = trimmed2.match(YAML_PORT_RE);
|
|
2682
|
+
if (m) return m[1];
|
|
2683
|
+
}
|
|
2684
|
+
continue;
|
|
2685
|
+
}
|
|
2686
|
+
inServer = false;
|
|
2687
|
+
}
|
|
2688
|
+
if (indent === 0 && /^server:$/.test(trimmed2)) {
|
|
2689
|
+
inServer = true;
|
|
2690
|
+
childIndent = null;
|
|
2691
|
+
}
|
|
2692
|
+
}
|
|
2693
|
+
return null;
|
|
2694
|
+
}
|
|
2419
2695
|
function detectJavaPort(context) {
|
|
2420
2696
|
const fc = context.fileContents;
|
|
2421
2697
|
if (!fc) return null;
|
|
@@ -2427,8 +2703,8 @@ function detectJavaPort(context) {
|
|
|
2427
2703
|
for (const name of ["application.yml", "application.yaml"]) {
|
|
2428
2704
|
const yml = fc[name];
|
|
2429
2705
|
if (!yml) continue;
|
|
2430
|
-
const
|
|
2431
|
-
if (
|
|
2706
|
+
const port = springYamlPort(yml) ?? yml.match(/^port:\s*["']?(\d{2,5})/m)?.[1];
|
|
2707
|
+
if (port) return clampPort(port);
|
|
2432
2708
|
}
|
|
2433
2709
|
return null;
|
|
2434
2710
|
}
|
|
@@ -2515,11 +2791,30 @@ function parseRequirementsTxt(content) {
|
|
|
2515
2791
|
}
|
|
2516
2792
|
return deps;
|
|
2517
2793
|
}
|
|
2794
|
+
function sliceArrayValue(body, key) {
|
|
2795
|
+
const open = body.match(new RegExp(`(?:^|\\n)\\s*${key}\\s*=\\s*\\[`));
|
|
2796
|
+
if (!open || open.index === void 0) return null;
|
|
2797
|
+
const from = open.index + open[0].length;
|
|
2798
|
+
let depth = 1;
|
|
2799
|
+
let quote = null;
|
|
2800
|
+
for (let i = from; i < body.length; i++) {
|
|
2801
|
+
const char = body[i];
|
|
2802
|
+
if (quote) {
|
|
2803
|
+
if (char === quote) quote = null;
|
|
2804
|
+
continue;
|
|
2805
|
+
}
|
|
2806
|
+
if (char === '"' || char === "'") quote = char;
|
|
2807
|
+
else if (char === "[") depth++;
|
|
2808
|
+
else if (char === "]" && --depth === 0) return body.slice(from, i);
|
|
2809
|
+
}
|
|
2810
|
+
return null;
|
|
2811
|
+
}
|
|
2518
2812
|
function parsePyprojectToml(content) {
|
|
2519
2813
|
const deps = {};
|
|
2520
|
-
const
|
|
2521
|
-
|
|
2522
|
-
|
|
2814
|
+
const project = content.match(/\[project\]([\s\S]*?)(?=\n\[|$)/);
|
|
2815
|
+
const pep621 = project ? sliceArrayValue(project[1], "dependencies") : null;
|
|
2816
|
+
if (pep621 !== null) {
|
|
2817
|
+
const items = pep621.matchAll(/["']([^"']+)["']/g);
|
|
2523
2818
|
for (const item of items) {
|
|
2524
2819
|
const m = item[1].match(/^([A-Za-z0-9][A-Za-z0-9._-]*)/);
|
|
2525
2820
|
if (m) deps[normalizeName(m[1])] = "*";
|
|
@@ -2576,8 +2871,11 @@ var pythonLanguageDetector = {
|
|
|
2576
2871
|
// ../../packages/core/src/languages/ruby.ts
|
|
2577
2872
|
function parseGemfile(content) {
|
|
2578
2873
|
const deps = {};
|
|
2579
|
-
for (const
|
|
2580
|
-
|
|
2874
|
+
for (const line of content.split("\n")) {
|
|
2875
|
+
if (line.trim().startsWith("#")) continue;
|
|
2876
|
+
for (const m of line.matchAll(/gem\s+['"]([^'"]+)['"]/g)) {
|
|
2877
|
+
deps[m[1].toLowerCase()] = "*";
|
|
2878
|
+
}
|
|
2581
2879
|
}
|
|
2582
2880
|
return deps;
|
|
2583
2881
|
}
|
|
@@ -4060,7 +4358,7 @@ var catalog_default = {
|
|
|
4060
4358
|
verified: true,
|
|
4061
4359
|
id: "minio",
|
|
4062
4360
|
name: "MinIO",
|
|
4063
|
-
description: "S3-compatible object storage with a web console \u2014 point any S3 client (aws-cli, SDKs) at it.",
|
|
4361
|
+
description: "S3-compatible object storage with a web console \u2014 point any S3 client (aws-cli, SDKs) at it, or bind a bucket straight into another project's uploads.",
|
|
4064
4362
|
kind: "template",
|
|
4065
4363
|
logo: "minio",
|
|
4066
4364
|
category: "database",
|
|
@@ -4119,6 +4417,29 @@ var catalog_default = {
|
|
|
4119
4417
|
help: "Auto-generated. The S3 admin secret \u2014 shown once after install.",
|
|
4120
4418
|
generate: "secret",
|
|
4121
4419
|
secret: true
|
|
4420
|
+
},
|
|
4421
|
+
{
|
|
4422
|
+
key: "OPENSHIP_BUCKET",
|
|
4423
|
+
service: "minio",
|
|
4424
|
+
label: "First bucket",
|
|
4425
|
+
help: "Created on the first deploy so an app can use this storage immediately. More can be added from the console.",
|
|
4426
|
+
type: "text",
|
|
4427
|
+
default: "uploads",
|
|
4428
|
+
required: true
|
|
4429
|
+
}
|
|
4430
|
+
],
|
|
4431
|
+
prepare: [
|
|
4432
|
+
{
|
|
4433
|
+
service: "minio",
|
|
4434
|
+
command: `mc alias set local http://127.0.0.1:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD" > /dev/null && mc mb --ignore-existing "local/$OPENSHIP_BUCKET" > /dev/null && printf '%s' "$OPENSHIP_BUCKET"`,
|
|
4435
|
+
capture: "bucket",
|
|
4436
|
+
phase: "post-ready",
|
|
4437
|
+
readiness: {
|
|
4438
|
+
test: 'mc alias set local http://127.0.0.1:9000 "$MINIO_ROOT_USER" "$MINIO_ROOT_PASSWORD"',
|
|
4439
|
+
interval: 1e3,
|
|
4440
|
+
retries: 30
|
|
4441
|
+
},
|
|
4442
|
+
once: true
|
|
4122
4443
|
}
|
|
4123
4444
|
],
|
|
4124
4445
|
endpoints: [
|
|
@@ -4147,21 +4468,54 @@ var catalog_default = {
|
|
|
4147
4468
|
{
|
|
4148
4469
|
id: "endpoint",
|
|
4149
4470
|
label: "S3 endpoint",
|
|
4150
|
-
source: "publicUrl:minio:9000"
|
|
4471
|
+
source: "publicUrl:minio:9000",
|
|
4472
|
+
service: "minio",
|
|
4473
|
+
envKey: "S3_ENDPOINT",
|
|
4474
|
+
recommended: true
|
|
4151
4475
|
},
|
|
4152
4476
|
{
|
|
4153
4477
|
id: "accessKey",
|
|
4154
4478
|
label: "Access key",
|
|
4155
|
-
source: "env:minio:MINIO_ROOT_USER"
|
|
4479
|
+
source: "env:minio:MINIO_ROOT_USER",
|
|
4480
|
+
service: "minio",
|
|
4481
|
+
envKey: "S3_ACCESS_KEY_ID",
|
|
4482
|
+
recommended: true
|
|
4156
4483
|
},
|
|
4157
4484
|
{
|
|
4158
4485
|
id: "secretKey",
|
|
4159
4486
|
label: "Secret key",
|
|
4160
4487
|
source: "env:minio:MINIO_ROOT_PASSWORD",
|
|
4161
|
-
|
|
4488
|
+
service: "minio",
|
|
4489
|
+
envKey: "S3_SECRET_ACCESS_KEY",
|
|
4490
|
+
secret: true,
|
|
4491
|
+
recommended: true
|
|
4492
|
+
},
|
|
4493
|
+
{
|
|
4494
|
+
id: "bucket",
|
|
4495
|
+
label: "Bucket",
|
|
4496
|
+
source: "env:minio:OPENSHIP_BUCKET",
|
|
4497
|
+
service: "minio",
|
|
4498
|
+
envKey: "S3_BUCKET"
|
|
4162
4499
|
}
|
|
4163
|
-
]
|
|
4164
|
-
|
|
4500
|
+
],
|
|
4501
|
+
guide: {
|
|
4502
|
+
intro: "Your app gets an S3-compatible bucket it can write uploads to.",
|
|
4503
|
+
useHint: "Bind it from the consuming project's Configuration \u2192 Object storage to get the framework's own env names (Laravel gets FILESYSTEM_DISK + AWS_*), or wire these values by hand.",
|
|
4504
|
+
defaultMode: "internal"
|
|
4505
|
+
}
|
|
4506
|
+
},
|
|
4507
|
+
provides: [
|
|
4508
|
+
{
|
|
4509
|
+
id: "s3",
|
|
4510
|
+
outputRefs: [
|
|
4511
|
+
"endpoint",
|
|
4512
|
+
"accessKey",
|
|
4513
|
+
"secretKey",
|
|
4514
|
+
"bucket"
|
|
4515
|
+
],
|
|
4516
|
+
category: "database"
|
|
4517
|
+
}
|
|
4518
|
+
]
|
|
4165
4519
|
},
|
|
4166
4520
|
{
|
|
4167
4521
|
available: true,
|
|
@@ -19143,9 +19497,14 @@ export {
|
|
|
19143
19497
|
buildOutputTransferExcludes,
|
|
19144
19498
|
PACKAGE_ROOT_ONLY_EXCLUDES,
|
|
19145
19499
|
packageManagerEnsureCommand,
|
|
19500
|
+
appVolumeTargets,
|
|
19501
|
+
isAwsS3Endpoint,
|
|
19146
19502
|
DEFAULT_IMAGE_REGISTRY,
|
|
19503
|
+
shellSplitWords,
|
|
19504
|
+
commandToArgv,
|
|
19147
19505
|
buildEdgeImageRef,
|
|
19148
19506
|
SYSTEM,
|
|
19507
|
+
resolveRedirectStatus,
|
|
19149
19508
|
isValidEmail,
|
|
19150
19509
|
formatBytes,
|
|
19151
19510
|
withTimeout,
|
|
@@ -19155,6 +19514,10 @@ export {
|
|
|
19155
19514
|
LOCAL_DASHBOARD_URL,
|
|
19156
19515
|
LOCAL_API_URL,
|
|
19157
19516
|
CLOUD_DASHBOARD_URL,
|
|
19517
|
+
hasCpuLimit,
|
|
19518
|
+
hasMemoryLimit,
|
|
19519
|
+
formatMemoryMb,
|
|
19520
|
+
formatCpuCores,
|
|
19158
19521
|
parseOpenshipConfigJson,
|
|
19159
19522
|
missingOutputDirectoryMessage,
|
|
19160
19523
|
compareSemver,
|