@open-mercato/cli 0.6.5-develop.4477.1.7a250f91b8 → 0.6.5-develop.4498.1.55dc06a57c
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.
|
@@ -7,6 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { createInterface } from "node:readline/promises";
|
|
8
8
|
import { stdin as input, stdout as output } from "node:process";
|
|
9
9
|
import spawn from "cross-spawn";
|
|
10
|
+
import { fetchWithTimeout } from "@open-mercato/shared/lib/http/fetchWithTimeout";
|
|
10
11
|
import { resolveEnvironment } from "../resolver.js";
|
|
11
12
|
import { resolveSpawnCommand } from "../spawn.js";
|
|
12
13
|
import { discoverIntegrationSpecFiles as discoverIntegrationSpecFilesShared } from "./integration-discovery.js";
|
|
@@ -468,6 +469,10 @@ function delay(milliseconds) {
|
|
|
468
469
|
setTimeout(resolve, milliseconds);
|
|
469
470
|
});
|
|
470
471
|
}
|
|
472
|
+
const READINESS_PROBE_FETCH_TIMEOUT_MS = 15e3;
|
|
473
|
+
function probeFetch(input2, init = {}) {
|
|
474
|
+
return fetchWithTimeout(input2, { timeoutMs: READINESS_PROBE_FETCH_TIMEOUT_MS, ...init });
|
|
475
|
+
}
|
|
471
476
|
function resolveBuildCacheTtlSeconds(logPrefix) {
|
|
472
477
|
const rawValue = process.env[BUILD_CACHE_TTL_ENV_VAR];
|
|
473
478
|
if (!rawValue) {
|
|
@@ -885,7 +890,7 @@ function isSuccessfulBrowserNavigationStatus(status) {
|
|
|
885
890
|
}
|
|
886
891
|
async function probeLoginPage(baseUrl) {
|
|
887
892
|
try {
|
|
888
|
-
const response = await
|
|
893
|
+
const response = await probeFetch(`${baseUrl}/login`, {
|
|
889
894
|
method: "GET",
|
|
890
895
|
redirect: "manual"
|
|
891
896
|
});
|
|
@@ -930,7 +935,7 @@ async function probeBackendLoginEndpoint(baseUrl) {
|
|
|
930
935
|
const form = new URLSearchParams();
|
|
931
936
|
form.set("email", "integration-healthcheck@example.invalid");
|
|
932
937
|
form.set("password", "invalid-password");
|
|
933
|
-
const response = await
|
|
938
|
+
const response = await probeFetch(`${baseUrl}/api/auth/login`, {
|
|
934
939
|
method: "POST",
|
|
935
940
|
redirect: "manual",
|
|
936
941
|
headers: {
|
|
@@ -958,7 +963,7 @@ async function probeAuthenticatedApi(baseUrl) {
|
|
|
958
963
|
const form = new URLSearchParams();
|
|
959
964
|
form.set("email", "admin@acme.com");
|
|
960
965
|
form.set("password", "secret");
|
|
961
|
-
const loginResponse = await
|
|
966
|
+
const loginResponse = await probeFetch(`${baseUrl}/api/auth/login`, {
|
|
962
967
|
method: "POST",
|
|
963
968
|
redirect: "manual",
|
|
964
969
|
headers: {
|
|
@@ -984,7 +989,7 @@ async function probeAuthenticatedApi(baseUrl) {
|
|
|
984
989
|
detail: loginResponse.ok ? "POST /api/auth/login did not return an auth token" : `POST /api/auth/login returned ${loginResponse.status}`
|
|
985
990
|
};
|
|
986
991
|
}
|
|
987
|
-
const apiResponse = await
|
|
992
|
+
const apiResponse = await probeFetch(`${baseUrl}/api/customers/people?pageSize=1`, {
|
|
988
993
|
headers: {
|
|
989
994
|
Authorization: `Bearer ${token}`
|
|
990
995
|
}
|
|
@@ -1288,22 +1293,33 @@ async function tryReuseExistingEnvironment(options) {
|
|
|
1288
1293
|
}
|
|
1289
1294
|
async function waitForApplicationReadiness(baseUrl, appProcess, options) {
|
|
1290
1295
|
const startTimestamp = Date.now();
|
|
1291
|
-
const
|
|
1292
|
-
const readinessStabilizationMs = 600;
|
|
1296
|
+
const intervalMs = options.intervalMs ?? APP_READY_INTERVAL_MS;
|
|
1297
|
+
const readinessStabilizationMs = options.stabilizationMs ?? 600;
|
|
1293
1298
|
let lastProbe = null;
|
|
1299
|
+
let exitCode = null;
|
|
1300
|
+
const exitSignal = getProcessExitPromise(appProcess).then(
|
|
1301
|
+
(code) => {
|
|
1302
|
+
exitCode = code ?? null;
|
|
1303
|
+
return { exited: true };
|
|
1304
|
+
},
|
|
1305
|
+
() => {
|
|
1306
|
+
exitCode = null;
|
|
1307
|
+
return { exited: true };
|
|
1308
|
+
}
|
|
1309
|
+
);
|
|
1310
|
+
const exitError = () => new Error(`Application process exited before readiness check (exit ${exitCode ?? "unknown"})`);
|
|
1294
1311
|
while (Date.now() - startTimestamp < options.timeoutMs) {
|
|
1295
|
-
const
|
|
1296
|
-
probeApplicationReadiness(baseUrl).then((probe) => ({
|
|
1297
|
-
|
|
1298
|
-
delay(APP_READY_INTERVAL_MS).then(() => ({ kind: "timeout" }))
|
|
1312
|
+
const cycle = await Promise.race([
|
|
1313
|
+
probeApplicationReadiness(baseUrl).then((probe) => ({ probe })),
|
|
1314
|
+
exitSignal
|
|
1299
1315
|
]);
|
|
1300
|
-
if (
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1316
|
+
if ("exited" in cycle) {
|
|
1317
|
+
throw exitError();
|
|
1318
|
+
}
|
|
1319
|
+
lastProbe = cycle.probe;
|
|
1320
|
+
if (cycle.probe.ready) {
|
|
1305
1321
|
const processExited = await Promise.race([
|
|
1306
|
-
|
|
1322
|
+
exitSignal.then(() => true),
|
|
1307
1323
|
delay(readinessStabilizationMs).then(() => false)
|
|
1308
1324
|
]);
|
|
1309
1325
|
if (processExited) {
|
|
@@ -1311,8 +1327,14 @@ async function waitForApplicationReadiness(baseUrl, appProcess, options) {
|
|
|
1311
1327
|
}
|
|
1312
1328
|
return;
|
|
1313
1329
|
}
|
|
1314
|
-
|
|
1315
|
-
|
|
1330
|
+
const remainingMs = options.timeoutMs - (Date.now() - startTimestamp);
|
|
1331
|
+
if (remainingMs <= 0) break;
|
|
1332
|
+
const waited = await Promise.race([
|
|
1333
|
+
exitSignal,
|
|
1334
|
+
delay(Math.min(intervalMs, remainingMs)).then(() => null)
|
|
1335
|
+
]);
|
|
1336
|
+
if (waited && "exited" in waited) {
|
|
1337
|
+
throw exitError();
|
|
1316
1338
|
}
|
|
1317
1339
|
}
|
|
1318
1340
|
const lastFrontendDetail = lastProbe?.frontend.detail ?? "GET /login was never observed";
|
|
@@ -2738,6 +2760,7 @@ export {
|
|
|
2738
2760
|
shouldUseIsolatedPortForFreshEnvironment,
|
|
2739
2761
|
startEphemeralEnvironment,
|
|
2740
2762
|
tryReuseExistingEnvironment,
|
|
2763
|
+
waitForApplicationReadiness,
|
|
2741
2764
|
writeEphemeralEnvironmentState
|
|
2742
2765
|
};
|
|
2743
2766
|
//# sourceMappingURL=integration.js.map
|