@open-mercato/cli 0.6.6-develop.6460.1.f94c74174c → 0.6.6-develop.6471.1.9ab5bdd79a
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/.turbo/turbo-build.log +3 -3
- package/dist/agentic/guides/module-facts.json +53 -53
- package/dist/agentic/guides/modules/ai_assistant.md +1 -1
- package/dist/agentic/guides/modules/api_docs.md +1 -1
- package/dist/agentic/guides/modules/api_keys.md +1 -1
- package/dist/agentic/guides/modules/attachments.md +1 -1
- package/dist/agentic/guides/modules/audit_logs.md +1 -1
- package/dist/agentic/guides/modules/auth.md +1 -1
- package/dist/agentic/guides/modules/business_rules.md +1 -1
- package/dist/agentic/guides/modules/catalog.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail.md +1 -1
- package/dist/agentic/guides/modules/channel_imap.md +1 -1
- package/dist/agentic/guides/modules/checkout.md +1 -1
- package/dist/agentic/guides/modules/communication_channels.md +1 -1
- package/dist/agentic/guides/modules/configs.md +1 -1
- package/dist/agentic/guides/modules/content.md +1 -1
- package/dist/agentic/guides/modules/currencies.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts.md +1 -1
- package/dist/agentic/guides/modules/customers.md +1 -1
- package/dist/agentic/guides/modules/dashboards.md +1 -1
- package/dist/agentic/guides/modules/data_sync.md +1 -1
- package/dist/agentic/guides/modules/dictionaries.md +1 -1
- package/dist/agentic/guides/modules/directory.md +1 -1
- package/dist/agentic/guides/modules/entities.md +1 -1
- package/dist/agentic/guides/modules/events.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe.md +1 -1
- package/dist/agentic/guides/modules/generators.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops.md +1 -1
- package/dist/agentic/guides/modules/integrations.md +1 -1
- package/dist/agentic/guides/modules/messages.md +1 -1
- package/dist/agentic/guides/modules/notifications.md +1 -1
- package/dist/agentic/guides/modules/onboarding.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways.md +1 -1
- package/dist/agentic/guides/modules/perspectives.md +1 -1
- package/dist/agentic/guides/modules/planner.md +1 -1
- package/dist/agentic/guides/modules/portal.md +1 -1
- package/dist/agentic/guides/modules/progress.md +1 -1
- package/dist/agentic/guides/modules/query_index.md +1 -1
- package/dist/agentic/guides/modules/record_locks.md +1 -1
- package/dist/agentic/guides/modules/resources.md +1 -1
- package/dist/agentic/guides/modules/sales.md +1 -1
- package/dist/agentic/guides/modules/scheduler.md +1 -1
- package/dist/agentic/guides/modules/search.md +1 -1
- package/dist/agentic/guides/modules/security.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers.md +1 -1
- package/dist/agentic/guides/modules/sso.md +1 -1
- package/dist/agentic/guides/modules/staff.md +1 -1
- package/dist/agentic/guides/modules/storage_s3.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo.md +1 -1
- package/dist/agentic/guides/modules/sync_excel.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays.md +1 -1
- package/dist/agentic/guides/modules/translations.md +1 -1
- package/dist/agentic/guides/modules/webhooks.md +1 -1
- package/dist/agentic/guides/modules/workflows.md +1 -1
- package/dist/lib/testing/integration.js +185 -5
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +2 -0
- package/dist/mercato.js.map +2 -2
- package/package.json +5 -5
- package/src/lib/testing/__tests__/integration.test.ts +228 -6
- package/src/lib/testing/integration.ts +231 -3
- package/src/mercato.ts +7 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# feature_toggles — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.6.6-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.6.6-develop.6471.1.9ab5bdd79a — R1 staleness stamp -->
|
|
3
3
|
|
|
4
4
|
## Entities
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# gateway_stripe — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.6.6-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.6.6-develop.6471.1.9ab5bdd79a — R1 staleness stamp -->
|
|
3
3
|
|
|
4
4
|
## Entities
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# payment_gateways — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.6.6-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.6.6-develop.6471.1.9ab5bdd79a — R1 staleness stamp -->
|
|
3
3
|
|
|
4
4
|
## Entities
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# shipping_carriers — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.6.6-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.6.6-develop.6471.1.9ab5bdd79a — R1 staleness stamp -->
|
|
3
3
|
|
|
4
4
|
## Entities
|
|
5
5
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# system_status_overlays — module facts (generated, do not edit)
|
|
2
|
-
<!-- generated from @open-mercato/core 0.6.6-develop.
|
|
2
|
+
<!-- generated from @open-mercato/core 0.6.6-develop.6471.1.9ab5bdd79a — R1 staleness stamp -->
|
|
3
3
|
|
|
4
4
|
## Entities
|
|
5
5
|
|
|
@@ -165,6 +165,7 @@ const FOLDER_TO_CATEGORY_CODE = {
|
|
|
165
165
|
api: "API",
|
|
166
166
|
integration: "INT"
|
|
167
167
|
};
|
|
168
|
+
const BACKEND_BROWSER_AUTH_REDIRECT_LIMIT = 6;
|
|
168
169
|
const BUILD_CACHE_STATE_VERSION = 2;
|
|
169
170
|
const BUILD_CACHE_ENV_KEYS = [
|
|
170
171
|
"NODE_ENV",
|
|
@@ -1064,17 +1065,195 @@ async function probeAuthenticatedApi(baseUrl) {
|
|
|
1064
1065
|
};
|
|
1065
1066
|
}
|
|
1066
1067
|
}
|
|
1068
|
+
function splitSetCookieHeader(header) {
|
|
1069
|
+
return header.split(/,(?=\s*[^;,\s=]+=)/).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
1070
|
+
}
|
|
1071
|
+
function getSetCookieHeaders(headers) {
|
|
1072
|
+
if (!headers) {
|
|
1073
|
+
return [];
|
|
1074
|
+
}
|
|
1075
|
+
const setCookieGetter = headers.getSetCookie;
|
|
1076
|
+
if (typeof setCookieGetter === "function") {
|
|
1077
|
+
return setCookieGetter.call(headers).map((value) => value.trim()).filter((value) => value.length > 0);
|
|
1078
|
+
}
|
|
1079
|
+
const combined = headers.get("set-cookie");
|
|
1080
|
+
return combined ? splitSetCookieHeader(combined) : [];
|
|
1081
|
+
}
|
|
1082
|
+
function parseSetCookiePair(header) {
|
|
1083
|
+
const pair = header.split(";", 1)[0]?.trim();
|
|
1084
|
+
if (!pair) {
|
|
1085
|
+
return null;
|
|
1086
|
+
}
|
|
1087
|
+
const equalsIndex = pair.indexOf("=");
|
|
1088
|
+
if (equalsIndex <= 0) {
|
|
1089
|
+
return null;
|
|
1090
|
+
}
|
|
1091
|
+
const name = pair.slice(0, equalsIndex).trim();
|
|
1092
|
+
if (!name) {
|
|
1093
|
+
return null;
|
|
1094
|
+
}
|
|
1095
|
+
return {
|
|
1096
|
+
name,
|
|
1097
|
+
value: pair.slice(equalsIndex + 1)
|
|
1098
|
+
};
|
|
1099
|
+
}
|
|
1100
|
+
function addSetCookieHeadersToJar(jar, headers) {
|
|
1101
|
+
for (const setCookieHeader of getSetCookieHeaders(headers)) {
|
|
1102
|
+
const pair = parseSetCookiePair(setCookieHeader);
|
|
1103
|
+
if (pair) {
|
|
1104
|
+
jar.set(pair.name, pair.value);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
function serializeCookieJar(jar) {
|
|
1109
|
+
return [...jar.entries()].map(([name, value]) => `${name}=${value}`).join("; ");
|
|
1110
|
+
}
|
|
1111
|
+
function formatCookieNames(jar) {
|
|
1112
|
+
const names = [...jar.keys()].sort((left, right) => left.localeCompare(right));
|
|
1113
|
+
return names.length > 0 ? names.join(", ") : "none";
|
|
1114
|
+
}
|
|
1115
|
+
function toReadinessPath(url) {
|
|
1116
|
+
return url.pathname || "/";
|
|
1117
|
+
}
|
|
1118
|
+
function resolveReadinessRedirect(baseUrl, currentUrl, rawLocation) {
|
|
1119
|
+
const location = rawLocation?.trim();
|
|
1120
|
+
if (!location) {
|
|
1121
|
+
return { error: "missing Location header" };
|
|
1122
|
+
}
|
|
1123
|
+
if (location.startsWith("//")) {
|
|
1124
|
+
return { error: "protocol-relative redirect" };
|
|
1125
|
+
}
|
|
1126
|
+
let nextUrl;
|
|
1127
|
+
try {
|
|
1128
|
+
nextUrl = new URL(location, currentUrl);
|
|
1129
|
+
} catch {
|
|
1130
|
+
return { error: "invalid Location header" };
|
|
1131
|
+
}
|
|
1132
|
+
if (nextUrl.origin !== baseUrl.origin) {
|
|
1133
|
+
return { error: "cross-origin redirect" };
|
|
1134
|
+
}
|
|
1135
|
+
return {
|
|
1136
|
+
url: nextUrl,
|
|
1137
|
+
path: toReadinessPath(nextUrl)
|
|
1138
|
+
};
|
|
1139
|
+
}
|
|
1140
|
+
async function probeBackendBrowserAuth(baseUrl) {
|
|
1141
|
+
try {
|
|
1142
|
+
const base = new URL(baseUrl);
|
|
1143
|
+
const form = new URLSearchParams();
|
|
1144
|
+
form.set("email", "admin@acme.com");
|
|
1145
|
+
form.set("password", "secret");
|
|
1146
|
+
const loginResponse = await probeFetch(`${baseUrl}/api/auth/login`, {
|
|
1147
|
+
method: "POST",
|
|
1148
|
+
redirect: "manual",
|
|
1149
|
+
headers: {
|
|
1150
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
1151
|
+
},
|
|
1152
|
+
body: form.toString()
|
|
1153
|
+
});
|
|
1154
|
+
if (!loginResponse.ok) {
|
|
1155
|
+
return {
|
|
1156
|
+
loginStatus: loginResponse.status,
|
|
1157
|
+
backendStatus: null,
|
|
1158
|
+
healthy: false,
|
|
1159
|
+
detail: `Backend browser auth login returned ${loginResponse.status}`
|
|
1160
|
+
};
|
|
1161
|
+
}
|
|
1162
|
+
const cookieJar = /* @__PURE__ */ new Map();
|
|
1163
|
+
addSetCookieHeadersToJar(cookieJar, loginResponse.headers);
|
|
1164
|
+
if (cookieJar.size === 0) {
|
|
1165
|
+
return {
|
|
1166
|
+
loginStatus: loginResponse.status,
|
|
1167
|
+
backendStatus: null,
|
|
1168
|
+
healthy: false,
|
|
1169
|
+
detail: "Backend browser auth login returned no cookies"
|
|
1170
|
+
};
|
|
1171
|
+
}
|
|
1172
|
+
let currentUrl = new URL("/backend", base);
|
|
1173
|
+
let backendStatus = null;
|
|
1174
|
+
const visitedPaths = /* @__PURE__ */ new Set();
|
|
1175
|
+
const trace = [];
|
|
1176
|
+
for (let redirectCount = 0; redirectCount <= BACKEND_BROWSER_AUTH_REDIRECT_LIMIT; redirectCount += 1) {
|
|
1177
|
+
const currentPath = toReadinessPath(currentUrl);
|
|
1178
|
+
visitedPaths.add(currentPath);
|
|
1179
|
+
const response = await probeFetch(currentUrl.toString(), {
|
|
1180
|
+
method: "GET",
|
|
1181
|
+
redirect: "manual",
|
|
1182
|
+
headers: {
|
|
1183
|
+
Cookie: serializeCookieJar(cookieJar)
|
|
1184
|
+
}
|
|
1185
|
+
});
|
|
1186
|
+
backendStatus = response.status;
|
|
1187
|
+
addSetCookieHeadersToJar(cookieJar, response.headers);
|
|
1188
|
+
const location = response.headers?.get("location") ?? null;
|
|
1189
|
+
const traceRedirect = location ? resolveReadinessRedirect(base, currentUrl, location) : null;
|
|
1190
|
+
const statusAndLocation = traceRedirect && !("error" in traceRedirect) ? `${currentPath} ${response.status} -> ${traceRedirect.path}` : `${currentPath} ${response.status}${location ? " -> [unsafe]" : ""}`;
|
|
1191
|
+
trace.push(statusAndLocation);
|
|
1192
|
+
if (response.status === 200 && currentPath === "/backend") {
|
|
1193
|
+
return {
|
|
1194
|
+
loginStatus: loginResponse.status,
|
|
1195
|
+
backendStatus,
|
|
1196
|
+
healthy: true,
|
|
1197
|
+
detail: `Cookie-backed GET /backend returned 200 (cookies: ${formatCookieNames(cookieJar)})`
|
|
1198
|
+
};
|
|
1199
|
+
}
|
|
1200
|
+
if (response.status < 300 || response.status >= 400) {
|
|
1201
|
+
return {
|
|
1202
|
+
loginStatus: loginResponse.status,
|
|
1203
|
+
backendStatus,
|
|
1204
|
+
healthy: false,
|
|
1205
|
+
detail: `Cookie-backed GET ${currentPath} returned ${response.status} (cookies: ${formatCookieNames(cookieJar)}; trace: ${trace.join(" | ")})`
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
const redirect = traceRedirect ?? resolveReadinessRedirect(base, currentUrl, location);
|
|
1209
|
+
if ("error" in redirect) {
|
|
1210
|
+
return {
|
|
1211
|
+
loginStatus: loginResponse.status,
|
|
1212
|
+
backendStatus,
|
|
1213
|
+
healthy: false,
|
|
1214
|
+
detail: `Backend browser auth probe followed unsafe redirect: ${redirect.error} (cookies: ${formatCookieNames(cookieJar)}; trace: ${trace.join(" | ")})`
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
if (visitedPaths.has(redirect.path)) {
|
|
1218
|
+
trace.push(redirect.path);
|
|
1219
|
+
return {
|
|
1220
|
+
loginStatus: loginResponse.status,
|
|
1221
|
+
backendStatus,
|
|
1222
|
+
healthy: false,
|
|
1223
|
+
detail: `Backend browser auth probe detected redirect loop: ${trace.join(" | ")} (cookies: ${formatCookieNames(cookieJar)})`
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
currentUrl = redirect.url;
|
|
1227
|
+
}
|
|
1228
|
+
return {
|
|
1229
|
+
loginStatus: loginResponse.status,
|
|
1230
|
+
backendStatus,
|
|
1231
|
+
healthy: false,
|
|
1232
|
+
detail: `Backend browser auth probe exceeded ${BACKEND_BROWSER_AUTH_REDIRECT_LIMIT} redirects (cookies: ${formatCookieNames(cookieJar)}; trace: ${trace.join(" | ")})`
|
|
1233
|
+
};
|
|
1234
|
+
} catch (error) {
|
|
1235
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1236
|
+
return {
|
|
1237
|
+
loginStatus: null,
|
|
1238
|
+
backendStatus: null,
|
|
1239
|
+
healthy: false,
|
|
1240
|
+
detail: `Backend browser auth probe failed: ${message}`
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1067
1244
|
async function probeApplicationReadiness(baseUrl) {
|
|
1068
|
-
const [frontend, backend, authenticated] = await Promise.all([
|
|
1245
|
+
const [frontend, backend, authenticated, backendBrowserAuth] = await Promise.all([
|
|
1069
1246
|
probeLoginPage(baseUrl),
|
|
1070
1247
|
probeBackendLoginEndpoint(baseUrl),
|
|
1071
|
-
probeAuthenticatedApi(baseUrl)
|
|
1248
|
+
probeAuthenticatedApi(baseUrl),
|
|
1249
|
+
probeBackendBrowserAuth(baseUrl)
|
|
1072
1250
|
]);
|
|
1073
1251
|
return {
|
|
1074
|
-
ready: frontend.healthy && backend.healthy && authenticated.healthy,
|
|
1252
|
+
ready: frontend.healthy && backend.healthy && authenticated.healthy && backendBrowserAuth.healthy,
|
|
1075
1253
|
frontend,
|
|
1076
1254
|
backend,
|
|
1077
|
-
authenticated
|
|
1255
|
+
authenticated,
|
|
1256
|
+
backendBrowserAuth
|
|
1078
1257
|
};
|
|
1079
1258
|
}
|
|
1080
1259
|
async function acquireEphemeralEnvironmentLock(logPrefix) {
|
|
@@ -1421,8 +1600,9 @@ async function waitForApplicationReadiness(baseUrl, appProcess, options) {
|
|
|
1421
1600
|
const lastFrontendDetail = lastProbe?.frontend.detail ?? "GET /login was never observed";
|
|
1422
1601
|
const lastBackendDetail = lastProbe?.backend.detail ?? "POST /api/auth/login was never observed";
|
|
1423
1602
|
const lastAuthenticatedDetail = lastProbe?.authenticated.detail ?? "Authenticated API probe was never observed";
|
|
1603
|
+
const lastBackendBrowserAuthDetail = lastProbe?.backendBrowserAuth.detail ?? "Backend browser auth probe was never observed";
|
|
1424
1604
|
throw new Error(
|
|
1425
|
-
`Application did not become ready within ${options.timeoutMs / 1e3} seconds. Last probe: ${lastFrontendDetail}; ${lastBackendDetail}; ${lastAuthenticatedDetail}`
|
|
1605
|
+
`Application did not become ready within ${options.timeoutMs / 1e3} seconds. Last probe: ${lastFrontendDetail}; ${lastBackendDetail}; ${lastAuthenticatedDetail}; ${lastBackendBrowserAuthDetail}`
|
|
1426
1606
|
);
|
|
1427
1607
|
}
|
|
1428
1608
|
function parseOptions(rawArgs) {
|