@walkeros/cli 4.7.0-next-1790722899482 → 4.7.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/CHANGELOG.md +80 -28
- package/dist/cli.js +7832 -6480
- package/dist/dev.d.ts +6 -0
- package/dist/dev.js +13 -1
- package/dist/dev.js.map +1 -1
- package/dist/examples/customers/README.md +3 -3
- package/dist/examples/customers/cust-1001 +1 -1
- package/dist/examples/customers/cust-42 +1 -1
- package/dist/examples/flow-complete.json +112 -29
- package/dist/examples/flow-complete.md +29 -11
- package/dist/examples/index.d.ts +12 -0
- package/dist/examples/index.js +126 -34
- package/dist/examples/index.js.map +1 -1
- package/dist/index.d.ts +42 -18
- package/dist/index.js +1484 -675
- package/dist/index.js.map +1 -1
- package/examples/customers/README.md +3 -3
- package/examples/customers/cust-1001 +1 -1
- package/examples/customers/cust-42 +1 -1
- package/examples/flow-complete.json +112 -29
- package/examples/flow-complete.md +29 -11
- package/package.json +29 -8
package/dist/index.js
CHANGED
|
@@ -5,8 +5,8 @@ var __export = (target, all) => {
|
|
|
5
5
|
};
|
|
6
6
|
|
|
7
7
|
// src/commands/bundle/index.ts
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import path15 from "path";
|
|
9
|
+
import fs16 from "fs-extra";
|
|
10
10
|
|
|
11
11
|
// src/core/cli-logger.ts
|
|
12
12
|
import chalk from "chalk";
|
|
@@ -220,7 +220,7 @@ function isAlreadyLocked(error) {
|
|
|
220
220
|
return hasCode(error) && error.code === "EEXIST";
|
|
221
221
|
}
|
|
222
222
|
function delay(ms) {
|
|
223
|
-
return new Promise((
|
|
223
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
224
224
|
}
|
|
225
225
|
function breakIfStale(lockPath) {
|
|
226
226
|
try {
|
|
@@ -553,18 +553,18 @@ function buildHeaders(token, headers) {
|
|
|
553
553
|
...mergeAuthHeaders(token, headers)
|
|
554
554
|
};
|
|
555
555
|
}
|
|
556
|
-
async function apiFetch(
|
|
556
|
+
async function apiFetch(path23, init) {
|
|
557
557
|
const baseUrl = resolveAppUrl();
|
|
558
558
|
const token = await resolveAccessToken();
|
|
559
559
|
if (token) requireSecureUrl(baseUrl);
|
|
560
|
-
return fetch(`${baseUrl}${
|
|
560
|
+
return fetch(`${baseUrl}${path23}`, {
|
|
561
561
|
...init,
|
|
562
562
|
headers: buildHeaders(token, init?.headers)
|
|
563
563
|
});
|
|
564
564
|
}
|
|
565
|
-
async function publicFetch(
|
|
565
|
+
async function publicFetch(path23, init) {
|
|
566
566
|
const baseUrl = resolveAppUrl();
|
|
567
|
-
return fetch(`${baseUrl}${
|
|
567
|
+
return fetch(`${baseUrl}${path23}`, {
|
|
568
568
|
...init,
|
|
569
569
|
headers: {
|
|
570
570
|
...clientContextHeaders(),
|
|
@@ -572,7 +572,7 @@ async function publicFetch(path20, init) {
|
|
|
572
572
|
}
|
|
573
573
|
});
|
|
574
574
|
}
|
|
575
|
-
async function deployFetch(
|
|
575
|
+
async function deployFetch(path23, init) {
|
|
576
576
|
const baseUrl = resolveAppUrl();
|
|
577
577
|
const token = resolveDeployToken() ?? await resolveAccessToken();
|
|
578
578
|
if (!token)
|
|
@@ -580,7 +580,7 @@ async function deployFetch(path20, init) {
|
|
|
580
580
|
"No authentication token available. Set WALKEROS_DEPLOY_TOKEN or run walkeros auth login."
|
|
581
581
|
);
|
|
582
582
|
requireSecureUrl(baseUrl);
|
|
583
|
-
return fetch(`${baseUrl}${
|
|
583
|
+
return fetch(`${baseUrl}${path23}`, {
|
|
584
584
|
...init,
|
|
585
585
|
headers: buildHeaders(token, init?.headers)
|
|
586
586
|
});
|
|
@@ -1015,8 +1015,8 @@ function validateFlowConfig(data) {
|
|
|
1015
1015
|
throw new Error("Invalid configuration: failed Flow.Json type guard.");
|
|
1016
1016
|
}
|
|
1017
1017
|
const errors = result.error.issues.map((issue) => {
|
|
1018
|
-
const
|
|
1019
|
-
return ` - ${
|
|
1018
|
+
const path23 = issue.path.length > 0 ? issue.path.map(String).join(".") : "root";
|
|
1019
|
+
return ` - ${path23}: ${issue.message}`;
|
|
1020
1020
|
}).join("\n");
|
|
1021
1021
|
throw new Error(`Invalid configuration:
|
|
1022
1022
|
${errors}`);
|
|
@@ -1055,9 +1055,86 @@ function getDefaultOutput(platform) {
|
|
|
1055
1055
|
}
|
|
1056
1056
|
|
|
1057
1057
|
// src/config/loader.ts
|
|
1058
|
+
import path8 from "path";
|
|
1059
|
+
import fs8 from "fs-extra";
|
|
1060
|
+
import { getFlowSettings, getPlatform } from "@walkeros/core";
|
|
1061
|
+
|
|
1062
|
+
// src/core/content-digest.ts
|
|
1063
|
+
import { createHash } from "crypto";
|
|
1058
1064
|
import path7 from "path";
|
|
1059
1065
|
import fs7 from "fs-extra";
|
|
1060
|
-
|
|
1066
|
+
var DIGEST_LENGTH = 12;
|
|
1067
|
+
function isRecord(value) {
|
|
1068
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
1069
|
+
}
|
|
1070
|
+
function canonicalJson(value) {
|
|
1071
|
+
return JSON.stringify(value, (_key, inner) => {
|
|
1072
|
+
if (!isRecord(inner)) return inner;
|
|
1073
|
+
const sorted = {};
|
|
1074
|
+
for (const key of Object.keys(inner).sort()) sorted[key] = inner[key];
|
|
1075
|
+
return sorted;
|
|
1076
|
+
});
|
|
1077
|
+
}
|
|
1078
|
+
function configDigest(flowSettings, flowName) {
|
|
1079
|
+
const collector = {
|
|
1080
|
+
...flowSettings.collector ?? {}
|
|
1081
|
+
};
|
|
1082
|
+
delete collector.release;
|
|
1083
|
+
collector.name ??= flowName;
|
|
1084
|
+
const config = flowSettings.config;
|
|
1085
|
+
const declaredEnv = config?.bundle?.env;
|
|
1086
|
+
const hashedConfig = config && declaredEnv ? {
|
|
1087
|
+
...config,
|
|
1088
|
+
bundle: { ...config.bundle, env: Object.keys(declaredEnv).sort() }
|
|
1089
|
+
} : config;
|
|
1090
|
+
return createHash("sha256").update(canonicalJson({ ...flowSettings, config: hashedConfig, collector })).digest("hex");
|
|
1091
|
+
}
|
|
1092
|
+
async function hashInstalledDir(dir) {
|
|
1093
|
+
const hash = createHash("sha256");
|
|
1094
|
+
for (const rel of await listFiles(dir, "")) {
|
|
1095
|
+
const abs = path7.join(dir, rel);
|
|
1096
|
+
const stat2 = await fs7.lstat(abs);
|
|
1097
|
+
hash.update(`${rel}\0`);
|
|
1098
|
+
hash.update(
|
|
1099
|
+
stat2.isSymbolicLink() ? await fs7.readlink(abs) : await fs7.readFile(abs)
|
|
1100
|
+
);
|
|
1101
|
+
hash.update("\0");
|
|
1102
|
+
}
|
|
1103
|
+
return hash.digest("hex").slice(0, DIGEST_LENGTH);
|
|
1104
|
+
}
|
|
1105
|
+
async function listFiles(root, rel) {
|
|
1106
|
+
const entries = await fs7.readdir(path7.join(root, rel), {
|
|
1107
|
+
withFileTypes: true
|
|
1108
|
+
});
|
|
1109
|
+
const files = [];
|
|
1110
|
+
for (const entry of entries) {
|
|
1111
|
+
const entryRel = rel ? `${rel}/${entry.name}` : entry.name;
|
|
1112
|
+
if (entry.isDirectory()) files.push(...await listFiles(root, entryRel));
|
|
1113
|
+
else files.push(entryRel);
|
|
1114
|
+
}
|
|
1115
|
+
return files.sort();
|
|
1116
|
+
}
|
|
1117
|
+
function releaseDigest(input) {
|
|
1118
|
+
return createHash("sha256").update(
|
|
1119
|
+
canonicalJson({
|
|
1120
|
+
config: input.configDigest,
|
|
1121
|
+
versions: input.versions,
|
|
1122
|
+
toolchain: input.toolchain
|
|
1123
|
+
})
|
|
1124
|
+
).digest("hex").slice(0, DIGEST_LENGTH);
|
|
1125
|
+
}
|
|
1126
|
+
|
|
1127
|
+
// src/config/window-collector.ts
|
|
1128
|
+
import { checkWindowCollector } from "@walkeros/core";
|
|
1129
|
+
function assertWindowCollector(value, source = {}) {
|
|
1130
|
+
const check = checkWindowCollector(value);
|
|
1131
|
+
if (check.ok) return check.name;
|
|
1132
|
+
const path23 = source.path ?? "config.settings.windowCollector";
|
|
1133
|
+
const subject = source.written !== void 0 && source.written !== value ? `${JSON.stringify(source.written)} resolved to ${JSON.stringify(value)}, which` : JSON.stringify(value);
|
|
1134
|
+
throw new Error(`${path23}: ${subject} ${check.reason}.`);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
// src/config/loader.ts
|
|
1061
1138
|
var DEFAULT_INCLUDE_FOLDER = "./shared";
|
|
1062
1139
|
function loadBundleConfig(rawConfig, options) {
|
|
1063
1140
|
const sanitized = stripLegacyBundleExternal(rawConfig, options.logger);
|
|
@@ -1067,6 +1144,7 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
1067
1144
|
assertLiteralBuildEnv(config, flowName);
|
|
1068
1145
|
let flowSettings = getFlowSettings(config, flowName, { deferred: true });
|
|
1069
1146
|
const platform = getPlatform(flowSettings);
|
|
1147
|
+
const flowConfigDigest = configDigest(flowSettings, flowName);
|
|
1070
1148
|
if (!platform) {
|
|
1071
1149
|
throw new Error(
|
|
1072
1150
|
`Invalid configuration: flow "${flowName}" must have config.platform set to "web" or "server".`
|
|
@@ -1083,16 +1161,20 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
1083
1161
|
const overrides = bundle2?.overrides ?? {};
|
|
1084
1162
|
const traceInclude = bundle2?.traceInclude;
|
|
1085
1163
|
const output = options.buildOverrides?.output || getDefaultOutput(platform);
|
|
1086
|
-
const configDir = isUrl(options.configPath) ? process.cwd() :
|
|
1164
|
+
const configDir = isUrl(options.configPath) ? process.cwd() : path8.dirname(options.configPath);
|
|
1087
1165
|
let includes = config.include;
|
|
1088
1166
|
if (!includes) {
|
|
1089
|
-
const defaultIncludePath =
|
|
1090
|
-
if (
|
|
1167
|
+
const defaultIncludePath = path8.resolve(configDir, DEFAULT_INCLUDE_FOLDER);
|
|
1168
|
+
if (fs8.pathExistsSync(defaultIncludePath)) {
|
|
1091
1169
|
includes = [DEFAULT_INCLUDE_FOLDER];
|
|
1092
1170
|
}
|
|
1093
1171
|
}
|
|
1094
1172
|
const buildOptions = {
|
|
1095
1173
|
...buildDefaults,
|
|
1174
|
+
...settingsToBuildOptions(platform, flowSettings.config?.settings, {
|
|
1175
|
+
path: `flows.${flowName}.config.settings.windowCollector`,
|
|
1176
|
+
written: config.flows[flowName]?.config?.settings?.windowCollector
|
|
1177
|
+
}),
|
|
1096
1178
|
packages,
|
|
1097
1179
|
overrides,
|
|
1098
1180
|
traceInclude,
|
|
@@ -1112,7 +1194,14 @@ function loadBundleConfig(rawConfig, options) {
|
|
|
1112
1194
|
buildOptions,
|
|
1113
1195
|
flowName,
|
|
1114
1196
|
isMultiFlow,
|
|
1115
|
-
availableFlows
|
|
1197
|
+
availableFlows,
|
|
1198
|
+
configDigest: flowConfigDigest
|
|
1199
|
+
};
|
|
1200
|
+
}
|
|
1201
|
+
function settingsToBuildOptions(platform, settings, source = {}) {
|
|
1202
|
+
if (platform !== "web" || settings?.windowCollector === void 0) return {};
|
|
1203
|
+
return {
|
|
1204
|
+
windowCollector: assertWindowCollector(settings.windowCollector, source)
|
|
1116
1205
|
};
|
|
1117
1206
|
}
|
|
1118
1207
|
var REFERENCE_PATTERN = /\$(?:env|var|secret|flow|contract)\.|\$code:|__WALKEROS_(?:ENV|SECRET):/;
|
|
@@ -1203,8 +1292,8 @@ function isPlainObject(value) {
|
|
|
1203
1292
|
// src/commands/bundle/bundler.ts
|
|
1204
1293
|
import esbuild2 from "esbuild";
|
|
1205
1294
|
import { builtinModules } from "module";
|
|
1206
|
-
import
|
|
1207
|
-
import
|
|
1295
|
+
import path14 from "path";
|
|
1296
|
+
import fs14 from "fs-extra";
|
|
1208
1297
|
import {
|
|
1209
1298
|
packageNameToVariable as packageNameToVariable2,
|
|
1210
1299
|
getStepRuntimeProps,
|
|
@@ -1372,8 +1461,8 @@ function applyStepPackages(flowSettings, packages, logger) {
|
|
|
1372
1461
|
|
|
1373
1462
|
// src/core/package-manager.ts
|
|
1374
1463
|
import pacote from "pacote";
|
|
1375
|
-
import
|
|
1376
|
-
import
|
|
1464
|
+
import path10 from "path";
|
|
1465
|
+
import fs10 from "fs-extra";
|
|
1377
1466
|
import { readFile } from "fs/promises";
|
|
1378
1467
|
import os from "os";
|
|
1379
1468
|
import semver2 from "semver";
|
|
@@ -1400,8 +1489,7 @@ async function getPackageCacheKey(packageName, version, date) {
|
|
|
1400
1489
|
return getHashServer(input, HASH_LENGTH);
|
|
1401
1490
|
}
|
|
1402
1491
|
function normalizeJson(content) {
|
|
1403
|
-
|
|
1404
|
-
return JSON.stringify(parsed);
|
|
1492
|
+
return canonicalJson(JSON.parse(content));
|
|
1405
1493
|
}
|
|
1406
1494
|
async function getFlowSettingsCacheKey(content, date) {
|
|
1407
1495
|
const dateStr = date ?? getTodayDate();
|
|
@@ -1412,8 +1500,8 @@ async function getFlowSettingsCacheKey(content, date) {
|
|
|
1412
1500
|
|
|
1413
1501
|
// src/core/atomic-cache.ts
|
|
1414
1502
|
import crypto from "crypto";
|
|
1415
|
-
import
|
|
1416
|
-
import
|
|
1503
|
+
import path9 from "path";
|
|
1504
|
+
import fs9 from "fs-extra";
|
|
1417
1505
|
var CACHE_COMPLETE_MARKER = ".walkeros-complete";
|
|
1418
1506
|
var TMP_INFIX = ".tmp-";
|
|
1419
1507
|
var BASE36 = "0123456789abcdefghijklmnopqrstuvwxyz";
|
|
@@ -1440,26 +1528,26 @@ function isCacheTempName(name) {
|
|
|
1440
1528
|
return TMP_NAME.test(name);
|
|
1441
1529
|
}
|
|
1442
1530
|
async function isCacheDirComplete(dir) {
|
|
1443
|
-
return
|
|
1531
|
+
return fs9.pathExists(path9.join(dir, CACHE_COMPLETE_MARKER));
|
|
1444
1532
|
}
|
|
1445
1533
|
async function readCacheDir(src, dest) {
|
|
1446
|
-
const marker =
|
|
1447
|
-
await
|
|
1534
|
+
const marker = path9.join(src, CACHE_COMPLETE_MARKER);
|
|
1535
|
+
await fs9.copy(src, dest, { filter: (file) => file !== marker });
|
|
1448
1536
|
}
|
|
1449
1537
|
async function sweepStaleCacheTemps(dir, maxAgeMs = 36e5) {
|
|
1450
1538
|
let entries;
|
|
1451
1539
|
try {
|
|
1452
|
-
entries = await
|
|
1540
|
+
entries = await fs9.readdir(dir);
|
|
1453
1541
|
} catch {
|
|
1454
1542
|
return;
|
|
1455
1543
|
}
|
|
1456
1544
|
const cutoff = Date.now() - maxAgeMs;
|
|
1457
1545
|
await Promise.all(
|
|
1458
1546
|
entries.filter(isCacheTempName).map(async (entry) => {
|
|
1459
|
-
const entryPath =
|
|
1547
|
+
const entryPath = path9.join(dir, entry);
|
|
1460
1548
|
try {
|
|
1461
|
-
const stats = await
|
|
1462
|
-
if (stats.mtimeMs < cutoff) await
|
|
1549
|
+
const stats = await fs9.stat(entryPath);
|
|
1550
|
+
if (stats.mtimeMs < cutoff) await fs9.remove(entryPath);
|
|
1463
1551
|
} catch {
|
|
1464
1552
|
}
|
|
1465
1553
|
})
|
|
@@ -1469,7 +1557,7 @@ async function replaceIncomplete(tmp, dest) {
|
|
|
1469
1557
|
const aside = tempSibling(dest);
|
|
1470
1558
|
let moved = false;
|
|
1471
1559
|
try {
|
|
1472
|
-
await
|
|
1560
|
+
await fs9.rename(dest, aside);
|
|
1473
1561
|
moved = true;
|
|
1474
1562
|
} catch (error) {
|
|
1475
1563
|
if (errorCode2(error) !== "ENOENT") throw error;
|
|
@@ -1478,54 +1566,54 @@ async function replaceIncomplete(tmp, dest) {
|
|
|
1478
1566
|
const winner = restore ? aside : tmp;
|
|
1479
1567
|
const loser = restore ? tmp : aside;
|
|
1480
1568
|
try {
|
|
1481
|
-
await
|
|
1569
|
+
await fs9.rename(winner, dest);
|
|
1482
1570
|
} catch (error) {
|
|
1483
1571
|
if (!isOccupied(error) || !await isCacheDirComplete(dest)) {
|
|
1484
|
-
if (!restore && moved) await
|
|
1572
|
+
if (!restore && moved) await fs9.remove(aside);
|
|
1485
1573
|
throw error;
|
|
1486
1574
|
}
|
|
1487
|
-
await
|
|
1575
|
+
await fs9.remove(winner);
|
|
1488
1576
|
}
|
|
1489
|
-
await
|
|
1577
|
+
await fs9.remove(loser);
|
|
1490
1578
|
}
|
|
1491
1579
|
async function writeCacheDir(src, dest, logger, options = {}) {
|
|
1492
|
-
const copy = options.copy ?? ((from, to) =>
|
|
1493
|
-
const dir =
|
|
1580
|
+
const copy = options.copy ?? ((from, to) => fs9.copy(from, to));
|
|
1581
|
+
const dir = path9.dirname(dest);
|
|
1494
1582
|
const tmp = tempSibling(dest);
|
|
1495
1583
|
try {
|
|
1496
|
-
await
|
|
1584
|
+
await fs9.ensureDir(dir);
|
|
1497
1585
|
await sweepStaleCacheTemps(dir);
|
|
1498
1586
|
await copy(src, tmp);
|
|
1499
|
-
await
|
|
1587
|
+
await fs9.writeFile(path9.join(tmp, CACHE_COMPLETE_MARKER), "");
|
|
1500
1588
|
try {
|
|
1501
|
-
await
|
|
1589
|
+
await fs9.rename(tmp, dest);
|
|
1502
1590
|
} catch (error) {
|
|
1503
1591
|
if (!isOccupied(error)) throw error;
|
|
1504
1592
|
if (await isCacheDirComplete(dest)) {
|
|
1505
|
-
await
|
|
1593
|
+
await fs9.remove(tmp);
|
|
1506
1594
|
return;
|
|
1507
1595
|
}
|
|
1508
1596
|
await replaceIncomplete(tmp, dest);
|
|
1509
1597
|
}
|
|
1510
1598
|
} catch (error) {
|
|
1511
|
-
await
|
|
1599
|
+
await fs9.remove(tmp).catch(() => {
|
|
1512
1600
|
});
|
|
1513
|
-
const label = options.label ??
|
|
1601
|
+
const label = options.label ?? path9.basename(dest);
|
|
1514
1602
|
logger.warn(
|
|
1515
1603
|
`Package cache write failed for ${label}: ${getErrorMessage(error)}. The build continues without caching it.`
|
|
1516
1604
|
);
|
|
1517
1605
|
}
|
|
1518
1606
|
}
|
|
1519
1607
|
async function writeCacheFile(dest, content) {
|
|
1520
|
-
const dir =
|
|
1608
|
+
const dir = path9.dirname(dest);
|
|
1521
1609
|
const tmp = tempSibling(dest);
|
|
1522
|
-
await
|
|
1610
|
+
await fs9.ensureDir(dir);
|
|
1523
1611
|
await sweepStaleCacheTemps(dir);
|
|
1524
1612
|
try {
|
|
1525
|
-
await
|
|
1526
|
-
await
|
|
1613
|
+
await fs9.writeFile(tmp, content, "utf-8");
|
|
1614
|
+
await fs9.rename(tmp, dest);
|
|
1527
1615
|
} catch (error) {
|
|
1528
|
-
await
|
|
1616
|
+
await fs9.remove(tmp).catch(() => {
|
|
1529
1617
|
});
|
|
1530
1618
|
throw error;
|
|
1531
1619
|
}
|
|
@@ -1584,8 +1672,8 @@ var PACOTE_OPTS = {
|
|
|
1584
1672
|
async function loadNpmConfigForPacote(projectDir = process.cwd(), homeDir = os.homedir()) {
|
|
1585
1673
|
const merged = {};
|
|
1586
1674
|
const sources = [
|
|
1587
|
-
|
|
1588
|
-
|
|
1675
|
+
path10.join(homeDir, ".npmrc"),
|
|
1676
|
+
path10.join(projectDir, ".npmrc")
|
|
1589
1677
|
];
|
|
1590
1678
|
for (const file of sources) {
|
|
1591
1679
|
let content;
|
|
@@ -1651,8 +1739,8 @@ function backoffForAttempt(index) {
|
|
|
1651
1739
|
return base + (Math.random() * 2 - 1) * spread;
|
|
1652
1740
|
}
|
|
1653
1741
|
function delay2(ms) {
|
|
1654
|
-
return new Promise((
|
|
1655
|
-
setTimeout(
|
|
1742
|
+
return new Promise((resolve5) => {
|
|
1743
|
+
setTimeout(resolve5, ms);
|
|
1656
1744
|
});
|
|
1657
1745
|
}
|
|
1658
1746
|
function describeError(error) {
|
|
@@ -1713,10 +1801,10 @@ function manifestWithResilience(spec, opts, _logger, retryOptions) {
|
|
|
1713
1801
|
);
|
|
1714
1802
|
}
|
|
1715
1803
|
function getPackageDirectory(baseDir, packageName) {
|
|
1716
|
-
return
|
|
1804
|
+
return path10.join(baseDir, "node_modules", packageName);
|
|
1717
1805
|
}
|
|
1718
1806
|
function getNestedPackageDirectory(baseDir, consumerName, nestedPackageName) {
|
|
1719
|
-
return
|
|
1807
|
+
return path10.join(
|
|
1720
1808
|
baseDir,
|
|
1721
1809
|
"node_modules",
|
|
1722
1810
|
consumerName,
|
|
@@ -1797,12 +1885,12 @@ async function collectAllSpecs(packages, logger, configDir, overrides = {}, npmC
|
|
|
1797
1885
|
if (visited.has(visitKey)) continue;
|
|
1798
1886
|
visited.add(visitKey);
|
|
1799
1887
|
if (item.localPath) {
|
|
1800
|
-
const resolvedPath =
|
|
1801
|
-
const candidatePath =
|
|
1802
|
-
const hasPkgJson = await
|
|
1888
|
+
const resolvedPath = path10.isAbsolute(item.localPath) ? item.localPath : path10.resolve(configDir || process.cwd(), item.localPath);
|
|
1889
|
+
const candidatePath = path10.join(resolvedPath, "package.json");
|
|
1890
|
+
const hasPkgJson = await fs10.pathExists(candidatePath);
|
|
1803
1891
|
if (hasPkgJson) {
|
|
1804
1892
|
try {
|
|
1805
|
-
const pkgJson = await
|
|
1893
|
+
const pkgJson = await fs10.readJson(candidatePath);
|
|
1806
1894
|
const deps2 = pkgJson.dependencies || {};
|
|
1807
1895
|
for (const [depName, depSpec] of Object.entries(deps2)) {
|
|
1808
1896
|
if (typeof depSpec === "string") {
|
|
@@ -2031,7 +2119,7 @@ async function downloadPackagesImpl(packages, targetDir, logger, useCache, confi
|
|
|
2031
2119
|
);
|
|
2032
2120
|
const resolution = await resolveVersionConflicts(allSpecs, logger, npmConfig);
|
|
2033
2121
|
const { topLevel, nested } = resolution;
|
|
2034
|
-
await
|
|
2122
|
+
await fs10.ensureDir(targetDir);
|
|
2035
2123
|
const localPackageMap = /* @__PURE__ */ new Map();
|
|
2036
2124
|
for (const pkg of packages) {
|
|
2037
2125
|
if (pkg.path) localPackageMap.set(pkg.name, pkg.path);
|
|
@@ -2060,7 +2148,7 @@ async function downloadPackagesImpl(packages, targetDir, logger, useCache, confi
|
|
|
2060
2148
|
logger.debug(`Downloading ${packageSpec} (cached)`);
|
|
2061
2149
|
}
|
|
2062
2150
|
try {
|
|
2063
|
-
await
|
|
2151
|
+
await fs10.ensureDir(path10.dirname(packageDir));
|
|
2064
2152
|
await readCacheDir(cachedPath, packageDir);
|
|
2065
2153
|
packagePaths.set(name, packageDir);
|
|
2066
2154
|
continue;
|
|
@@ -2069,7 +2157,7 @@ async function downloadPackagesImpl(packages, targetDir, logger, useCache, confi
|
|
|
2069
2157
|
}
|
|
2070
2158
|
}
|
|
2071
2159
|
try {
|
|
2072
|
-
await
|
|
2160
|
+
await fs10.ensureDir(path10.dirname(packageDir));
|
|
2073
2161
|
const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
|
|
2074
2162
|
await extractWithResilience(
|
|
2075
2163
|
packageSpec,
|
|
@@ -2113,7 +2201,7 @@ async function downloadPackagesImpl(packages, targetDir, logger, useCache, confi
|
|
|
2113
2201
|
nestedPkg.name
|
|
2114
2202
|
);
|
|
2115
2203
|
try {
|
|
2116
|
-
await
|
|
2204
|
+
await fs10.ensureDir(path10.dirname(nestedDir));
|
|
2117
2205
|
const cacheDir = process.env.NPM_CACHE_DIR || getTmpPath(tmpDir, "cache", "npm");
|
|
2118
2206
|
await extractWithResilience(
|
|
2119
2207
|
resolvedSpec,
|
|
@@ -2134,7 +2222,7 @@ async function downloadPackagesImpl(packages, targetDir, logger, useCache, confi
|
|
|
2134
2222
|
async function getCachedPackagePath(pkg, tmpDir) {
|
|
2135
2223
|
const cacheDir = getTmpPath(tmpDir, "cache", "packages");
|
|
2136
2224
|
const cacheKey = await getPackageCacheKey(pkg.name, pkg.version);
|
|
2137
|
-
return
|
|
2225
|
+
return path10.join(cacheDir, cacheKey);
|
|
2138
2226
|
}
|
|
2139
2227
|
async function isPackageCached(pkg, tmpDir) {
|
|
2140
2228
|
const cachedPath = await getCachedPackagePath(pkg, tmpDir);
|
|
@@ -2166,18 +2254,18 @@ Each package must use the same version across all declarations. Please update yo
|
|
|
2166
2254
|
// src/commands/bundle/nft-trace.ts
|
|
2167
2255
|
import esbuild from "esbuild";
|
|
2168
2256
|
import { nodeFileTrace } from "@vercel/nft";
|
|
2169
|
-
import * as
|
|
2170
|
-
import * as
|
|
2257
|
+
import * as path11 from "path";
|
|
2258
|
+
import * as fs11 from "fs/promises";
|
|
2171
2259
|
import picomatch from "picomatch";
|
|
2172
2260
|
async function traceAndCopy(opts) {
|
|
2173
2261
|
try {
|
|
2174
|
-
await
|
|
2262
|
+
await fs11.stat(opts.entry);
|
|
2175
2263
|
} catch {
|
|
2176
2264
|
throw new Error(
|
|
2177
2265
|
`nft-trace: entry file not found at '${opts.entry}'. Check the path or run 'walkeros bundle' from the directory containing your flow.json.`
|
|
2178
2266
|
);
|
|
2179
2267
|
}
|
|
2180
|
-
const realBase = await
|
|
2268
|
+
const realBase = await fs11.realpath(opts.base);
|
|
2181
2269
|
const expandedExtras = await expandTraceIncludes(
|
|
2182
2270
|
opts.extraIncludes ?? [],
|
|
2183
2271
|
realBase
|
|
@@ -2186,22 +2274,22 @@ async function traceAndCopy(opts) {
|
|
|
2186
2274
|
const { fileList, reasons } = await nodeFileTrace(entries, {
|
|
2187
2275
|
base: realBase
|
|
2188
2276
|
});
|
|
2189
|
-
const outDirReal =
|
|
2277
|
+
const outDirReal = path11.resolve(opts.outDir);
|
|
2190
2278
|
let copied = 0;
|
|
2191
2279
|
for (const file of fileList) {
|
|
2192
2280
|
const reason = reasons.get(file);
|
|
2193
2281
|
if (reason?.ignored) continue;
|
|
2194
|
-
const dst =
|
|
2195
|
-
if (!dst.startsWith(outDirReal +
|
|
2282
|
+
const dst = path11.resolve(outDirReal, file);
|
|
2283
|
+
if (!dst.startsWith(outDirReal + path11.sep) && dst !== outDirReal) {
|
|
2196
2284
|
throw new Error(
|
|
2197
2285
|
`nft-trace: traced file '${file}' resolves outside outDir. This usually means base is too narrow for a hoisted monorepo. Move base up to the workspace root or set traceInclude explicitly.`
|
|
2198
2286
|
);
|
|
2199
2287
|
}
|
|
2200
|
-
const src =
|
|
2201
|
-
await
|
|
2202
|
-
await
|
|
2203
|
-
const s = await
|
|
2204
|
-
if (s.mode & 73) await
|
|
2288
|
+
const src = path11.join(realBase, file);
|
|
2289
|
+
await fs11.mkdir(path11.dirname(dst), { recursive: true });
|
|
2290
|
+
await fs11.copyFile(src, dst);
|
|
2291
|
+
const s = await fs11.stat(src);
|
|
2292
|
+
if (s.mode & 73) await fs11.chmod(dst, s.mode);
|
|
2205
2293
|
copied++;
|
|
2206
2294
|
}
|
|
2207
2295
|
return { fileList: Array.from(fileList), copied, reasons };
|
|
@@ -2261,13 +2349,13 @@ async function expandTraceIncludes(patterns, base) {
|
|
|
2261
2349
|
else literals.push(entry);
|
|
2262
2350
|
}
|
|
2263
2351
|
const resolvedLiterals = literals.map(
|
|
2264
|
-
(p) =>
|
|
2352
|
+
(p) => path11.isAbsolute(p) ? p : path11.resolve(base, p)
|
|
2265
2353
|
);
|
|
2266
2354
|
if (globs.length === 0) return resolvedLiterals;
|
|
2267
2355
|
const matchers = globs.map((g) => picomatch(g));
|
|
2268
2356
|
const matchedFiles = [];
|
|
2269
2357
|
await walkFiles(base, base, async (absFile, relFile) => {
|
|
2270
|
-
const relPosix = relFile.split(
|
|
2358
|
+
const relPosix = relFile.split(path11.sep).join("/");
|
|
2271
2359
|
if (matchers.some((m) => m(relPosix))) {
|
|
2272
2360
|
matchedFiles.push(absFile);
|
|
2273
2361
|
}
|
|
@@ -2277,27 +2365,27 @@ async function expandTraceIncludes(patterns, base) {
|
|
|
2277
2365
|
async function walkFiles(root, dir, visit) {
|
|
2278
2366
|
let entries;
|
|
2279
2367
|
try {
|
|
2280
|
-
entries = await
|
|
2368
|
+
entries = await fs11.readdir(dir, { withFileTypes: true });
|
|
2281
2369
|
} catch {
|
|
2282
2370
|
return;
|
|
2283
2371
|
}
|
|
2284
2372
|
for (const entry of entries) {
|
|
2285
|
-
const abs =
|
|
2373
|
+
const abs = path11.join(dir, entry.name);
|
|
2286
2374
|
if (entry.isDirectory()) {
|
|
2287
2375
|
await walkFiles(root, abs, visit);
|
|
2288
2376
|
} else if (entry.isFile()) {
|
|
2289
|
-
await visit(abs,
|
|
2377
|
+
await visit(abs, path11.relative(root, abs));
|
|
2290
2378
|
}
|
|
2291
2379
|
}
|
|
2292
2380
|
}
|
|
2293
2381
|
|
|
2294
2382
|
// src/commands/bundle/assert-consumer-deps.ts
|
|
2295
|
-
import
|
|
2296
|
-
import * as
|
|
2383
|
+
import fs12 from "fs-extra";
|
|
2384
|
+
import * as path12 from "path";
|
|
2297
2385
|
import semver3 from "semver";
|
|
2298
2386
|
async function assertConsumerDepsSatisfied(root, logger) {
|
|
2299
2387
|
const consumers = await collectInstalledPackages(
|
|
2300
|
-
|
|
2388
|
+
path12.join(root, "node_modules")
|
|
2301
2389
|
);
|
|
2302
2390
|
const violations = [];
|
|
2303
2391
|
for (const consumer of consumers) {
|
|
@@ -2344,17 +2432,17 @@ async function assertConsumerDepsSatisfied(root, logger) {
|
|
|
2344
2432
|
}
|
|
2345
2433
|
async function collectInstalledPackages(nodeModulesDir) {
|
|
2346
2434
|
const result = [];
|
|
2347
|
-
if (!await
|
|
2435
|
+
if (!await fs12.pathExists(nodeModulesDir)) return result;
|
|
2348
2436
|
async function walk(dir) {
|
|
2349
|
-
const entries = await
|
|
2437
|
+
const entries = await fs12.readdir(dir, { withFileTypes: true });
|
|
2350
2438
|
for (const entry of entries) {
|
|
2351
2439
|
if (!entry.isDirectory()) continue;
|
|
2352
|
-
const full =
|
|
2440
|
+
const full = path12.join(dir, entry.name);
|
|
2353
2441
|
if (entry.name.startsWith("@")) {
|
|
2354
|
-
const scopedEntries = await
|
|
2442
|
+
const scopedEntries = await fs12.readdir(full, { withFileTypes: true });
|
|
2355
2443
|
for (const scoped of scopedEntries) {
|
|
2356
2444
|
if (!scoped.isDirectory()) continue;
|
|
2357
|
-
await collectOne(
|
|
2445
|
+
await collectOne(path12.join(full, scoped.name));
|
|
2358
2446
|
}
|
|
2359
2447
|
continue;
|
|
2360
2448
|
}
|
|
@@ -2362,12 +2450,12 @@ async function collectInstalledPackages(nodeModulesDir) {
|
|
|
2362
2450
|
}
|
|
2363
2451
|
}
|
|
2364
2452
|
async function collectOne(pkgDir) {
|
|
2365
|
-
const pkgJsonPath =
|
|
2366
|
-
if (!await
|
|
2367
|
-
const pkg = await
|
|
2453
|
+
const pkgJsonPath = path12.join(pkgDir, "package.json");
|
|
2454
|
+
if (!await fs12.pathExists(pkgJsonPath)) return;
|
|
2455
|
+
const pkg = await fs12.readJson(pkgJsonPath);
|
|
2368
2456
|
result.push({ dir: pkgDir, pkg });
|
|
2369
|
-
const nestedNm =
|
|
2370
|
-
if (await
|
|
2457
|
+
const nestedNm = path12.join(pkgDir, "node_modules");
|
|
2458
|
+
if (await fs12.pathExists(nestedNm)) await walk(nestedNm);
|
|
2371
2459
|
}
|
|
2372
2460
|
await walk(nodeModulesDir);
|
|
2373
2461
|
return result;
|
|
@@ -2375,13 +2463,13 @@ async function collectInstalledPackages(nodeModulesDir) {
|
|
|
2375
2463
|
async function resolveSiblingOrAncestor(consumerDir, depName, root) {
|
|
2376
2464
|
let current = consumerDir;
|
|
2377
2465
|
while (true) {
|
|
2378
|
-
const candidate =
|
|
2379
|
-
const pkgJson =
|
|
2380
|
-
if (await
|
|
2381
|
-
const pkg = await
|
|
2466
|
+
const candidate = path12.join(current, "node_modules", depName);
|
|
2467
|
+
const pkgJson = path12.join(candidate, "package.json");
|
|
2468
|
+
if (await fs12.pathExists(pkgJson)) {
|
|
2469
|
+
const pkg = await fs12.readJson(pkgJson);
|
|
2382
2470
|
if (pkg.version) return { dir: candidate, version: pkg.version };
|
|
2383
2471
|
}
|
|
2384
|
-
const parent =
|
|
2472
|
+
const parent = path12.dirname(current);
|
|
2385
2473
|
if (parent === current || !current.startsWith(root)) return null;
|
|
2386
2474
|
current = parent;
|
|
2387
2475
|
}
|
|
@@ -2391,8 +2479,8 @@ async function resolveSiblingOrAncestor(consumerDir, depName, root) {
|
|
|
2391
2479
|
import { getHashServer as getHashServer3 } from "@walkeros/server-core";
|
|
2392
2480
|
|
|
2393
2481
|
// src/core/build-cache.ts
|
|
2394
|
-
import
|
|
2395
|
-
import
|
|
2482
|
+
import fs13 from "fs-extra";
|
|
2483
|
+
import path13 from "path";
|
|
2396
2484
|
import { getHashServer as getHashServer2 } from "@walkeros/server-core";
|
|
2397
2485
|
function serializeKeyInputs(inputs) {
|
|
2398
2486
|
return JSON.stringify({
|
|
@@ -2405,7 +2493,8 @@ function serializeKeyInputs(inputs) {
|
|
|
2405
2493
|
minifyOptions: inputs.minifyOptions ?? null,
|
|
2406
2494
|
windowCollector: inputs.windowCollector ?? null,
|
|
2407
2495
|
windowElb: inputs.windowElb ?? null,
|
|
2408
|
-
versionsHash: inputs.versionsHash
|
|
2496
|
+
versionsHash: inputs.versionsHash,
|
|
2497
|
+
toolchain: inputs.toolchain
|
|
2409
2498
|
});
|
|
2410
2499
|
}
|
|
2411
2500
|
async function computeCodeCacheKey(codeContent, inputs) {
|
|
@@ -2417,11 +2506,11 @@ ${serializeKeyInputs(inputs)}`;
|
|
|
2417
2506
|
async function getBuildCachePath(configContent, tmpDir) {
|
|
2418
2507
|
const cacheDir = getTmpPath(tmpDir, "cache", "builds");
|
|
2419
2508
|
const cacheKey = await getFlowSettingsCacheKey(configContent);
|
|
2420
|
-
return
|
|
2509
|
+
return path13.join(cacheDir, `${cacheKey}.js`);
|
|
2421
2510
|
}
|
|
2422
2511
|
async function isBuildCached(configContent, tmpDir) {
|
|
2423
2512
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
2424
|
-
return
|
|
2513
|
+
return fs13.pathExists(cachePath);
|
|
2425
2514
|
}
|
|
2426
2515
|
async function cacheBuild(configContent, buildOutput, tmpDir) {
|
|
2427
2516
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
@@ -2429,15 +2518,15 @@ async function cacheBuild(configContent, buildOutput, tmpDir) {
|
|
|
2429
2518
|
}
|
|
2430
2519
|
async function getCachedBuild(configContent, tmpDir) {
|
|
2431
2520
|
const cachePath = await getBuildCachePath(configContent, tmpDir);
|
|
2432
|
-
if (await
|
|
2433
|
-
return await
|
|
2521
|
+
if (await fs13.pathExists(cachePath)) {
|
|
2522
|
+
return await fs13.readFile(cachePath, "utf-8");
|
|
2434
2523
|
}
|
|
2435
2524
|
return null;
|
|
2436
2525
|
}
|
|
2437
2526
|
async function getCodeCachePath(codeContent, tmpDir, inputs) {
|
|
2438
2527
|
const cacheDir = getTmpPath(tmpDir, "cache", "code");
|
|
2439
2528
|
const cacheKey = await computeCodeCacheKey(codeContent, inputs);
|
|
2440
|
-
return
|
|
2529
|
+
return path13.join(cacheDir, `${cacheKey}.js`);
|
|
2441
2530
|
}
|
|
2442
2531
|
async function cacheCode(codeContent, codeOutput, tmpDir, inputs) {
|
|
2443
2532
|
const cachePath = await getCodeCachePath(codeContent, tmpDir, inputs);
|
|
@@ -2445,21 +2534,44 @@ async function cacheCode(codeContent, codeOutput, tmpDir, inputs) {
|
|
|
2445
2534
|
}
|
|
2446
2535
|
async function getCachedCode(codeContent, tmpDir, inputs) {
|
|
2447
2536
|
const cachePath = await getCodeCachePath(codeContent, tmpDir, inputs);
|
|
2448
|
-
if (await
|
|
2449
|
-
return
|
|
2537
|
+
if (await fs13.pathExists(cachePath)) {
|
|
2538
|
+
return fs13.readFile(cachePath, "utf-8");
|
|
2450
2539
|
}
|
|
2451
2540
|
return null;
|
|
2452
2541
|
}
|
|
2453
2542
|
async function ensureCodeOnDisk(codeContent, compiledCode, tmpDir, inputs) {
|
|
2454
2543
|
const cacheDir = getTmpPath(tmpDir, "cache", "code");
|
|
2455
2544
|
const cacheKey = await computeCodeCacheKey(codeContent, inputs);
|
|
2456
|
-
const cachePath =
|
|
2457
|
-
if (!await
|
|
2545
|
+
const cachePath = path13.join(cacheDir, `${cacheKey}.mjs`);
|
|
2546
|
+
if (!await fs13.pathExists(cachePath)) {
|
|
2458
2547
|
await writeCacheFile(cachePath, compiledCode);
|
|
2459
2548
|
}
|
|
2460
2549
|
return cachePath;
|
|
2461
2550
|
}
|
|
2462
2551
|
|
|
2552
|
+
// src/version.ts
|
|
2553
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
2554
|
+
import { fileURLToPath } from "url";
|
|
2555
|
+
import { dirname as dirname3, join as join4 } from "path";
|
|
2556
|
+
var versionFilename = fileURLToPath(import.meta.url);
|
|
2557
|
+
var versionDirname = dirname3(versionFilename);
|
|
2558
|
+
function findPackageJson() {
|
|
2559
|
+
const paths = [
|
|
2560
|
+
join4(versionDirname, "../package.json"),
|
|
2561
|
+
// dist/ or src/
|
|
2562
|
+
join4(versionDirname, "../../package.json")
|
|
2563
|
+
// src/core/ (not used, but safe)
|
|
2564
|
+
];
|
|
2565
|
+
for (const p of paths) {
|
|
2566
|
+
try {
|
|
2567
|
+
return readFileSync2(p, "utf-8");
|
|
2568
|
+
} catch {
|
|
2569
|
+
}
|
|
2570
|
+
}
|
|
2571
|
+
return JSON.stringify({ version: "0.0.0" });
|
|
2572
|
+
}
|
|
2573
|
+
var VERSION = JSON.parse(findPackageJson()).version;
|
|
2574
|
+
|
|
2463
2575
|
// src/commands/bundle/bundler.ts
|
|
2464
2576
|
function isInlineCode(code) {
|
|
2465
2577
|
return code !== null && typeof code === "object" && !Array.isArray(code) && "push" in code;
|
|
@@ -2500,18 +2612,18 @@ function generateInlineCode(inline, runtimeProps, isDestination) {
|
|
|
2500
2612
|
}
|
|
2501
2613
|
async function copyIncludes(includes, sourceDir, outputDir, logger) {
|
|
2502
2614
|
for (const include of includes) {
|
|
2503
|
-
const sourcePath =
|
|
2504
|
-
const folderName =
|
|
2505
|
-
const destPath =
|
|
2506
|
-
const resolvedOutput =
|
|
2507
|
-
const resolvedSource =
|
|
2508
|
-
if (resolvedSource === resolvedOutput || resolvedOutput.startsWith(resolvedSource +
|
|
2615
|
+
const sourcePath = path14.resolve(sourceDir, include);
|
|
2616
|
+
const folderName = path14.basename(include);
|
|
2617
|
+
const destPath = path14.join(outputDir, folderName);
|
|
2618
|
+
const resolvedOutput = path14.resolve(outputDir);
|
|
2619
|
+
const resolvedSource = path14.resolve(sourcePath);
|
|
2620
|
+
if (resolvedSource === resolvedOutput || resolvedOutput.startsWith(resolvedSource + path14.sep) || resolvedSource.startsWith(resolvedOutput + path14.sep)) {
|
|
2509
2621
|
throw new Error(
|
|
2510
2622
|
`Circular include detected: "${include}" resolves to "${resolvedSource}" which overlaps with output directory "${resolvedOutput}"`
|
|
2511
2623
|
);
|
|
2512
2624
|
}
|
|
2513
|
-
if (await
|
|
2514
|
-
await
|
|
2625
|
+
if (await fs14.pathExists(sourcePath)) {
|
|
2626
|
+
await fs14.copy(sourcePath, destPath);
|
|
2515
2627
|
logger.debug(`Copied ${include} to output`);
|
|
2516
2628
|
} else {
|
|
2517
2629
|
logger.warn(`Include folder not found: ${include}`);
|
|
@@ -2536,27 +2648,42 @@ function generateCacheKeyContent(flowSettings, buildOptions, versionsHash) {
|
|
|
2536
2648
|
// not change this key. The durable cross-version cache bust is the
|
|
2537
2649
|
// version/toolchain hash, not this field.
|
|
2538
2650
|
emittedFormat: resolveEmittedFormat(buildOptions),
|
|
2539
|
-
versionsHash
|
|
2651
|
+
versionsHash,
|
|
2652
|
+
// Generated code changes with the CLI, so a CLI upgrade never serves a
|
|
2653
|
+
// build made by the previous version.
|
|
2654
|
+
toolchain: VERSION
|
|
2540
2655
|
};
|
|
2541
2656
|
return JSON.stringify(configForCache);
|
|
2542
2657
|
}
|
|
2543
2658
|
function resolveEmittedFormat(buildOptions) {
|
|
2544
2659
|
return buildOptions.platform === "browser" ? "iife" : "esm";
|
|
2545
2660
|
}
|
|
2546
|
-
async function
|
|
2661
|
+
async function resolvedVersionLines(topLevel, packagePaths) {
|
|
2662
|
+
const lines = [];
|
|
2663
|
+
for (const [name, pkg] of [...topLevel.entries()].sort(
|
|
2664
|
+
([a], [b]) => a.localeCompare(b)
|
|
2665
|
+
)) {
|
|
2666
|
+
const installed = packagePaths.get(name);
|
|
2667
|
+
lines.push(
|
|
2668
|
+
pkg.version === "local" && installed ? `${name}@local:${await hashInstalledDir(installed)}` : `${name}@${pkg.version}`
|
|
2669
|
+
);
|
|
2670
|
+
}
|
|
2671
|
+
return lines;
|
|
2672
|
+
}
|
|
2673
|
+
async function bundleCore(flowSettings, buildOptions, logger, showStats = false, provenance) {
|
|
2547
2674
|
const bundleStartTime = Date.now();
|
|
2548
2675
|
const CACHE_DIR = buildOptions.tempDir || getTmpPath();
|
|
2549
2676
|
const npmConfig = await loadNpmConfigForPacote(
|
|
2550
2677
|
buildOptions.configDir ?? process.cwd()
|
|
2551
2678
|
);
|
|
2552
|
-
const outputPath =
|
|
2553
|
-
const outputDirAbs =
|
|
2554
|
-
await
|
|
2555
|
-
await
|
|
2556
|
-
await
|
|
2679
|
+
const outputPath = path14.resolve(buildOptions.output);
|
|
2680
|
+
const outputDirAbs = path14.dirname(outputPath);
|
|
2681
|
+
await fs14.remove(path14.join(outputDirAbs, "node_modules"));
|
|
2682
|
+
await fs14.remove(path14.join(outputDirAbs, "package.json"));
|
|
2683
|
+
await fs14.remove(path14.join(outputDirAbs, "package-lock.json"));
|
|
2557
2684
|
const TEMP_DIR = buildOptions.tempDir || await tmpRunDir("build");
|
|
2558
2685
|
try {
|
|
2559
|
-
await
|
|
2686
|
+
await fs14.ensureDir(TEMP_DIR);
|
|
2560
2687
|
const hasSourcesOrDests = Object.keys(flowSettings.sources || {}).length > 0 || Object.keys(flowSettings.destinations || {}).length > 0;
|
|
2561
2688
|
if (hasSourcesOrDests && !buildOptions.packages["@walkeros/collector"]) {
|
|
2562
2689
|
buildOptions.packages["@walkeros/collector"] = {};
|
|
@@ -2584,10 +2711,10 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2584
2711
|
);
|
|
2585
2712
|
const warnedBundleFieldPackages = /* @__PURE__ */ new Set();
|
|
2586
2713
|
for (const [pkgName, pkgPath] of packagePaths.entries()) {
|
|
2587
|
-
const pkgJsonPath =
|
|
2714
|
+
const pkgJsonPath = path14.join(pkgPath, "package.json");
|
|
2588
2715
|
let pkgJson;
|
|
2589
2716
|
try {
|
|
2590
|
-
pkgJson = await
|
|
2717
|
+
pkgJson = await fs14.readJSON(pkgJsonPath);
|
|
2591
2718
|
} catch {
|
|
2592
2719
|
continue;
|
|
2593
2720
|
}
|
|
@@ -2612,15 +2739,30 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2612
2739
|
require: pkgJson.main
|
|
2613
2740
|
}
|
|
2614
2741
|
};
|
|
2615
|
-
await
|
|
2742
|
+
await fs14.writeJSON(pkgJsonPath, pkgJson, { spaces: 2 });
|
|
2616
2743
|
}
|
|
2617
2744
|
}
|
|
2618
2745
|
}
|
|
2619
2746
|
if (process.env.BUNDLER_STRICT_RANGES !== "0") {
|
|
2620
2747
|
await assertConsumerDepsSatisfied(TEMP_DIR, logger);
|
|
2621
2748
|
}
|
|
2622
|
-
const sortedVersions =
|
|
2749
|
+
const sortedVersions = await resolvedVersionLines(
|
|
2750
|
+
resolutionResult.topLevel,
|
|
2751
|
+
packagePaths
|
|
2752
|
+
);
|
|
2623
2753
|
const versionsHash = await getHashServer3(sortedVersions.join("\n"), 12);
|
|
2754
|
+
if (provenance) {
|
|
2755
|
+
applyCollectorProvenance(
|
|
2756
|
+
flowSettings,
|
|
2757
|
+
provenance.flowName,
|
|
2758
|
+
provenance.release,
|
|
2759
|
+
() => releaseDigest({
|
|
2760
|
+
configDigest: provenance.configDigest,
|
|
2761
|
+
versions: sortedVersions,
|
|
2762
|
+
toolchain: VERSION
|
|
2763
|
+
})
|
|
2764
|
+
);
|
|
2765
|
+
}
|
|
2624
2766
|
const declaredPackages = Object.keys(buildOptions.packages).filter(
|
|
2625
2767
|
(name) => !name.startsWith(".") && !name.startsWith("/")
|
|
2626
2768
|
);
|
|
@@ -2635,8 +2777,8 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2635
2777
|
const cachedBuild = await getCachedBuild(configContent, CACHE_DIR);
|
|
2636
2778
|
if (cachedBuild) {
|
|
2637
2779
|
logger.debug("Using cached build");
|
|
2638
|
-
await
|
|
2639
|
-
await
|
|
2780
|
+
await fs14.ensureDir(path14.dirname(outputPath));
|
|
2781
|
+
await fs14.writeFile(outputPath, cachedBuild);
|
|
2640
2782
|
await finishArtifact(
|
|
2641
2783
|
outputPath,
|
|
2642
2784
|
flowSettings,
|
|
@@ -2645,7 +2787,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2645
2787
|
declaredPackages,
|
|
2646
2788
|
logger
|
|
2647
2789
|
);
|
|
2648
|
-
const stats2 = await
|
|
2790
|
+
const stats2 = await fs14.stat(outputPath);
|
|
2649
2791
|
const sizeKB2 = (stats2.size / 1024).toFixed(1);
|
|
2650
2792
|
logger.info(`Output: ${outputPath} (${sizeKB2} KB, cached)`);
|
|
2651
2793
|
if (showStats) {
|
|
@@ -2668,14 +2810,14 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2668
2810
|
}
|
|
2669
2811
|
}
|
|
2670
2812
|
}
|
|
2671
|
-
const packageJsonPath =
|
|
2672
|
-
await
|
|
2813
|
+
const packageJsonPath = path14.join(TEMP_DIR, "package.json");
|
|
2814
|
+
await fs14.writeFile(
|
|
2673
2815
|
packageJsonPath,
|
|
2674
2816
|
JSON.stringify({ type: "module" }, null, 2)
|
|
2675
2817
|
);
|
|
2676
2818
|
logger.debug("Creating entry point");
|
|
2677
2819
|
const { codeEntry, dataPayload, hasFlow, devPackages } = await createEntryPoint(flowSettings, buildOptions, packagePaths, logger);
|
|
2678
|
-
await
|
|
2820
|
+
await fs14.ensureDir(path14.dirname(outputPath));
|
|
2679
2821
|
const codeKeyInputs = {
|
|
2680
2822
|
// Deploy browser skeletons (externalizeDev) externalize each `<pkg>/dev`
|
|
2681
2823
|
// so the lazy registry is not inlined; in-process simulate/push inline it.
|
|
@@ -2695,7 +2837,8 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2695
2837
|
// Retained but inert (deprecation surface): no codegen reads it anymore.
|
|
2696
2838
|
// Keeping it here only over-keys the code cache, which is harmless.
|
|
2697
2839
|
windowElb: buildOptions.windowElb,
|
|
2698
|
-
versionsHash
|
|
2840
|
+
versionsHash,
|
|
2841
|
+
toolchain: VERSION
|
|
2699
2842
|
};
|
|
2700
2843
|
let compiledCode = null;
|
|
2701
2844
|
if (buildOptions.cache !== false) {
|
|
@@ -2707,8 +2850,8 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2707
2850
|
logger.debug(
|
|
2708
2851
|
`Running esbuild (target: ${buildOptions.target || "es2018"}, format: ${buildOptions.format})`
|
|
2709
2852
|
);
|
|
2710
|
-
const entryPath =
|
|
2711
|
-
await
|
|
2853
|
+
const entryPath = path14.join(TEMP_DIR, "entry.js");
|
|
2854
|
+
await fs14.writeFile(entryPath, codeEntry);
|
|
2712
2855
|
const esbuildOptions = createEsbuildOptions(
|
|
2713
2856
|
{ ...buildOptions, minify: false },
|
|
2714
2857
|
entryPath,
|
|
@@ -2729,7 +2872,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false)
|
|
|
2729
2872
|
} finally {
|
|
2730
2873
|
await esbuild2.stop();
|
|
2731
2874
|
}
|
|
2732
|
-
compiledCode = await
|
|
2875
|
+
compiledCode = await fs14.readFile(outputPath, "utf-8");
|
|
2733
2876
|
if (buildOptions.cache !== false) {
|
|
2734
2877
|
await cacheCode(codeEntry, compiledCode, CACHE_DIR, codeKeyInputs);
|
|
2735
2878
|
}
|
|
@@ -2747,7 +2890,7 @@ export { __configData };`;
|
|
|
2747
2890
|
` : "";
|
|
2748
2891
|
const esmOutput = `${banner}${compiledCode}
|
|
2749
2892
|
${dataDeclaration}`;
|
|
2750
|
-
await
|
|
2893
|
+
await fs14.writeFile(outputPath, esmOutput);
|
|
2751
2894
|
} else {
|
|
2752
2895
|
const stage2Entry = (buildOptions.platform || "node") === "browser" ? generateWebEntry(stage1Path, dataPayload, {
|
|
2753
2896
|
windowCollector: buildOptions.windowCollector,
|
|
@@ -2755,8 +2898,8 @@ ${dataDeclaration}`;
|
|
|
2755
2898
|
platform: buildOptions.platform,
|
|
2756
2899
|
observe: readObserveConnect(flowSettings, logger)
|
|
2757
2900
|
}) : generateServerEntry(stage1Path, dataPayload);
|
|
2758
|
-
const stage2EntryPath =
|
|
2759
|
-
await
|
|
2901
|
+
const stage2EntryPath = path14.join(TEMP_DIR, "stage2.mjs");
|
|
2902
|
+
await fs14.writeFile(stage2EntryPath, stage2Entry);
|
|
2760
2903
|
const stage2Options = {
|
|
2761
2904
|
entryPoints: [stage2EntryPath],
|
|
2762
2905
|
bundle: true,
|
|
@@ -2794,7 +2937,7 @@ ${dataDeclaration}`;
|
|
|
2794
2937
|
await esbuild2.stop();
|
|
2795
2938
|
}
|
|
2796
2939
|
}
|
|
2797
|
-
const outputStats = await
|
|
2940
|
+
const outputStats = await fs14.stat(outputPath);
|
|
2798
2941
|
const sizeKB = (outputStats.size / 1024).toFixed(1);
|
|
2799
2942
|
const buildTime = ((Date.now() - bundleStartTime) / 1e3).toFixed(1);
|
|
2800
2943
|
logger.info(`Output: ${outputPath} (${sizeKB} KB, ${buildTime}s)`);
|
|
@@ -2804,7 +2947,7 @@ ${dataDeclaration}`;
|
|
|
2804
2947
|
buildOptions,
|
|
2805
2948
|
versionsHash
|
|
2806
2949
|
);
|
|
2807
|
-
const buildOutput = await
|
|
2950
|
+
const buildOutput = await fs14.readFile(outputPath, "utf-8");
|
|
2808
2951
|
await cacheBuild(configContent, buildOutput, CACHE_DIR);
|
|
2809
2952
|
logger.debug("Build cached for future use");
|
|
2810
2953
|
}
|
|
@@ -2830,7 +2973,7 @@ ${dataDeclaration}`;
|
|
|
2830
2973
|
throw error;
|
|
2831
2974
|
} finally {
|
|
2832
2975
|
if (!buildOptions.tempDir) {
|
|
2833
|
-
await
|
|
2976
|
+
await fs14.remove(TEMP_DIR).catch(() => {
|
|
2834
2977
|
});
|
|
2835
2978
|
}
|
|
2836
2979
|
}
|
|
@@ -2859,12 +3002,12 @@ async function finishArtifact(outputPath, flowSettings, buildOptions, tempDir, d
|
|
|
2859
3002
|
await copyIncludes(
|
|
2860
3003
|
buildOptions.include,
|
|
2861
3004
|
buildOptions.configDir || process.cwd(),
|
|
2862
|
-
|
|
3005
|
+
path14.dirname(outputPath),
|
|
2863
3006
|
logger
|
|
2864
3007
|
);
|
|
2865
3008
|
}
|
|
2866
3009
|
async function collectBundleStats(outputPath, packages, startTime, entryContent) {
|
|
2867
|
-
const stats = await
|
|
3010
|
+
const stats = await fs14.stat(outputPath);
|
|
2868
3011
|
const totalSize = stats.size;
|
|
2869
3012
|
const buildTime = Date.now() - startTime;
|
|
2870
3013
|
const packageStats = Object.entries(packages).map(([name, pkg]) => ({
|
|
@@ -2943,13 +3086,13 @@ function getNodeExternals() {
|
|
|
2943
3086
|
return externals;
|
|
2944
3087
|
}
|
|
2945
3088
|
async function runNftServerPath(outputPath, flowSettings, buildOptions, tempDir, declaredPackages, logger) {
|
|
2946
|
-
const outDir =
|
|
3089
|
+
const outDir = path14.dirname(outputPath);
|
|
2947
3090
|
const flowExtraIncludes = [
|
|
2948
3091
|
...flowSettings.config?.bundle?.traceInclude ?? [],
|
|
2949
3092
|
...buildOptions.traceInclude ?? []
|
|
2950
3093
|
];
|
|
2951
|
-
const stagedEntry =
|
|
2952
|
-
await
|
|
3094
|
+
const stagedEntry = path14.join(tempDir, "__nft-flow.mjs");
|
|
3095
|
+
await fs14.copyFile(outputPath, stagedEntry);
|
|
2953
3096
|
let result;
|
|
2954
3097
|
try {
|
|
2955
3098
|
result = await traceAndCopy({
|
|
@@ -2959,12 +3102,12 @@ async function runNftServerPath(outputPath, flowSettings, buildOptions, tempDir,
|
|
|
2959
3102
|
extraIncludes: flowExtraIncludes
|
|
2960
3103
|
});
|
|
2961
3104
|
} finally {
|
|
2962
|
-
await
|
|
3105
|
+
await fs14.remove(stagedEntry).catch(() => {
|
|
2963
3106
|
});
|
|
2964
3107
|
}
|
|
2965
|
-
const stagedRel =
|
|
3108
|
+
const stagedRel = path14.relative(await fs14.realpath(tempDir), stagedEntry);
|
|
2966
3109
|
const trimmedFileList = result.fileList.filter((f) => f !== stagedRel);
|
|
2967
|
-
await
|
|
3110
|
+
await fs14.remove(path14.join(outDir, stagedRel)).catch(() => {
|
|
2968
3111
|
});
|
|
2969
3112
|
if (declaredPackages.length > 0) {
|
|
2970
3113
|
const unused = assertDepsTraced({
|
|
@@ -2984,8 +3127,8 @@ async function runNftServerPath(outputPath, flowSettings, buildOptions, tempDir,
|
|
|
2984
3127
|
if (name.startsWith(".") || name.startsWith("/")) continue;
|
|
2985
3128
|
dependencies[name] = "*";
|
|
2986
3129
|
}
|
|
2987
|
-
const sidecarPath =
|
|
2988
|
-
await
|
|
3130
|
+
const sidecarPath = path14.join(outDir, "package.json");
|
|
3131
|
+
await fs14.writeJson(
|
|
2989
3132
|
sidecarPath,
|
|
2990
3133
|
{
|
|
2991
3134
|
name: "walkeros-bundle",
|
|
@@ -3085,7 +3228,7 @@ async function computePackageExports(usedPackages, packagePaths) {
|
|
|
3085
3228
|
const localPath = packagePaths.get(packageName);
|
|
3086
3229
|
if (!localPath) continue;
|
|
3087
3230
|
try {
|
|
3088
|
-
const pkgJson = await
|
|
3231
|
+
const pkgJson = await fs14.readJSON(path14.join(localPath, "package.json"));
|
|
3089
3232
|
const exports = pkgJson?.walkerOS?.exports;
|
|
3090
3233
|
if (exports && typeof exports === "object" && !Array.isArray(exports))
|
|
3091
3234
|
result[packageName] = Object.keys(exports);
|
|
@@ -3100,8 +3243,8 @@ async function computeDevPackages(usedPackages, packagePaths) {
|
|
|
3100
3243
|
const localPath = packagePaths.get(packageName);
|
|
3101
3244
|
if (!localPath) continue;
|
|
3102
3245
|
try {
|
|
3103
|
-
const pkgJsonPath =
|
|
3104
|
-
const pkgJson = await
|
|
3246
|
+
const pkgJsonPath = path14.join(localPath, "package.json");
|
|
3247
|
+
const pkgJson = await fs14.readJSON(pkgJsonPath);
|
|
3105
3248
|
const exports = pkgJson.exports;
|
|
3106
3249
|
if (exports && typeof exports === "object" && "./dev" in exports) {
|
|
3107
3250
|
devPackages.push(packageName);
|
|
@@ -3255,10 +3398,10 @@ ${firstError.text}`
|
|
|
3255
3398
|
function buildDataPayload(flowSettings) {
|
|
3256
3399
|
return buildSplitConfigObject(flowSettings, detectNamedImports(flowSettings)).dataPayloadObj;
|
|
3257
3400
|
}
|
|
3258
|
-
function applyCollectorProvenance(flowSettings, flowName, release2,
|
|
3401
|
+
function applyCollectorProvenance(flowSettings, flowName, release2, fallback) {
|
|
3259
3402
|
const collector = flowSettings.collector ?? {};
|
|
3260
3403
|
collector.name ??= flowName;
|
|
3261
|
-
collector.release
|
|
3404
|
+
collector.release = release2 ?? collector.release ?? fallback();
|
|
3262
3405
|
flowSettings.collector = collector;
|
|
3263
3406
|
}
|
|
3264
3407
|
function buildSplitConfigObject(flowSettings, namedImports) {
|
|
@@ -3457,7 +3600,7 @@ function generateWebEntry(stage1Path, dataPayload, options = {}) {
|
|
|
3457
3600
|
const assignments = [];
|
|
3458
3601
|
if (options.windowCollector) {
|
|
3459
3602
|
assignments.push(
|
|
3460
|
-
` if (typeof window !== 'undefined') window['${options.windowCollector}'] = collector;`
|
|
3603
|
+
` if (typeof window !== 'undefined') window['${assertWindowCollector(options.windowCollector)}'] = collector;`
|
|
3461
3604
|
);
|
|
3462
3605
|
}
|
|
3463
3606
|
const assignmentCode = assignments.length > 0 ? "\n" + assignments.join("\n") : "";
|
|
@@ -3487,7 +3630,7 @@ function generateWrapEntry(stage1Path, options = {}) {
|
|
|
3487
3630
|
const assignments = [];
|
|
3488
3631
|
if (options.windowCollector) {
|
|
3489
3632
|
assignments.push(
|
|
3490
|
-
` if (typeof window !== 'undefined') window['${options.windowCollector}'] = collector;`
|
|
3633
|
+
` if (typeof window !== 'undefined') window['${assertWindowCollector(options.windowCollector)}'] = collector;`
|
|
3491
3634
|
);
|
|
3492
3635
|
}
|
|
3493
3636
|
const assignmentCode = assignments.length > 0 ? "\n" + assignments.join("\n") : "";
|
|
@@ -3726,12 +3869,12 @@ function resolveTarget2(target) {
|
|
|
3726
3869
|
}
|
|
3727
3870
|
|
|
3728
3871
|
// src/commands/bundle/upload.ts
|
|
3729
|
-
import
|
|
3872
|
+
import fs15 from "fs-extra";
|
|
3730
3873
|
function sanitizeUrl(url) {
|
|
3731
3874
|
return url.split("?")[0];
|
|
3732
3875
|
}
|
|
3733
3876
|
async function uploadBundleToUrl(filePath, url, timeoutMs = 3e4) {
|
|
3734
|
-
const bundleContent = await
|
|
3877
|
+
const bundleContent = await fs15.readFile(filePath);
|
|
3735
3878
|
const doUpload = async (attempt) => {
|
|
3736
3879
|
const response = await fetch(url, {
|
|
3737
3880
|
method: "PUT",
|
|
@@ -3776,14 +3919,14 @@ Packages:`);
|
|
|
3776
3919
|
|
|
3777
3920
|
// src/commands/bundle/index.ts
|
|
3778
3921
|
function resolveOutputPath(output, buildOptions, flowSubdir) {
|
|
3779
|
-
const resolved =
|
|
3922
|
+
const resolved = path15.resolve(output);
|
|
3780
3923
|
const filename = buildOptions.platform === "browser" ? "walker.js" : "flow.mjs";
|
|
3781
3924
|
if (flowSubdir) {
|
|
3782
|
-
return
|
|
3925
|
+
return path15.join(resolved, flowSubdir, filename);
|
|
3783
3926
|
}
|
|
3784
|
-
const ext =
|
|
3785
|
-
if (output.endsWith("/") || output.endsWith(
|
|
3786
|
-
return
|
|
3927
|
+
const ext = path15.extname(resolved);
|
|
3928
|
+
if (output.endsWith("/") || output.endsWith(path15.sep) || !ext) {
|
|
3929
|
+
return path15.join(resolved, filename);
|
|
3787
3930
|
}
|
|
3788
3931
|
return resolved;
|
|
3789
3932
|
}
|
|
@@ -3791,26 +3934,33 @@ function isArchiveOutput(output) {
|
|
|
3791
3934
|
const lower = output.toLowerCase();
|
|
3792
3935
|
return lower.endsWith(".tar.gz") || lower.endsWith(".tgz");
|
|
3793
3936
|
}
|
|
3794
|
-
async function runBundleCoreWithArchive(flowSettings, buildOptions, logger, showStats
|
|
3937
|
+
async function runBundleCoreWithArchive(flowSettings, buildOptions, logger, showStats, provenance) {
|
|
3795
3938
|
if (!isArchiveOutput(buildOptions.output)) {
|
|
3796
|
-
return bundleCore(
|
|
3939
|
+
return bundleCore(
|
|
3940
|
+
flowSettings,
|
|
3941
|
+
buildOptions,
|
|
3942
|
+
logger,
|
|
3943
|
+
showStats,
|
|
3944
|
+
provenance
|
|
3945
|
+
);
|
|
3797
3946
|
}
|
|
3798
3947
|
if (buildOptions.platform !== "node") {
|
|
3799
3948
|
throw new Error(
|
|
3800
|
-
`Archive output (${
|
|
3949
|
+
`Archive output (${path15.extname(buildOptions.output)}) is only supported for server (node) flows. Web bundles are a single-file IIFE with no node_modules to pack \u2014 use a .js output instead.`
|
|
3801
3950
|
);
|
|
3802
3951
|
}
|
|
3803
|
-
const archivePath =
|
|
3952
|
+
const archivePath = path15.resolve(buildOptions.output);
|
|
3804
3953
|
const tempDir = await tmpRunDir("archive");
|
|
3805
3954
|
try {
|
|
3806
3955
|
const stats = await bundleCore(
|
|
3807
3956
|
flowSettings,
|
|
3808
|
-
{ ...buildOptions, output:
|
|
3957
|
+
{ ...buildOptions, output: path15.join(tempDir, "flow.mjs") },
|
|
3809
3958
|
logger,
|
|
3810
|
-
showStats
|
|
3959
|
+
showStats,
|
|
3960
|
+
provenance
|
|
3811
3961
|
);
|
|
3812
3962
|
for (const required of ["flow.mjs", "package.json"]) {
|
|
3813
|
-
if (!await
|
|
3963
|
+
if (!await fs16.pathExists(path15.join(tempDir, required))) {
|
|
3814
3964
|
throw new Error(
|
|
3815
3965
|
`Bundle archive build is missing ${required}; cannot pack ${archivePath}.`
|
|
3816
3966
|
);
|
|
@@ -3819,14 +3969,14 @@ async function runBundleCoreWithArchive(flowSettings, buildOptions, logger, show
|
|
|
3819
3969
|
const candidates = ["flow.mjs", "node_modules", "package.json"];
|
|
3820
3970
|
const entries = [];
|
|
3821
3971
|
for (const entry of candidates) {
|
|
3822
|
-
if (await
|
|
3972
|
+
if (await fs16.pathExists(path15.join(tempDir, entry))) entries.push(entry);
|
|
3823
3973
|
}
|
|
3824
|
-
await
|
|
3974
|
+
await fs16.ensureDir(path15.dirname(archivePath));
|
|
3825
3975
|
await packBundleDir(tempDir, archivePath, entries);
|
|
3826
3976
|
logger.debug(`Packed bundle archive: ${archivePath}`);
|
|
3827
3977
|
return stats;
|
|
3828
3978
|
} finally {
|
|
3829
|
-
await
|
|
3979
|
+
await fs16.remove(tempDir).catch(() => {
|
|
3830
3980
|
});
|
|
3831
3981
|
}
|
|
3832
3982
|
}
|
|
@@ -3861,7 +4011,7 @@ async function bundleCommand(options) {
|
|
|
3861
4011
|
} catch {
|
|
3862
4012
|
throw new Error("Invalid JSON received on stdin");
|
|
3863
4013
|
}
|
|
3864
|
-
configPath =
|
|
4014
|
+
configPath = path15.resolve(process.cwd(), "stdin.config.json");
|
|
3865
4015
|
} else {
|
|
3866
4016
|
const file = options.config || "bundle.config.json";
|
|
3867
4017
|
configPath = resolveAsset(file, "config");
|
|
@@ -3879,18 +4029,18 @@ async function bundleCommand(options) {
|
|
|
3879
4029
|
flowSettings,
|
|
3880
4030
|
buildOptions,
|
|
3881
4031
|
flowName,
|
|
3882
|
-
isMultiFlow
|
|
4032
|
+
isMultiFlow,
|
|
4033
|
+
configDigest: configDigest2
|
|
3883
4034
|
} of configsToBundle) {
|
|
3884
4035
|
try {
|
|
3885
4036
|
if (options.cache !== void 0) {
|
|
3886
4037
|
buildOptions.cache = options.cache;
|
|
3887
4038
|
}
|
|
3888
|
-
applyCollectorProvenance(flowSettings, flowName, options.release);
|
|
3889
4039
|
const outputIsUrl = options.output ? isUrl(options.output) : false;
|
|
3890
4040
|
const uploadUrl = outputIsUrl ? options.output : void 0;
|
|
3891
4041
|
if (outputIsUrl) {
|
|
3892
4042
|
const ext = buildOptions.platform === "browser" ? ".js" : ".mjs";
|
|
3893
|
-
buildOptions.output =
|
|
4043
|
+
buildOptions.output = path15.join(
|
|
3894
4044
|
await tmpRunDir("bundle"),
|
|
3895
4045
|
`bundle${ext}`
|
|
3896
4046
|
);
|
|
@@ -3914,19 +4064,20 @@ async function bundleCommand(options) {
|
|
|
3914
4064
|
flowSettings,
|
|
3915
4065
|
buildOptions,
|
|
3916
4066
|
logger,
|
|
3917
|
-
shouldCollectStats
|
|
4067
|
+
shouldCollectStats === true,
|
|
4068
|
+
{ flowName, release: options.release, configDigest: configDigest2 }
|
|
3918
4069
|
);
|
|
3919
4070
|
results.push({ flowName, success: true, stats });
|
|
3920
4071
|
if (uploadUrl) {
|
|
3921
4072
|
await uploadBundleToUrl(buildOptions.output, uploadUrl);
|
|
3922
4073
|
logger.info(`Uploaded to: ${sanitizeUrl(uploadUrl)}`);
|
|
3923
|
-
await
|
|
4074
|
+
await fs16.remove(path15.dirname(buildOptions.output));
|
|
3924
4075
|
}
|
|
3925
4076
|
if (!options.json && !options.all && options.stats && stats) {
|
|
3926
4077
|
displayStats(stats, logger);
|
|
3927
4078
|
}
|
|
3928
4079
|
if (writingToStdout && !options.json) {
|
|
3929
|
-
const bundleContent = await
|
|
4080
|
+
const bundleContent = await fs16.readFile(buildOptions.output);
|
|
3930
4081
|
await writeResult(bundleContent, {});
|
|
3931
4082
|
if (process.stdout.isTTY) {
|
|
3932
4083
|
const defaultPath = buildOptions.platform === "browser" ? "./dist/walker.js" : "./dist/flow.mjs";
|
|
@@ -4009,7 +4160,7 @@ async function bundle(configOrPath, options = {}) {
|
|
|
4009
4160
|
);
|
|
4010
4161
|
}
|
|
4011
4162
|
let rawConfig;
|
|
4012
|
-
let configPath =
|
|
4163
|
+
let configPath = path15.resolve(process.cwd(), "walkeros.config.json");
|
|
4013
4164
|
if (typeof configOrPath === "string") {
|
|
4014
4165
|
configPath = resolveAsset(configOrPath, "config");
|
|
4015
4166
|
rawConfig = await loadJsonConfig(configPath);
|
|
@@ -4022,13 +4173,12 @@ async function bundle(configOrPath, options = {}) {
|
|
|
4022
4173
|
withDev: preset.withDev,
|
|
4023
4174
|
externalizeDev: preset.externalizeDev
|
|
4024
4175
|
};
|
|
4025
|
-
const { flowSettings, buildOptions, flowName } = loadBundleConfig(rawConfig, {
|
|
4176
|
+
const { flowSettings, buildOptions, flowName, configDigest: configDigest2 } = loadBundleConfig(rawConfig, {
|
|
4026
4177
|
configPath,
|
|
4027
4178
|
flowName: options.flowName,
|
|
4028
4179
|
buildOverrides: mergedOverrides,
|
|
4029
4180
|
buildEnv: options.buildEnv
|
|
4030
4181
|
});
|
|
4031
|
-
applyCollectorProvenance(flowSettings, flowName, options.release);
|
|
4032
4182
|
if (options.cache !== void 0) {
|
|
4033
4183
|
buildOptions.cache = options.cache;
|
|
4034
4184
|
}
|
|
@@ -4037,13 +4187,14 @@ async function bundle(configOrPath, options = {}) {
|
|
|
4037
4187
|
flowSettings,
|
|
4038
4188
|
buildOptions,
|
|
4039
4189
|
logger,
|
|
4040
|
-
options.stats ?? false
|
|
4190
|
+
options.stats ?? false,
|
|
4191
|
+
{ flowName, release: options.release, configDigest: configDigest2 }
|
|
4041
4192
|
);
|
|
4042
4193
|
}
|
|
4043
4194
|
|
|
4044
4195
|
// src/commands/push/index.ts
|
|
4045
|
-
import
|
|
4046
|
-
import
|
|
4196
|
+
import path18 from "path";
|
|
4197
|
+
import fs18 from "fs-extra";
|
|
4047
4198
|
import { createIngest, getPlatform as getPlatform3, stepId } from "@walkeros/core";
|
|
4048
4199
|
import {
|
|
4049
4200
|
enrichEvent,
|
|
@@ -4054,7 +4205,7 @@ import {
|
|
|
4054
4205
|
} from "@walkeros/collector";
|
|
4055
4206
|
|
|
4056
4207
|
// src/core/redact-line.ts
|
|
4057
|
-
import { scrubSecrets, redactLine } from "@walkeros/core/node";
|
|
4208
|
+
import { scrubJson, scrubSecrets, redactLine } from "@walkeros/core/node";
|
|
4058
4209
|
|
|
4059
4210
|
// src/core/to-printable.ts
|
|
4060
4211
|
import { toPrintable } from "@walkeros/core/node";
|
|
@@ -4251,7 +4402,7 @@ function applyOverrides(config, overrides) {
|
|
|
4251
4402
|
}
|
|
4252
4403
|
|
|
4253
4404
|
// src/commands/push/flow-context.ts
|
|
4254
|
-
import
|
|
4405
|
+
import path16 from "path";
|
|
4255
4406
|
import { pathToFileURL } from "url";
|
|
4256
4407
|
import { JSDOM, VirtualConsole } from "jsdom";
|
|
4257
4408
|
|
|
@@ -4310,7 +4461,7 @@ function installTimerInterception(options = {}) {
|
|
|
4310
4461
|
if (options.domWindow && options.domWindow !== globalThis) {
|
|
4311
4462
|
patchTarget(options.domWindow);
|
|
4312
4463
|
}
|
|
4313
|
-
const drainMicrotasks = () => new Promise((
|
|
4464
|
+
const drainMicrotasks = () => new Promise((resolve5) => realSetTimeout(resolve5, 0));
|
|
4314
4465
|
async function flush(wallTimeout = 5e3) {
|
|
4315
4466
|
const deadline = Date.now() + wallTimeout;
|
|
4316
4467
|
const maxIterations = 100;
|
|
@@ -4405,7 +4556,12 @@ var DOM_GLOBALS = [
|
|
|
4405
4556
|
"CustomEvent",
|
|
4406
4557
|
"Event",
|
|
4407
4558
|
"localStorage",
|
|
4408
|
-
"sessionStorage"
|
|
4559
|
+
"sessionStorage",
|
|
4560
|
+
"Node",
|
|
4561
|
+
"Element",
|
|
4562
|
+
"HTMLElement",
|
|
4563
|
+
"Document",
|
|
4564
|
+
"ShadowRoot"
|
|
4409
4565
|
];
|
|
4410
4566
|
function exposeDomGlobals(domWindow) {
|
|
4411
4567
|
const saved = DOM_GLOBALS.map(
|
|
@@ -4495,7 +4651,7 @@ async function withFlowContext(options, fn, onError) {
|
|
|
4495
4651
|
vm.runInThisContext(snapshotCode);
|
|
4496
4652
|
}
|
|
4497
4653
|
}
|
|
4498
|
-
const fileUrl = pathToFileURL(
|
|
4654
|
+
const fileUrl = pathToFileURL(path16.resolve(esmPath)).href;
|
|
4499
4655
|
const module = await import(`${fileUrl}?t=${Date.now()}`);
|
|
4500
4656
|
const { wireConfig, startFlow: startFlow2 } = module;
|
|
4501
4657
|
if (typeof wireConfig !== "function" || typeof startFlow2 !== "function") {
|
|
@@ -4618,14 +4774,44 @@ function buildSimulationResult(args) {
|
|
|
4618
4774
|
}
|
|
4619
4775
|
|
|
4620
4776
|
// src/commands/push/prepare.ts
|
|
4621
|
-
import
|
|
4622
|
-
import
|
|
4777
|
+
import path17 from "path";
|
|
4778
|
+
import fs17 from "fs-extra";
|
|
4623
4779
|
import { getPlatform as getPlatform2 } from "@walkeros/core";
|
|
4780
|
+
|
|
4781
|
+
// src/core/known-secrets.ts
|
|
4782
|
+
import { REF_SECRET } from "@walkeros/core";
|
|
4783
|
+
function collectKnownSecrets(flow, env = process.env) {
|
|
4784
|
+
const names = /* @__PURE__ */ new Set();
|
|
4785
|
+
collectSecretNames(flow, names);
|
|
4786
|
+
const values = /* @__PURE__ */ new Set();
|
|
4787
|
+
for (const name of names) {
|
|
4788
|
+
const value = env[name];
|
|
4789
|
+
if (value) values.add(value);
|
|
4790
|
+
}
|
|
4791
|
+
return [...values];
|
|
4792
|
+
}
|
|
4793
|
+
function collectSecretNames(value, names) {
|
|
4794
|
+
if (typeof value === "string") {
|
|
4795
|
+
const match = value.match(REF_SECRET);
|
|
4796
|
+
if (match) names.add(match[1]);
|
|
4797
|
+
return;
|
|
4798
|
+
}
|
|
4799
|
+
if (Array.isArray(value)) {
|
|
4800
|
+
for (const item of value) collectSecretNames(item, names);
|
|
4801
|
+
return;
|
|
4802
|
+
}
|
|
4803
|
+
if (value && typeof value === "object") {
|
|
4804
|
+
for (const item of Object.values(value)) collectSecretNames(item, names);
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
// src/commands/push/prepare.ts
|
|
4624
4809
|
async function prepareFlow(input) {
|
|
4625
4810
|
const logger = createCLILogger({
|
|
4626
4811
|
silent: input.silent,
|
|
4627
4812
|
verbose: input.verbose,
|
|
4628
|
-
stderr: input.json
|
|
4813
|
+
stderr: input.json,
|
|
4814
|
+
knownSecrets: collectKnownSecrets(input.config)
|
|
4629
4815
|
});
|
|
4630
4816
|
logger.debug("Loading flow configuration");
|
|
4631
4817
|
const { flowSettings, buildOptions } = loadBundleConfig(input.config, {
|
|
@@ -4649,7 +4835,7 @@ async function prepareFlow(input) {
|
|
|
4649
4835
|
}
|
|
4650
4836
|
logger.debug("Bundling flow configuration");
|
|
4651
4837
|
const tempDir = await tmpRunDir("push");
|
|
4652
|
-
const bundlePath =
|
|
4838
|
+
const bundlePath = path17.join(tempDir, "flow.mjs");
|
|
4653
4839
|
const pushBuildOptions = {
|
|
4654
4840
|
...buildOptions,
|
|
4655
4841
|
output: bundlePath,
|
|
@@ -4666,7 +4852,7 @@ async function prepareFlow(input) {
|
|
|
4666
4852
|
overrides,
|
|
4667
4853
|
flowSettings,
|
|
4668
4854
|
cleanup: async () => {
|
|
4669
|
-
await
|
|
4855
|
+
await fs17.remove(tempDir).catch(() => {
|
|
4670
4856
|
});
|
|
4671
4857
|
}
|
|
4672
4858
|
};
|
|
@@ -4710,51 +4896,6 @@ function dispatchSimulate(flags) {
|
|
|
4710
4896
|
return { kind: plan.kind, ids: plan.ids };
|
|
4711
4897
|
}
|
|
4712
4898
|
|
|
4713
|
-
// src/core/known-secrets.ts
|
|
4714
|
-
import { REF_SECRET } from "@walkeros/core";
|
|
4715
|
-
function collectKnownSecrets(flow, env = process.env) {
|
|
4716
|
-
const names = /* @__PURE__ */ new Set();
|
|
4717
|
-
collectSecretNames(flow, names);
|
|
4718
|
-
const values = /* @__PURE__ */ new Set();
|
|
4719
|
-
for (const name of names) {
|
|
4720
|
-
const value = env[name];
|
|
4721
|
-
if (value) values.add(value);
|
|
4722
|
-
}
|
|
4723
|
-
return [...values];
|
|
4724
|
-
}
|
|
4725
|
-
function collectSecretNames(value, names) {
|
|
4726
|
-
if (typeof value === "string") {
|
|
4727
|
-
const match = value.match(REF_SECRET);
|
|
4728
|
-
if (match) names.add(match[1]);
|
|
4729
|
-
return;
|
|
4730
|
-
}
|
|
4731
|
-
if (Array.isArray(value)) {
|
|
4732
|
-
for (const item of value) collectSecretNames(item, names);
|
|
4733
|
-
return;
|
|
4734
|
-
}
|
|
4735
|
-
if (value && typeof value === "object") {
|
|
4736
|
-
for (const item of Object.values(value)) collectSecretNames(item, names);
|
|
4737
|
-
}
|
|
4738
|
-
}
|
|
4739
|
-
var MIN_KNOWN_LEN = 6;
|
|
4740
|
-
function maskKnownNumbers(value, known) {
|
|
4741
|
-
const candidates = known.filter((secret) => secret.length >= MIN_KNOWN_LEN);
|
|
4742
|
-
const mask = (item) => {
|
|
4743
|
-
if (typeof item === "number") {
|
|
4744
|
-
const printed = String(item);
|
|
4745
|
-
return candidates.some((secret) => printed.includes(secret)) ? "***" : item;
|
|
4746
|
-
}
|
|
4747
|
-
if (Array.isArray(item)) return item.map(mask);
|
|
4748
|
-
if (item && typeof item === "object") {
|
|
4749
|
-
const copy = {};
|
|
4750
|
-
for (const [key, entry] of Object.entries(item)) copy[key] = mask(entry);
|
|
4751
|
-
return copy;
|
|
4752
|
-
}
|
|
4753
|
-
return item;
|
|
4754
|
-
};
|
|
4755
|
-
return mask(value);
|
|
4756
|
-
}
|
|
4757
|
-
|
|
4758
4899
|
// src/commands/push/run.ts
|
|
4759
4900
|
import { isObject as isObject3 } from "@walkeros/core";
|
|
4760
4901
|
function simulationToPushResult(result) {
|
|
@@ -4951,22 +5092,22 @@ async function runDestinationSimulationLoop(config, event, destinationIds, optio
|
|
|
4951
5092
|
}
|
|
4952
5093
|
|
|
4953
5094
|
// src/commands/push/dev-examples.ts
|
|
4954
|
-
function
|
|
5095
|
+
function isRecord2(value) {
|
|
4955
5096
|
return value !== null && typeof value === "object";
|
|
4956
5097
|
}
|
|
4957
5098
|
function selectDevExamples(devModule, exportName) {
|
|
4958
|
-
if (!
|
|
5099
|
+
if (!isRecord2(devModule)) return void 0;
|
|
4959
5100
|
const map = devModule.exportExamples;
|
|
4960
|
-
if (
|
|
5101
|
+
if (isRecord2(map) && exportName !== void 0) {
|
|
4961
5102
|
const selected = map[exportName];
|
|
4962
|
-
return
|
|
5103
|
+
return isRecord2(selected) ? selected : void 0;
|
|
4963
5104
|
}
|
|
4964
5105
|
const examples = devModule.examples;
|
|
4965
|
-
return
|
|
5106
|
+
return isRecord2(examples) ? examples : void 0;
|
|
4966
5107
|
}
|
|
4967
5108
|
function legacyExportRefusal(devModule, packageExports, packageName, exportName) {
|
|
4968
5109
|
if (exportName === void 0) return void 0;
|
|
4969
|
-
if (
|
|
5110
|
+
if (isRecord2(devModule) && isRecord2(devModule.exportExamples))
|
|
4970
5111
|
return void 0;
|
|
4971
5112
|
if (packageExports) {
|
|
4972
5113
|
const declared = packageExports[packageName];
|
|
@@ -5014,11 +5155,11 @@ function resolveExportName(flow, kind, id) {
|
|
|
5014
5155
|
}
|
|
5015
5156
|
|
|
5016
5157
|
// src/commands/push/index.ts
|
|
5017
|
-
function
|
|
5158
|
+
function isRecord3(value) {
|
|
5018
5159
|
return value !== null && typeof value === "object";
|
|
5019
5160
|
}
|
|
5020
5161
|
function isFlowJson(value) {
|
|
5021
|
-
return
|
|
5162
|
+
return isRecord3(value) && isRecord3(value.flows);
|
|
5022
5163
|
}
|
|
5023
5164
|
function isString(value) {
|
|
5024
5165
|
return typeof value === "string";
|
|
@@ -5036,9 +5177,9 @@ function getDevEnv(devModule, exportName) {
|
|
|
5036
5177
|
const examples = selectDevExamples(devModule, exportName);
|
|
5037
5178
|
if (!examples || !("env" in examples)) return void 0;
|
|
5038
5179
|
const env = examples.env;
|
|
5039
|
-
if (!
|
|
5180
|
+
if (!isRecord3(env)) return void 0;
|
|
5040
5181
|
const result = {};
|
|
5041
|
-
if ("push" in env &&
|
|
5182
|
+
if ("push" in env && isRecord3(env.push)) result.push = env.push;
|
|
5042
5183
|
if ("simulation" in env && isStringArray(env.simulation))
|
|
5043
5184
|
result.simulation = env.simulation;
|
|
5044
5185
|
return result;
|
|
@@ -5046,14 +5187,14 @@ function getDevEnv(devModule, exportName) {
|
|
|
5046
5187
|
async function applyStoreMockEnvs(flowConfig, flowSettings, devExports) {
|
|
5047
5188
|
const unmocked = [];
|
|
5048
5189
|
const stores = flowConfig.stores;
|
|
5049
|
-
if (!
|
|
5190
|
+
if (!isRecord3(stores)) return unmocked;
|
|
5050
5191
|
for (const [storeId, storeDef] of Object.entries(stores)) {
|
|
5051
5192
|
const packageName = flowSettings.stores?.[storeId]?.package;
|
|
5052
5193
|
const loadDev = packageName ? devExports?.[packageName] : void 0;
|
|
5053
5194
|
const devModule = typeof loadDev === "function" ? await loadDev() : void 0;
|
|
5054
5195
|
const { exportName } = resolveExportName(flowSettings, "store", storeId);
|
|
5055
5196
|
const push2 = getDevEnv(devModule, exportName)?.push;
|
|
5056
|
-
if (!push2 || !
|
|
5197
|
+
if (!push2 || !isRecord3(storeDef)) {
|
|
5057
5198
|
unmocked.push(storeId);
|
|
5058
5199
|
continue;
|
|
5059
5200
|
}
|
|
@@ -5065,10 +5206,12 @@ function isStringArray(value) {
|
|
|
5065
5206
|
return Array.isArray(value) && value.every(isString);
|
|
5066
5207
|
}
|
|
5067
5208
|
async function pushCore(inputPath, event, options = {}) {
|
|
5209
|
+
let known = options.knownSecrets ?? [];
|
|
5068
5210
|
const logger = createCLILogger({
|
|
5069
5211
|
silent: options.silent,
|
|
5070
5212
|
verbose: options.verbose,
|
|
5071
|
-
stderr: options.json
|
|
5213
|
+
stderr: options.json,
|
|
5214
|
+
knownSecrets: () => known
|
|
5072
5215
|
});
|
|
5073
5216
|
const startTime = Date.now();
|
|
5074
5217
|
let tempDir;
|
|
@@ -5089,6 +5232,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
5089
5232
|
if (detected.type === "config") {
|
|
5090
5233
|
const raw = options.raw !== void 0 ? options.raw : "content" in detected ? JSON.parse(detected.content) : void 0;
|
|
5091
5234
|
const knownSecrets = options.knownSecrets ?? (isFlowJson(raw) ? collectKnownSecrets(raw) : []);
|
|
5235
|
+
known = knownSecrets;
|
|
5092
5236
|
result = await executeConfigPush(
|
|
5093
5237
|
{
|
|
5094
5238
|
config: inputPath,
|
|
@@ -5129,7 +5273,7 @@ async function pushCore(inputPath, event, options = {}) {
|
|
|
5129
5273
|
};
|
|
5130
5274
|
} finally {
|
|
5131
5275
|
if (tempDir) {
|
|
5132
|
-
await
|
|
5276
|
+
await fs18.remove(tempDir).catch(() => {
|
|
5133
5277
|
});
|
|
5134
5278
|
}
|
|
5135
5279
|
}
|
|
@@ -5145,14 +5289,9 @@ async function pushCommand(options) {
|
|
|
5145
5289
|
}
|
|
5146
5290
|
function renderPushOutput(result, options = {}) {
|
|
5147
5291
|
const knownSecrets = options.knownSecrets ?? [];
|
|
5148
|
-
return scrubSecrets(
|
|
5149
|
-
|
|
5150
|
-
|
|
5151
|
-
null,
|
|
5152
|
-
2
|
|
5153
|
-
) : formatPushResult(result, { knownSecrets }),
|
|
5154
|
-
{ known: knownSecrets }
|
|
5155
|
-
);
|
|
5292
|
+
return options.json ? scrubJson(result, { known: knownSecrets, space: 2 }) : scrubSecrets(formatPushResult(result, { knownSecrets }), {
|
|
5293
|
+
known: knownSecrets
|
|
5294
|
+
});
|
|
5156
5295
|
}
|
|
5157
5296
|
var MAX_CALL_ARGS_LENGTH = 300;
|
|
5158
5297
|
function compactJson(value) {
|
|
@@ -5206,7 +5345,7 @@ function formatPushResult(result, options = {}) {
|
|
|
5206
5345
|
const lines = [];
|
|
5207
5346
|
lines.push(`success: ${result.success}`);
|
|
5208
5347
|
if (result.success) {
|
|
5209
|
-
const elbResult =
|
|
5348
|
+
const elbResult = isRecord3(result.elbResult) ? result.elbResult : void 0;
|
|
5210
5349
|
if (elbResult) {
|
|
5211
5350
|
if (typeof elbResult.id === "string")
|
|
5212
5351
|
lines.push(` Event ID: ${elbResult.id}`);
|
|
@@ -5260,7 +5399,7 @@ async function executeConfigPush(options, validatedEvent, logger, setTempDir, lo
|
|
|
5260
5399
|
logger.debug("Bundling flow configuration");
|
|
5261
5400
|
const tempDir = await tmpRunDir("push");
|
|
5262
5401
|
setTempDir(tempDir);
|
|
5263
|
-
const tempPath =
|
|
5402
|
+
const tempPath = path18.join(tempDir, "flow.mjs");
|
|
5264
5403
|
const pushBuildOptions = {
|
|
5265
5404
|
...buildOptions,
|
|
5266
5405
|
output: tempPath,
|
|
@@ -5289,8 +5428,8 @@ async function executeConfigPush(options, validatedEvent, logger, setTempDir, lo
|
|
|
5289
5428
|
async function executeBundlePush(bundleContent, platform, validatedEvent, logger, setTempDir, overrides = {}, snapshotCode, flowLogs = {}) {
|
|
5290
5429
|
const tempDir = await tmpRunDir("push");
|
|
5291
5430
|
setTempDir(tempDir);
|
|
5292
|
-
const tempPath =
|
|
5293
|
-
await
|
|
5431
|
+
const tempPath = path18.join(tempDir, "flow.mjs");
|
|
5432
|
+
await fs18.writeFile(tempPath, bundleContent, "utf8");
|
|
5294
5433
|
logger.debug(`Bundle written to: ${tempPath}`);
|
|
5295
5434
|
logger.debug(
|
|
5296
5435
|
`Executing in ${platform} environment (${platform === "web" ? "JSDOM" : "Node.js"})`
|
|
@@ -5399,9 +5538,9 @@ function resolvePageUrl(input, pageUrl) {
|
|
|
5399
5538
|
return parsed.href;
|
|
5400
5539
|
}
|
|
5401
5540
|
function triggerUrl(input) {
|
|
5402
|
-
if (!
|
|
5541
|
+
if (!isRecord3(input) || !isRecord3(input.trigger)) return void 0;
|
|
5403
5542
|
const { options } = input.trigger;
|
|
5404
|
-
return
|
|
5543
|
+
return isRecord3(options) && isString(options.url) ? options.url : void 0;
|
|
5405
5544
|
}
|
|
5406
5545
|
function isSourceInit(value) {
|
|
5407
5546
|
return typeof value === "function";
|
|
@@ -5527,12 +5666,12 @@ async function simulateSource(configOrPath, input, options) {
|
|
|
5527
5666
|
`Stores without a mock env run as configured: ${unmockedStores.join(", ")}`
|
|
5528
5667
|
);
|
|
5529
5668
|
const wiredSources = flowConfig.sources;
|
|
5530
|
-
const wiredSource =
|
|
5531
|
-
const source =
|
|
5669
|
+
const wiredSource = isRecord3(wiredSources) ? wiredSources[options.sourceId] : void 0;
|
|
5670
|
+
const source = isRecord3(
|
|
5532
5671
|
wiredSource
|
|
5533
5672
|
) ? {
|
|
5534
5673
|
...wiredSource,
|
|
5535
|
-
...
|
|
5674
|
+
...isRecord3(wiredSource.config) ? { config: { ...wiredSource.config } } : {}
|
|
5536
5675
|
} : void 0;
|
|
5537
5676
|
flowConfig.sources = source ? { [options.sourceId]: source } : {};
|
|
5538
5677
|
const commandCalls = [];
|
|
@@ -5546,7 +5685,7 @@ async function simulateSource(configOrPath, input, options) {
|
|
|
5546
5685
|
simulation: devEnv.simulation
|
|
5547
5686
|
});
|
|
5548
5687
|
source.env = {
|
|
5549
|
-
...
|
|
5688
|
+
...isRecord3(source.env) ? source.env : {},
|
|
5550
5689
|
...wrappedEnv
|
|
5551
5690
|
};
|
|
5552
5691
|
trackedCalls = calls;
|
|
@@ -5897,10 +6036,10 @@ async function simulateCollector(configOrPath, event, options) {
|
|
|
5897
6036
|
}
|
|
5898
6037
|
}
|
|
5899
6038
|
function isConsentRecord(value) {
|
|
5900
|
-
return
|
|
6039
|
+
return isRecord3(value) && Object.values(value).every((granted) => typeof granted === "boolean");
|
|
5901
6040
|
}
|
|
5902
6041
|
function pendingRequire(definition) {
|
|
5903
|
-
if (!
|
|
6042
|
+
if (!isRecord3(definition) || !isRecord3(definition.config)) return [];
|
|
5904
6043
|
const { require: require2 } = definition.config;
|
|
5905
6044
|
return isStringArray(require2) ? require2 : [];
|
|
5906
6045
|
}
|
|
@@ -5970,16 +6109,16 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
5970
6109
|
options.data ?? module.__configData ?? void 0
|
|
5971
6110
|
);
|
|
5972
6111
|
const wiredDestinations = flowConfig.destinations;
|
|
5973
|
-
const wiredTarget =
|
|
5974
|
-
if (!
|
|
5975
|
-
const available =
|
|
6112
|
+
const wiredTarget = isRecord3(wiredDestinations) ? wiredDestinations[options.destinationId] : void 0;
|
|
6113
|
+
if (!isRecord3(wiredTarget)) {
|
|
6114
|
+
const available = isRecord3(wiredDestinations) ? Object.keys(wiredDestinations).join(", ") : "";
|
|
5976
6115
|
throw new Error(
|
|
5977
6116
|
`Destination "${options.destinationId}" not found in collector. Available: ${available || "none"}`
|
|
5978
6117
|
);
|
|
5979
6118
|
}
|
|
5980
6119
|
const target = {
|
|
5981
6120
|
...wiredTarget,
|
|
5982
|
-
config:
|
|
6121
|
+
config: isRecord3(wiredTarget.config) ? { ...wiredTarget.config } : {}
|
|
5983
6122
|
};
|
|
5984
6123
|
flowConfig.destinations = { [options.destinationId]: target };
|
|
5985
6124
|
if (flowConfig.sources) flowConfig.sources = {};
|
|
@@ -6019,7 +6158,7 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
6019
6158
|
);
|
|
6020
6159
|
}
|
|
6021
6160
|
const destConfig = target.config;
|
|
6022
|
-
if (
|
|
6161
|
+
if (isRecord3(destConfig)) {
|
|
6023
6162
|
destConfig.env = devEnv.push;
|
|
6024
6163
|
}
|
|
6025
6164
|
if (devEnv.simulation?.length) {
|
|
@@ -6028,7 +6167,7 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
6028
6167
|
simulation: devEnv.simulation
|
|
6029
6168
|
};
|
|
6030
6169
|
const { wrappedEnv, calls } = wrapEnv(combined);
|
|
6031
|
-
if (
|
|
6170
|
+
if (isRecord3(destConfig)) destConfig.env = wrappedEnv;
|
|
6032
6171
|
trackedCalls = calls;
|
|
6033
6172
|
}
|
|
6034
6173
|
}
|
|
@@ -6115,7 +6254,10 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
6115
6254
|
}
|
|
6116
6255
|
|
|
6117
6256
|
// src/commands/validate/index.ts
|
|
6257
|
+
import * as fs20 from "fs";
|
|
6258
|
+
import * as path20 from "path";
|
|
6118
6259
|
import chalk2 from "chalk";
|
|
6260
|
+
import { isObject as isObject9 } from "@walkeros/core";
|
|
6119
6261
|
|
|
6120
6262
|
// src/commands/validate/validators/contract.ts
|
|
6121
6263
|
import { isObject as isObject4 } from "@walkeros/core";
|
|
@@ -6242,21 +6384,28 @@ function validateContract(input) {
|
|
|
6242
6384
|
}
|
|
6243
6385
|
}
|
|
6244
6386
|
}
|
|
6387
|
+
const reportedCycles = /* @__PURE__ */ new Set();
|
|
6245
6388
|
for (const name of contractNames) {
|
|
6246
|
-
const
|
|
6389
|
+
const chain = [];
|
|
6247
6390
|
let current = name;
|
|
6248
6391
|
while (current) {
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6392
|
+
const start = chain.indexOf(current);
|
|
6393
|
+
if (start !== -1) {
|
|
6394
|
+
const cycle = chain.slice(start);
|
|
6395
|
+
const key = [...cycle].sort().join("\0");
|
|
6396
|
+
if (!reportedCycles.has(key)) {
|
|
6397
|
+
reportedCycles.add(key);
|
|
6398
|
+
errors.push({
|
|
6399
|
+
path: `${cycle[0]}.extend`,
|
|
6400
|
+
message: `Circular extend chain: ${[...cycle, current].join(" \u2192 ")}`,
|
|
6401
|
+
code: "CIRCULAR_EXTENDS"
|
|
6402
|
+
});
|
|
6403
|
+
}
|
|
6255
6404
|
break;
|
|
6256
6405
|
}
|
|
6257
|
-
|
|
6406
|
+
chain.push(current);
|
|
6258
6407
|
const entry = contracts[current];
|
|
6259
|
-
current = entry
|
|
6408
|
+
current = isObject4(entry) && typeof entry.extend === "string" ? entry.extend : "";
|
|
6260
6409
|
}
|
|
6261
6410
|
}
|
|
6262
6411
|
return {
|
|
@@ -6323,21 +6472,25 @@ function validateEvent2(input) {
|
|
|
6323
6472
|
|
|
6324
6473
|
// src/commands/validate/validators/flow.ts
|
|
6325
6474
|
import {
|
|
6475
|
+
checkWindowCollector as checkWindowCollector2,
|
|
6476
|
+
ENV_MARKER_PREFIX as ENV_MARKER_PREFIX3,
|
|
6326
6477
|
getByPath,
|
|
6327
|
-
getFlowSettings as getFlowSettings2,
|
|
6328
6478
|
getRouteGraph,
|
|
6329
|
-
isObject as
|
|
6479
|
+
isObject as isObject7,
|
|
6330
6480
|
REF_CONTRACT,
|
|
6331
6481
|
resolveContracts,
|
|
6332
6482
|
validateStepEntry
|
|
6333
6483
|
} from "@walkeros/core";
|
|
6334
|
-
import { schemas as schemas4 } from "@walkeros/core/dev";
|
|
6484
|
+
import { schemas as schemas4, validateFlowStructure } from "@walkeros/core/dev";
|
|
6335
6485
|
import {
|
|
6336
6486
|
validateEventAgainstContract
|
|
6337
6487
|
} from "@walkeros/transformer-validate";
|
|
6338
6488
|
|
|
6339
6489
|
// src/commands/validate/scope.ts
|
|
6340
6490
|
import { isObject as isObject5 } from "@walkeros/core";
|
|
6491
|
+
function isFlowJson2(value) {
|
|
6492
|
+
return isObject5(value) && "version" in value && isObject5(value.flows);
|
|
6493
|
+
}
|
|
6341
6494
|
var ENTRY_SECTIONS = [
|
|
6342
6495
|
"sources",
|
|
6343
6496
|
"destinations",
|
|
@@ -6370,11 +6523,11 @@ function resolveScope(config, options = {}) {
|
|
|
6370
6523
|
}
|
|
6371
6524
|
flows = [options.flow];
|
|
6372
6525
|
}
|
|
6373
|
-
const
|
|
6374
|
-
if (
|
|
6526
|
+
const path23 = options.path;
|
|
6527
|
+
if (path23 === void 0) {
|
|
6375
6528
|
return { allFlows, flows, entries: [], searchedFlows: [], errors: [] };
|
|
6376
6529
|
}
|
|
6377
|
-
const parts =
|
|
6530
|
+
const parts = path23.split(".");
|
|
6378
6531
|
let sections = ENTRY_SECTIONS;
|
|
6379
6532
|
let section;
|
|
6380
6533
|
let key;
|
|
@@ -6387,7 +6540,7 @@ function resolveScope(config, options = {}) {
|
|
|
6387
6540
|
searchedFlows: [],
|
|
6388
6541
|
errors: [
|
|
6389
6542
|
{
|
|
6390
|
-
path:
|
|
6543
|
+
path: path23,
|
|
6391
6544
|
message: `Section "${parts[0]}" cannot be addressed by --path. Use one of: ${ENTRY_SECTIONS.join(", ")}`,
|
|
6392
6545
|
code: "UNSUPPORTED_SECTION"
|
|
6393
6546
|
}
|
|
@@ -6407,8 +6560,8 @@ function resolveScope(config, options = {}) {
|
|
|
6407
6560
|
searchedFlows: [],
|
|
6408
6561
|
errors: [
|
|
6409
6562
|
{
|
|
6410
|
-
path:
|
|
6411
|
-
message: `Invalid path "${
|
|
6563
|
+
path: path23,
|
|
6564
|
+
message: `Invalid path "${path23}". Use "section.key" or just "key"`,
|
|
6412
6565
|
code: "INVALID_PATH"
|
|
6413
6566
|
}
|
|
6414
6567
|
]
|
|
@@ -6436,7 +6589,7 @@ function resolveScope(config, options = {}) {
|
|
|
6436
6589
|
target: { key },
|
|
6437
6590
|
errors: [
|
|
6438
6591
|
{
|
|
6439
|
-
path:
|
|
6592
|
+
path: path23,
|
|
6440
6593
|
message: `Ambiguous key "${key}" found in multiple sections: ${matched.join(", ")}. Use dot-notation (e.g., ${matched[0]}.${key})`,
|
|
6441
6594
|
code: "AMBIGUOUS_ENTRY"
|
|
6442
6595
|
}
|
|
@@ -6453,7 +6606,7 @@ function resolveScope(config, options = {}) {
|
|
|
6453
6606
|
target,
|
|
6454
6607
|
errors: [
|
|
6455
6608
|
{
|
|
6456
|
-
path:
|
|
6609
|
+
path: path23,
|
|
6457
6610
|
message: `Entry "${key}" not found in ${section ?? "any section"} of flow(s): ${flows.join(", ") || "none"}`,
|
|
6458
6611
|
code: "ENTRY_NOT_FOUND"
|
|
6459
6612
|
}
|
|
@@ -6469,9 +6622,9 @@ function resolveScope(config, options = {}) {
|
|
|
6469
6622
|
errors: []
|
|
6470
6623
|
};
|
|
6471
6624
|
}
|
|
6472
|
-
function flowOfPath(
|
|
6625
|
+
function flowOfPath(path23, flowNames) {
|
|
6473
6626
|
return flowNames.find(
|
|
6474
|
-
(name) =>
|
|
6627
|
+
(name) => path23 === `flows.${name}` || path23.startsWith(`flows.${name}.`)
|
|
6475
6628
|
);
|
|
6476
6629
|
}
|
|
6477
6630
|
function describeScope(resolved, checks) {
|
|
@@ -6488,93 +6641,554 @@ function describeScope(resolved, checks) {
|
|
|
6488
6641
|
return scope;
|
|
6489
6642
|
}
|
|
6490
6643
|
|
|
6491
|
-
// src/commands/validate/validators/
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
}
|
|
6498
|
-
function
|
|
6499
|
-
const errors = [];
|
|
6500
|
-
const warnings = [];
|
|
6501
|
-
const skipped = [];
|
|
6502
|
-
const checks = ["file:schema", "flow:schema"];
|
|
6503
|
-
const details = {};
|
|
6504
|
-
let json;
|
|
6644
|
+
// src/commands/validate/validators/resolve.ts
|
|
6645
|
+
import {
|
|
6646
|
+
FlowCycleError,
|
|
6647
|
+
FlowReferenceError,
|
|
6648
|
+
getFlowSettings as getFlowSettings2,
|
|
6649
|
+
getErrorMessage as getErrorMessage2
|
|
6650
|
+
} from "@walkeros/core";
|
|
6651
|
+
function resolveFlow2(file, name) {
|
|
6505
6652
|
try {
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
|
|
6513
|
-
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
const config = isObject6(input) ? input : {};
|
|
6518
|
-
const flowsValue = config.flows;
|
|
6519
|
-
const flows = isObject6(flowsValue) ? flowsValue : void 0;
|
|
6520
|
-
const allFlows = scope.allFlows;
|
|
6521
|
-
const inScope = (path20) => {
|
|
6522
|
-
const flow = flowOfPath(path20, allFlows);
|
|
6523
|
-
return flow === void 0 || scope.flows.includes(flow);
|
|
6524
|
-
};
|
|
6525
|
-
const coreResult = validateFlowConfig2(json);
|
|
6526
|
-
for (const issue of coreResult.errors) {
|
|
6527
|
-
const path20 = issue.path || "root";
|
|
6528
|
-
if (!inScope(path20)) continue;
|
|
6529
|
-
errors.push({ path: path20, message: issue.message, code: "SCHEMA_VALIDATION" });
|
|
6653
|
+
const flow = getFlowSettings2(file, name, { deferred: true });
|
|
6654
|
+
return { ok: true, flow };
|
|
6655
|
+
} catch (error) {
|
|
6656
|
+
return {
|
|
6657
|
+
ok: false,
|
|
6658
|
+
error: {
|
|
6659
|
+
path: `flows.${name}`,
|
|
6660
|
+
message: getErrorMessage2(error),
|
|
6661
|
+
code: resolutionCode(error)
|
|
6662
|
+
}
|
|
6663
|
+
};
|
|
6530
6664
|
}
|
|
6531
|
-
|
|
6532
|
-
|
|
6533
|
-
|
|
6534
|
-
|
|
6665
|
+
}
|
|
6666
|
+
function resolutionCode(error) {
|
|
6667
|
+
if (error instanceof FlowReferenceError) return error.code;
|
|
6668
|
+
if (error instanceof FlowCycleError) return error.code;
|
|
6669
|
+
return "UNRESOLVED_REFERENCE";
|
|
6670
|
+
}
|
|
6671
|
+
|
|
6672
|
+
// src/commands/validate/validators/settings.ts
|
|
6673
|
+
import * as fs19 from "fs";
|
|
6674
|
+
import * as path19 from "path";
|
|
6675
|
+
import Ajv from "ajv";
|
|
6676
|
+
import {
|
|
6677
|
+
ENV_MARKER_PREFIX as ENV_MARKER_PREFIX2,
|
|
6678
|
+
fetchPackage,
|
|
6679
|
+
getErrorMessage as getErrorMessage3,
|
|
6680
|
+
isObject as isObject6,
|
|
6681
|
+
REF_CODE_PREFIX,
|
|
6682
|
+
REF_STORE,
|
|
6683
|
+
SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX3
|
|
6684
|
+
} from "@walkeros/core";
|
|
6685
|
+
var CLIENT_HEADER = "walkeros-cli/4.7.0";
|
|
6686
|
+
function createSettingsContext(configDir) {
|
|
6687
|
+
return { configDir, cache: /* @__PURE__ */ new Map(), compiled: /* @__PURE__ */ new Map() };
|
|
6688
|
+
}
|
|
6689
|
+
function selectSettingsSchema(pkg, packageLabel, exportName) {
|
|
6690
|
+
if (exportName === void 0) return { ok: true, settings: pkg.settings };
|
|
6691
|
+
if (pkg.exportSchemas) {
|
|
6692
|
+
const entry = Object.prototype.hasOwnProperty.call(
|
|
6693
|
+
pkg.exportSchemas,
|
|
6694
|
+
exportName
|
|
6695
|
+
) ? pkg.exportSchemas[exportName] : void 0;
|
|
6696
|
+
if (!isObject6(entry))
|
|
6697
|
+
return {
|
|
6698
|
+
ok: false,
|
|
6699
|
+
reason: `${packageLabel} has no export "${exportName}"`
|
|
6700
|
+
};
|
|
6701
|
+
return { ok: true, settings: entry.settings };
|
|
6535
6702
|
}
|
|
6536
|
-
if (
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6703
|
+
if (pkg.exports && pkg.exports.length < 2)
|
|
6704
|
+
return { ok: true, settings: pkg.settings };
|
|
6705
|
+
return {
|
|
6706
|
+
ok: false,
|
|
6707
|
+
reason: `${packageLabel} predates per-export settings schemas; the step imports "${exportName}"`
|
|
6708
|
+
};
|
|
6709
|
+
}
|
|
6710
|
+
var SECTION_KIND = {
|
|
6711
|
+
sources: "source",
|
|
6712
|
+
transformers: "transformer",
|
|
6713
|
+
destinations: "destination",
|
|
6714
|
+
stores: "store"
|
|
6715
|
+
};
|
|
6716
|
+
function pointerSegments(pointer) {
|
|
6717
|
+
if (pointer === "") return [];
|
|
6718
|
+
return pointer.split("/").slice(1).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
6719
|
+
}
|
|
6720
|
+
function valueAt(root, segments) {
|
|
6721
|
+
let current = root;
|
|
6722
|
+
for (const segment of segments) {
|
|
6723
|
+
if (Array.isArray(current)) current = current[Number(segment)];
|
|
6724
|
+
else if (isObject6(current)) current = current[segment];
|
|
6725
|
+
else return void 0;
|
|
6542
6726
|
}
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6546
|
-
|
|
6547
|
-
|
|
6548
|
-
|
|
6549
|
-
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6727
|
+
return current;
|
|
6728
|
+
}
|
|
6729
|
+
var MARKER = ENV_MARKER_PREFIX2.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6730
|
+
var ENV_MARKER = new RegExp(
|
|
6731
|
+
`${MARKER}([a-zA-Z_][a-zA-Z0-9_]*)(?::((?:(?!${MARKER})[^\\s"'])*))?`,
|
|
6732
|
+
"g"
|
|
6733
|
+
);
|
|
6734
|
+
function prepareSettings(settings) {
|
|
6735
|
+
const deferred = [];
|
|
6736
|
+
const walk = (value, segments) => {
|
|
6737
|
+
if (Array.isArray(value))
|
|
6738
|
+
return value.map((item, index) => walk(item, [...segments, `${index}`]));
|
|
6739
|
+
if (isObject6(value))
|
|
6740
|
+
return Object.fromEntries(
|
|
6741
|
+
Object.entries(value).map(([key, item]) => [
|
|
6742
|
+
key,
|
|
6743
|
+
walk(item, [...segments, key])
|
|
6744
|
+
])
|
|
6745
|
+
);
|
|
6746
|
+
if (typeof value !== "string") return value;
|
|
6747
|
+
if (value.startsWith(SECRET_MARKER_PREFIX3)) {
|
|
6748
|
+
deferred.push({
|
|
6749
|
+
segments,
|
|
6750
|
+
reference: `$secret.${value.slice(SECRET_MARKER_PREFIX3.length)}`
|
|
6751
|
+
});
|
|
6752
|
+
return value;
|
|
6753
|
+
}
|
|
6754
|
+
if (value.includes(ENV_MARKER_PREFIX2)) {
|
|
6755
|
+
let runtimeOnly = false;
|
|
6756
|
+
const withDefaults = value.replace(
|
|
6757
|
+
ENV_MARKER,
|
|
6758
|
+
(_match, _name, fallback) => {
|
|
6759
|
+
if (fallback === void 0) runtimeOnly = true;
|
|
6760
|
+
return fallback ?? "";
|
|
6761
|
+
}
|
|
6762
|
+
);
|
|
6763
|
+
if (!runtimeOnly) return withDefaults;
|
|
6764
|
+
deferred.push({
|
|
6765
|
+
segments,
|
|
6766
|
+
reference: value.replace(
|
|
6767
|
+
ENV_MARKER,
|
|
6768
|
+
(_match, name, fallback) => fallback === void 0 ? `$env.${name}` : `$env.${name}:${fallback}`
|
|
6769
|
+
)
|
|
6770
|
+
});
|
|
6771
|
+
return value;
|
|
6772
|
+
}
|
|
6773
|
+
if (REF_STORE.test(value) || value.startsWith(REF_CODE_PREFIX)) {
|
|
6774
|
+
deferred.push({ segments, reference: value });
|
|
6775
|
+
}
|
|
6776
|
+
return value;
|
|
6777
|
+
};
|
|
6778
|
+
return { value: walk(settings, []), deferred };
|
|
6779
|
+
}
|
|
6780
|
+
function isUnder(segments, prefix) {
|
|
6781
|
+
return prefix.every((segment, index) => segments[index] === segment);
|
|
6782
|
+
}
|
|
6783
|
+
function bundlePin(rawFlow, name) {
|
|
6784
|
+
const config = isObject6(rawFlow) ? rawFlow.config : void 0;
|
|
6785
|
+
const bundle2 = isObject6(config) ? config.bundle : void 0;
|
|
6786
|
+
const packages = isObject6(bundle2) ? bundle2.packages : void 0;
|
|
6787
|
+
const pin = isObject6(packages) ? packages[name] : void 0;
|
|
6788
|
+
if (!isObject6(pin)) return {};
|
|
6789
|
+
return {
|
|
6790
|
+
...typeof pin.version === "string" ? { version: pin.version } : {},
|
|
6791
|
+
...typeof pin.path === "string" ? { path: pin.path } : {}
|
|
6792
|
+
};
|
|
6793
|
+
}
|
|
6794
|
+
function packageSource(spec, rawFlow) {
|
|
6795
|
+
if (spec.startsWith(".") || spec.startsWith("/"))
|
|
6796
|
+
return { name: spec, localPath: spec };
|
|
6797
|
+
const { name, version } = parsePackageSpec(spec);
|
|
6798
|
+
const pin = bundlePin(rawFlow, name);
|
|
6799
|
+
if (pin.path) return { name, localPath: pin.path };
|
|
6800
|
+
const pinned = pin.version ?? version;
|
|
6801
|
+
return pinned ? { name, version: pinned } : { name };
|
|
6802
|
+
}
|
|
6803
|
+
function readJson2(file) {
|
|
6804
|
+
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
6805
|
+
}
|
|
6806
|
+
function readLocalSchema(source, configDir) {
|
|
6807
|
+
const localPath = source.localPath ?? "";
|
|
6808
|
+
const root = path19.isAbsolute(localPath) ? localPath : path19.resolve(configDir, localPath);
|
|
6809
|
+
const file = [
|
|
6810
|
+
path19.join(root, "dist", "walkerOS.json"),
|
|
6811
|
+
path19.join(root, "walkerOS.json")
|
|
6812
|
+
].find((candidate) => fs19.existsSync(candidate));
|
|
6813
|
+
if (!file) throw new Error(`no walkerOS.json under ${root}`);
|
|
6814
|
+
const meta = readJson2(file);
|
|
6815
|
+
const pkgFile = path19.join(root, "package.json");
|
|
6816
|
+
const pkg = fs19.existsSync(pkgFile) ? readJson2(pkgFile) : void 0;
|
|
6817
|
+
const schemas6 = isObject6(meta) ? meta.schemas : void 0;
|
|
6818
|
+
const exportSchemas = isObject6(meta) ? meta.exportSchemas : void 0;
|
|
6819
|
+
const declared = isObject6(meta) && isObject6(meta.$meta) ? meta.$meta.exports : void 0;
|
|
6820
|
+
const version = isObject6(pkg) && typeof pkg.version === "string" ? pkg.version : void 0;
|
|
6821
|
+
return {
|
|
6822
|
+
...version ? { version } : {},
|
|
6823
|
+
settings: isObject6(schemas6) ? schemas6.settings : void 0,
|
|
6824
|
+
...isObject6(exportSchemas) ? { exportSchemas } : {},
|
|
6825
|
+
...isObject6(declared) ? { exports: Object.keys(declared) } : {}
|
|
6826
|
+
};
|
|
6827
|
+
}
|
|
6828
|
+
async function loadSchema(source, context2) {
|
|
6829
|
+
if (source.localPath !== void 0) {
|
|
6830
|
+
const configDir = context2.configDir;
|
|
6831
|
+
if (configDir === void 0)
|
|
6832
|
+
throw new Error(
|
|
6833
|
+
"it is a local path package and the input is not a file, so there is no directory to read it from"
|
|
6834
|
+
);
|
|
6835
|
+
return readLocalSchema(source, configDir);
|
|
6836
|
+
}
|
|
6837
|
+
const info = await fetchPackage(source.name, {
|
|
6838
|
+
...source.version ? { version: source.version } : {},
|
|
6839
|
+
client: CLIENT_HEADER
|
|
6840
|
+
});
|
|
6841
|
+
return {
|
|
6842
|
+
version: info.version,
|
|
6843
|
+
settings: info.schemas.settings,
|
|
6844
|
+
...info.exportSchemas ? { exportSchemas: info.exportSchemas } : {},
|
|
6845
|
+
...info.exports ? { exports: Object.keys(info.exports) } : {}
|
|
6846
|
+
};
|
|
6847
|
+
}
|
|
6848
|
+
function compileSettings(settings) {
|
|
6849
|
+
if (!isObject6(settings)) return void 0;
|
|
6850
|
+
const ajv = new Ajv({ allErrors: true, validateFormats: false });
|
|
6851
|
+
try {
|
|
6852
|
+
return { ok: true, validate: ajv.compile(settings) };
|
|
6853
|
+
} catch (error) {
|
|
6854
|
+
return { ok: false, message: getErrorMessage3(error) };
|
|
6855
|
+
}
|
|
6856
|
+
}
|
|
6857
|
+
function sourceKey(source) {
|
|
6858
|
+
return source.localPath ? `path:${source.localPath}` : `${source.name}@${source.version ?? "latest"}`;
|
|
6859
|
+
}
|
|
6860
|
+
function cachedSchema(source, context2) {
|
|
6861
|
+
const key = sourceKey(source);
|
|
6862
|
+
let pending = context2.cache.get(key);
|
|
6863
|
+
if (!pending) {
|
|
6864
|
+
pending = loadSchema(source, context2);
|
|
6865
|
+
context2.cache.set(key, pending);
|
|
6866
|
+
}
|
|
6867
|
+
return pending;
|
|
6868
|
+
}
|
|
6869
|
+
function cachedCompile(source, exportName, settings, context2) {
|
|
6870
|
+
const key = `${sourceKey(source)}#${exportName ?? ""}`;
|
|
6871
|
+
if (context2.compiled.has(key)) return context2.compiled.get(key);
|
|
6872
|
+
const compiled = compileSettings(settings);
|
|
6873
|
+
context2.compiled.set(key, compiled);
|
|
6874
|
+
return compiled;
|
|
6875
|
+
}
|
|
6876
|
+
async function checkStepSettings(target, resolvedFlow, rawFlow, check, context2) {
|
|
6877
|
+
const at = `flows.${target.flow}.${target.section}.${target.key}`;
|
|
6878
|
+
const outcome = { findings: [], skipped: [], deferred: [] };
|
|
6879
|
+
const spec = typeof target.entry.package === "string" ? target.entry.package : "";
|
|
6880
|
+
if (!spec) {
|
|
6881
|
+
outcome.skipped.push({
|
|
6882
|
+
path: at,
|
|
6883
|
+
check,
|
|
6884
|
+
reason: "No package field, so there is no settings schema to fetch",
|
|
6885
|
+
code: "NO_PACKAGE"
|
|
6886
|
+
});
|
|
6887
|
+
return outcome;
|
|
6888
|
+
}
|
|
6889
|
+
const source = packageSource(spec, rawFlow);
|
|
6890
|
+
let schema;
|
|
6891
|
+
try {
|
|
6892
|
+
schema = await cachedSchema(source, context2);
|
|
6893
|
+
} catch (error) {
|
|
6894
|
+
outcome.skipped.push({
|
|
6895
|
+
path: at,
|
|
6896
|
+
check,
|
|
6897
|
+
reason: `Schema for ${source.name}${source.version ? `@${source.version}` : ""} could not be loaded: ${getErrorMessage3(error)}`,
|
|
6898
|
+
code: "SCHEMA_UNAVAILABLE"
|
|
6899
|
+
});
|
|
6900
|
+
return outcome;
|
|
6901
|
+
}
|
|
6902
|
+
outcome.checked = {
|
|
6903
|
+
path: at,
|
|
6904
|
+
package: source.name,
|
|
6905
|
+
...schema.version ? { version: schema.version } : {}
|
|
6906
|
+
};
|
|
6907
|
+
const { exportName } = resolveExportName(
|
|
6908
|
+
resolvedFlow,
|
|
6909
|
+
SECTION_KIND[target.section],
|
|
6910
|
+
target.key
|
|
6911
|
+
);
|
|
6912
|
+
const version = schema.version ?? source.version;
|
|
6913
|
+
const selection = selectSettingsSchema(
|
|
6914
|
+
schema,
|
|
6915
|
+
version ? `${source.name}@${version}` : source.name,
|
|
6916
|
+
exportName
|
|
6917
|
+
);
|
|
6918
|
+
if (!selection.ok) {
|
|
6919
|
+
outcome.skipped.push({
|
|
6920
|
+
path: at,
|
|
6921
|
+
check,
|
|
6922
|
+
reason: selection.reason,
|
|
6923
|
+
code: "NO_SETTINGS_SCHEMA"
|
|
6924
|
+
});
|
|
6925
|
+
return outcome;
|
|
6926
|
+
}
|
|
6927
|
+
const compiled = cachedCompile(
|
|
6928
|
+
source,
|
|
6929
|
+
exportName,
|
|
6930
|
+
selection.settings,
|
|
6931
|
+
context2
|
|
6932
|
+
);
|
|
6933
|
+
if (!compiled) {
|
|
6934
|
+
outcome.skipped.push({
|
|
6935
|
+
path: at,
|
|
6936
|
+
check,
|
|
6937
|
+
reason: `Package ${source.name} has no settings schema`,
|
|
6938
|
+
code: "NO_SETTINGS_SCHEMA"
|
|
6939
|
+
});
|
|
6940
|
+
return outcome;
|
|
6941
|
+
}
|
|
6942
|
+
if (!compiled.ok) {
|
|
6943
|
+
outcome.skipped.push({
|
|
6944
|
+
path: at,
|
|
6945
|
+
check,
|
|
6946
|
+
reason: `The settings schema of ${source.name} cannot be compiled: ${compiled.message}`,
|
|
6947
|
+
code: "SCHEMA_UNAVAILABLE"
|
|
6948
|
+
});
|
|
6949
|
+
return outcome;
|
|
6950
|
+
}
|
|
6951
|
+
const validate2 = compiled.validate;
|
|
6952
|
+
const step = stepOf(resolvedFlow, target.section, target.key);
|
|
6953
|
+
const config = isObject6(step?.config) ? step.config : {};
|
|
6954
|
+
const prepared = prepareSettings(config.settings ?? {});
|
|
6955
|
+
const base = `${at}.config.settings`;
|
|
6956
|
+
for (const { segments, reference } of prepared.deferred) {
|
|
6957
|
+
outcome.deferred.push({
|
|
6958
|
+
path: [base, ...segments].join("."),
|
|
6959
|
+
reference
|
|
6960
|
+
});
|
|
6961
|
+
}
|
|
6962
|
+
if (validate2(prepared.value)) return outcome;
|
|
6963
|
+
for (const e of validate2.errors || []) {
|
|
6964
|
+
const segments = pointerSegments(e.instancePath);
|
|
6965
|
+
if (prepared.deferred.some((d) => isUnder(segments, d.segments))) continue;
|
|
6966
|
+
const finding = {
|
|
6967
|
+
path: [base, ...segments].join("."),
|
|
6968
|
+
message: describeAjvError(e),
|
|
6969
|
+
code: "ENTRY_SCHEMA",
|
|
6970
|
+
keyword: e.keyword
|
|
6971
|
+
};
|
|
6972
|
+
if (segments.length > 0) finding.value = valueAt(prepared.value, segments);
|
|
6973
|
+
outcome.findings.push(finding);
|
|
6974
|
+
}
|
|
6975
|
+
return outcome;
|
|
6976
|
+
}
|
|
6977
|
+
function describeAjvError(error) {
|
|
6978
|
+
const message = error.message || "Unknown error";
|
|
6979
|
+
const extra = error.params.additionalProperty;
|
|
6980
|
+
return error.keyword === "additionalProperties" && typeof extra === "string" ? `${message}: "${extra}"` : message;
|
|
6981
|
+
}
|
|
6982
|
+
function stepOf(flow, section, key) {
|
|
6983
|
+
switch (section) {
|
|
6984
|
+
case "sources":
|
|
6985
|
+
return flow.sources?.[key];
|
|
6986
|
+
case "destinations":
|
|
6987
|
+
return flow.destinations?.[key];
|
|
6988
|
+
case "transformers":
|
|
6989
|
+
return flow.transformers?.[key];
|
|
6990
|
+
case "stores":
|
|
6991
|
+
return flow.stores?.[key];
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
|
|
6995
|
+
// src/commands/validate/validators/flow.ts
|
|
6996
|
+
var { validateFlowConfig: validateFlowConfig2 } = schemas4;
|
|
6997
|
+
var DEPRECATED_PACKAGES = {
|
|
6998
|
+
"@walkeros/store-memory": "has been removed. Use the built-in cache by omitting cache.store, or remove the store declaration if it was only used as a cache target."
|
|
6999
|
+
};
|
|
7000
|
+
var OPEN_STEP_KINDS = [
|
|
7001
|
+
["destinations", "Destination"],
|
|
7002
|
+
["stores", "Store"]
|
|
7003
|
+
];
|
|
7004
|
+
async function validateFlowWithPackages(input, options = {}) {
|
|
7005
|
+
const run = runFlowChecks(input, options);
|
|
7006
|
+
const { result, scope } = run;
|
|
7007
|
+
if (options.offline) {
|
|
7008
|
+
const described = describeScope(scope, run.checks);
|
|
7009
|
+
described.offline = true;
|
|
7010
|
+
result.details.scope = described;
|
|
7011
|
+
return result;
|
|
7012
|
+
}
|
|
7013
|
+
run.checks.push("flow:package-settings");
|
|
7014
|
+
const context2 = createSettingsContext(options.configDir);
|
|
7015
|
+
const deferred = [];
|
|
7016
|
+
const packages = [];
|
|
7017
|
+
const pending = [];
|
|
7018
|
+
for (const name of scope.flows) {
|
|
7019
|
+
const flow = run.resolved.get(name);
|
|
7020
|
+
const rawFlow = run.typed?.flows[name];
|
|
7021
|
+
const reason = run.gate(name);
|
|
7022
|
+
if (!flow || !rawFlow || reason) {
|
|
7023
|
+
run.skipped.push({
|
|
7024
|
+
path: `flows.${name}`,
|
|
7025
|
+
check: "flow:package-settings",
|
|
7026
|
+
reason: reason ?? `flows.${name} did not resolve`,
|
|
7027
|
+
code: "GATED_BY_ERRORS"
|
|
7028
|
+
});
|
|
7029
|
+
continue;
|
|
7030
|
+
}
|
|
7031
|
+
for (const section of ENTRY_SECTIONS) {
|
|
7032
|
+
const steps = isObject7(rawFlow[section]) ? rawFlow[section] : {};
|
|
7033
|
+
for (const [key, entry] of Object.entries(steps)) {
|
|
7034
|
+
if (!isObject7(entry) || entry.package === void 0) continue;
|
|
7035
|
+
const target = { flow: name, section, key, entry };
|
|
7036
|
+
pending.push(
|
|
7037
|
+
checkStepSettings(
|
|
7038
|
+
target,
|
|
7039
|
+
flow,
|
|
7040
|
+
rawFlow,
|
|
7041
|
+
"flow:package-settings",
|
|
7042
|
+
context2
|
|
7043
|
+
)
|
|
7044
|
+
);
|
|
7045
|
+
}
|
|
7046
|
+
}
|
|
7047
|
+
}
|
|
7048
|
+
for (const outcome of await Promise.all(pending)) {
|
|
7049
|
+
result.warnings.push(...outcome.findings);
|
|
7050
|
+
run.skipped.push(...outcome.skipped);
|
|
7051
|
+
deferred.push(...outcome.deferred);
|
|
7052
|
+
if (outcome.checked) packages.push(outcome.checked);
|
|
7053
|
+
}
|
|
7054
|
+
result.details.scope = describeScope(scope, run.checks);
|
|
7055
|
+
result.details.deferred = [...result.details.deferred ?? [], ...deferred];
|
|
7056
|
+
if (packages.length > 0) result.details.packages = packages;
|
|
7057
|
+
return result;
|
|
7058
|
+
}
|
|
7059
|
+
function runFlowChecks(input, options) {
|
|
7060
|
+
const errors = [];
|
|
7061
|
+
const warnings = [];
|
|
7062
|
+
const skipped = [];
|
|
7063
|
+
const checks = ["file:schema", "flow:schema"];
|
|
7064
|
+
const details = {};
|
|
7065
|
+
const resolved = /* @__PURE__ */ new Map();
|
|
7066
|
+
const result = {
|
|
7067
|
+
valid: false,
|
|
7068
|
+
type: "flow",
|
|
7069
|
+
errors,
|
|
7070
|
+
warnings,
|
|
7071
|
+
details
|
|
7072
|
+
};
|
|
7073
|
+
let json;
|
|
7074
|
+
const scope = resolveScope(input, { flow: options.flow });
|
|
7075
|
+
try {
|
|
7076
|
+
json = JSON.stringify(input, null, 2);
|
|
7077
|
+
} catch {
|
|
7078
|
+
errors.push({
|
|
7079
|
+
path: "root",
|
|
7080
|
+
message: "Input cannot be serialized to JSON",
|
|
7081
|
+
code: "SERIALIZATION_ERROR"
|
|
7082
|
+
});
|
|
7083
|
+
return {
|
|
7084
|
+
result,
|
|
7085
|
+
scope,
|
|
7086
|
+
resolved,
|
|
7087
|
+
checks,
|
|
7088
|
+
skipped,
|
|
7089
|
+
gate: () => "the input cannot be serialized"
|
|
7090
|
+
};
|
|
7091
|
+
}
|
|
7092
|
+
errors.push(...scope.errors);
|
|
7093
|
+
const config = isObject7(input) ? input : {};
|
|
7094
|
+
const flowsValue = config.flows;
|
|
7095
|
+
const flows = isObject7(flowsValue) ? flowsValue : void 0;
|
|
7096
|
+
const allFlows = scope.allFlows;
|
|
7097
|
+
const inScope = (path23) => {
|
|
7098
|
+
const flow = flowOfPath(path23, allFlows);
|
|
7099
|
+
return flow === void 0 || scope.flows.includes(flow);
|
|
7100
|
+
};
|
|
7101
|
+
let contractErrors = 0;
|
|
7102
|
+
if ("contract" in config) {
|
|
7103
|
+
checks.push("file:contract");
|
|
7104
|
+
const contract = validateContract(config.contract);
|
|
7105
|
+
contractErrors = contract.errors.length;
|
|
7106
|
+
for (const error of contract.errors)
|
|
7107
|
+
errors.push({ ...error, path: `contract.${error.path}` });
|
|
7108
|
+
for (const warning of contract.warnings)
|
|
7109
|
+
warnings.push({ ...warning, path: `contract.${warning.path}` });
|
|
7110
|
+
}
|
|
7111
|
+
const coreResult = validateFlowConfig2(json);
|
|
7112
|
+
for (const issue of coreResult.errors) {
|
|
7113
|
+
const path23 = issue.path || "root";
|
|
7114
|
+
if (!inScope(path23)) continue;
|
|
7115
|
+
if (path23 === "contract" && contractErrors > 0) continue;
|
|
7116
|
+
errors.push({ path: path23, message: issue.message, code: "SCHEMA_VALIDATION" });
|
|
7117
|
+
}
|
|
7118
|
+
for (const issue of coreResult.warnings) {
|
|
7119
|
+
const path23 = issue.path || "root";
|
|
7120
|
+
if (!inScope(path23)) continue;
|
|
7121
|
+
warnings.push({ path: path23, message: issue.message, code: "CONFIG_WARNING" });
|
|
7122
|
+
}
|
|
7123
|
+
if (flows && allFlows.length === 0) {
|
|
7124
|
+
errors.push({
|
|
7125
|
+
path: "flows",
|
|
7126
|
+
message: "At least one flow is required",
|
|
7127
|
+
code: "EMPTY_FLOWS"
|
|
7128
|
+
});
|
|
7129
|
+
}
|
|
7130
|
+
checks.push("flow:steps");
|
|
7131
|
+
for (const flowName of scope.flows) {
|
|
7132
|
+
const flowValue = flows?.[flowName];
|
|
7133
|
+
if (!isObject7(flowValue)) continue;
|
|
7134
|
+
const transformersValue = flowValue.transformers;
|
|
7135
|
+
if (isObject7(transformersValue)) {
|
|
7136
|
+
for (const [name, transformerValue] of Object.entries(
|
|
7137
|
+
transformersValue
|
|
7138
|
+
)) {
|
|
7139
|
+
if (!isObject7(transformerValue)) continue;
|
|
7140
|
+
const result2 = validateStepEntry(transformerValue, "Transformer");
|
|
7141
|
+
if (!result2.ok) {
|
|
7142
|
+
errors.push({
|
|
7143
|
+
path: `flows.${flowName}.transformers.${name}`,
|
|
7144
|
+
message: result2.reason || "Invalid transformer entry.",
|
|
7145
|
+
code: result2.code
|
|
7146
|
+
});
|
|
7147
|
+
}
|
|
7148
|
+
}
|
|
7149
|
+
}
|
|
7150
|
+
for (const [section, kind] of OPEN_STEP_KINDS) {
|
|
7151
|
+
const steps = flowValue[section];
|
|
7152
|
+
if (!isObject7(steps)) continue;
|
|
7153
|
+
for (const [name, step] of Object.entries(steps)) {
|
|
7154
|
+
if (!isObject7(step)) continue;
|
|
7155
|
+
const at = `flows.${flowName}.${section}.${name}`;
|
|
7156
|
+
for (const key of unknownStepKeys(step, kind)) {
|
|
7157
|
+
warnings.push({
|
|
7158
|
+
path: `${at}.${key}`,
|
|
7159
|
+
message: `Unknown key "${key}" on ${kind} is ignored by the runtime`,
|
|
7160
|
+
suggestion: "Remove the key, or move it to where it belongs.",
|
|
7161
|
+
code: "UNKNOWN_KEY"
|
|
7162
|
+
});
|
|
7163
|
+
}
|
|
7164
|
+
const pkg = step.package;
|
|
7165
|
+
if (typeof pkg === "string" && pkg in DEPRECATED_PACKAGES) {
|
|
7166
|
+
warnings.push({
|
|
7167
|
+
path: at,
|
|
7168
|
+
message: `${kind} "${name}" uses ${pkg}, which ${DEPRECATED_PACKAGES[pkg]}`,
|
|
7169
|
+
code: "DEPRECATED_PACKAGE"
|
|
7170
|
+
});
|
|
7171
|
+
}
|
|
7172
|
+
}
|
|
6559
7173
|
}
|
|
6560
7174
|
}
|
|
6561
|
-
if (flows) {
|
|
6562
|
-
details.flowNames = allFlows;
|
|
6563
|
-
details.flowCount = allFlows.length;
|
|
6564
|
-
}
|
|
7175
|
+
if (flows) {
|
|
7176
|
+
details.flowNames = allFlows;
|
|
7177
|
+
details.flowCount = allFlows.length;
|
|
7178
|
+
}
|
|
6565
7179
|
checks.push("flow:package-versions");
|
|
6566
7180
|
let totalPackageCount = 0;
|
|
6567
7181
|
for (const flowName of scope.flows) {
|
|
6568
7182
|
const flowValue = flows?.[flowName];
|
|
6569
|
-
if (!
|
|
7183
|
+
if (!isObject7(flowValue)) continue;
|
|
6570
7184
|
const flowConfig = flowValue.config;
|
|
6571
|
-
if (!
|
|
7185
|
+
if (!isObject7(flowConfig)) continue;
|
|
6572
7186
|
const bundle2 = flowConfig.bundle;
|
|
6573
|
-
if (!
|
|
7187
|
+
if (!isObject7(bundle2)) continue;
|
|
6574
7188
|
const packages = bundle2.packages;
|
|
6575
|
-
if (!
|
|
7189
|
+
if (!isObject7(packages)) continue;
|
|
6576
7190
|
for (const [pkgName, pkgConfigValue] of Object.entries(packages)) {
|
|
6577
|
-
if (!
|
|
7191
|
+
if (!isObject7(pkgConfigValue)) continue;
|
|
6578
7192
|
if (!pkgConfigValue.version && !pkgConfigValue.path) {
|
|
6579
7193
|
warnings.push({
|
|
6580
7194
|
path: `flows.${flowName}.config.bundle.packages.${pkgName}`,
|
|
@@ -6594,10 +7208,8 @@ function validateFlow(input, options = {}) {
|
|
|
6594
7208
|
}
|
|
6595
7209
|
const typed = isFlowJson2(input) ? input : void 0;
|
|
6596
7210
|
const gate = (name) => {
|
|
6597
|
-
if (!typed || errors.some(
|
|
6598
|
-
|
|
6599
|
-
))
|
|
6600
|
-
return "file-level schema errors: the file shape is not valid";
|
|
7211
|
+
if (!typed || errors.some((e) => flowOfPath(e.path, allFlows) === void 0))
|
|
7212
|
+
return "file-level errors: the file shape or its contract is not valid";
|
|
6601
7213
|
if (errors.some((e) => flowOfPath(e.path, allFlows) === name))
|
|
6602
7214
|
return `earlier errors in flows.${name}`;
|
|
6603
7215
|
return void 0;
|
|
@@ -6621,9 +7233,25 @@ function validateFlow(input, options = {}) {
|
|
|
6621
7233
|
run(name, flow, typed);
|
|
6622
7234
|
}
|
|
6623
7235
|
};
|
|
7236
|
+
perFlow(["flow:structure"], (name, flow, file) => {
|
|
7237
|
+
const structure = validateFlowStructure({
|
|
7238
|
+
...file,
|
|
7239
|
+
flows: { [name]: flow }
|
|
7240
|
+
});
|
|
7241
|
+
errors.push(...structure.errors);
|
|
7242
|
+
});
|
|
6624
7243
|
perFlow(["flow:routes"], (name, flow) => {
|
|
6625
7244
|
lintFlowRoutes(name, flow, errors, warnings);
|
|
6626
7245
|
});
|
|
7246
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
7247
|
+
const resolutionOf = (name, file) => {
|
|
7248
|
+
let resolution = resolutions.get(name);
|
|
7249
|
+
if (!resolution) {
|
|
7250
|
+
resolution = resolveFlow2(file, name);
|
|
7251
|
+
resolutions.set(name, resolution);
|
|
7252
|
+
}
|
|
7253
|
+
return resolution;
|
|
7254
|
+
};
|
|
6627
7255
|
let totalConnections;
|
|
6628
7256
|
perFlow(
|
|
6629
7257
|
["flow:examples", "flow:contract-examples", "flow:mapping-keys"],
|
|
@@ -6633,23 +7261,27 @@ function validateFlow(input, options = {}) {
|
|
|
6633
7261
|
checkCompatibility(name, conn, errors, warnings);
|
|
6634
7262
|
}
|
|
6635
7263
|
totalConnections = (totalConnections ?? 0) + connections.length;
|
|
7264
|
+
const resolution = resolutionOf(name, file);
|
|
6636
7265
|
for (const [stepName, transformer] of Object.entries(
|
|
6637
7266
|
flow.transformers || {}
|
|
6638
7267
|
)) {
|
|
6639
7268
|
if (!isValidateStep(transformer)) continue;
|
|
7269
|
+
const resolvedConfig = resolution.ok ? resolution.flow.transformers?.[stepName]?.config : void 0;
|
|
6640
7270
|
checkValidateStepExamples(
|
|
6641
7271
|
`flows.${name}.transformers.${stepName}`,
|
|
6642
7272
|
transformer,
|
|
6643
7273
|
file.contract,
|
|
6644
7274
|
errors,
|
|
6645
7275
|
warnings,
|
|
6646
|
-
options.strict === true
|
|
7276
|
+
options.strict === true,
|
|
7277
|
+
skipped,
|
|
7278
|
+
isObject7(resolvedConfig) && isObject7(resolvedConfig.settings) ? resolvedConfig.settings : void 0
|
|
6647
7279
|
);
|
|
6648
7280
|
}
|
|
6649
7281
|
for (const [destName, dest] of Object.entries(flow.destinations || {})) {
|
|
6650
|
-
if (!
|
|
7282
|
+
if (!isObject7(dest.config)) continue;
|
|
6651
7283
|
const mapping = dest.config.mapping;
|
|
6652
|
-
if (!
|
|
7284
|
+
if (!isObject7(mapping)) continue;
|
|
6653
7285
|
for (const key of Object.keys(mapping)) {
|
|
6654
7286
|
if (key.includes(".") && !key.includes(" ")) {
|
|
6655
7287
|
const parts = key.split(".");
|
|
@@ -6667,41 +7299,59 @@ function validateFlow(input, options = {}) {
|
|
|
6667
7299
|
if (totalConnections !== void 0) {
|
|
6668
7300
|
details.connectionsChecked = totalConnections;
|
|
6669
7301
|
}
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
onWarning: (message) => {
|
|
6677
|
-
warnings.push({
|
|
6678
|
-
path: `flows.${name}`,
|
|
6679
|
-
message,
|
|
6680
|
-
code: "FLOW_REF_WARNING"
|
|
6681
|
-
});
|
|
6682
|
-
}
|
|
6683
|
-
});
|
|
6684
|
-
} catch (err) {
|
|
6685
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
6686
|
-
if (/Cyclic \$flow reference/.test(message)) {
|
|
6687
|
-
errors.push({
|
|
6688
|
-
path: `flows.${name}`,
|
|
6689
|
-
message,
|
|
6690
|
-
code: "FLOW_CYCLE"
|
|
6691
|
-
});
|
|
6692
|
-
}
|
|
7302
|
+
const deferred = [];
|
|
7303
|
+
perFlow(["flow:resolve"], (name, flow, file) => {
|
|
7304
|
+
const resolution = resolutionOf(name, file);
|
|
7305
|
+
if (!resolution.ok) {
|
|
7306
|
+
errors.push(resolution.error);
|
|
7307
|
+
return;
|
|
6693
7308
|
}
|
|
7309
|
+
resolved.set(name, resolution.flow);
|
|
7310
|
+
checkResolvedWindowCollector(name, flow, resolution.flow, errors, deferred);
|
|
6694
7311
|
});
|
|
6695
7312
|
details.scope = describeScope(scope, checks);
|
|
6696
7313
|
details.skipped = skipped;
|
|
7314
|
+
details.deferred = deferred;
|
|
7315
|
+
result.valid = errors.length === 0;
|
|
6697
7316
|
return {
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
7317
|
+
result,
|
|
7318
|
+
scope,
|
|
7319
|
+
typed,
|
|
7320
|
+
resolved,
|
|
7321
|
+
checks,
|
|
7322
|
+
skipped,
|
|
7323
|
+
gate
|
|
6703
7324
|
};
|
|
6704
7325
|
}
|
|
7326
|
+
function checkResolvedWindowCollector(name, raw, flow, errors, deferred) {
|
|
7327
|
+
const written = raw.config?.settings?.windowCollector;
|
|
7328
|
+
const value = flow.config?.settings?.windowCollector;
|
|
7329
|
+
if (flow.config?.platform !== "web" || typeof written !== "string" || !/\$(?:var|env)\./.test(written))
|
|
7330
|
+
return;
|
|
7331
|
+
const path23 = `flows.${name}.config.settings.windowCollector`;
|
|
7332
|
+
if (typeof value === "string" && value.includes(ENV_MARKER_PREFIX3)) {
|
|
7333
|
+
deferred.push({ path: path23, reference: written });
|
|
7334
|
+
return;
|
|
7335
|
+
}
|
|
7336
|
+
const check = checkWindowCollector2(value);
|
|
7337
|
+
if (check.ok) return;
|
|
7338
|
+
errors.push({
|
|
7339
|
+
path: path23,
|
|
7340
|
+
message: `${JSON.stringify(written)} resolved to ${JSON.stringify(value)}, which ${check.reason}`,
|
|
7341
|
+
code: "SCHEMA_VALIDATION"
|
|
7342
|
+
});
|
|
7343
|
+
}
|
|
7344
|
+
function unknownStepKeys(step, kind) {
|
|
7345
|
+
const unknown = [];
|
|
7346
|
+
const rest = { ...step };
|
|
7347
|
+
for (; ; ) {
|
|
7348
|
+
const verdict = validateStepEntry(rest, kind);
|
|
7349
|
+
if (verdict.code !== "UNKNOWN_KEY" || verdict.key === void 0) break;
|
|
7350
|
+
unknown.push(verdict.key);
|
|
7351
|
+
Reflect.deleteProperty(rest, verdict.key);
|
|
7352
|
+
}
|
|
7353
|
+
return unknown;
|
|
7354
|
+
}
|
|
6705
7355
|
function routeTargets(spec) {
|
|
6706
7356
|
if (spec === void 0) return [];
|
|
6707
7357
|
const targets = /* @__PURE__ */ new Set();
|
|
@@ -6772,10 +7422,10 @@ function buildConnectionGraph(config) {
|
|
|
6772
7422
|
function checkCompatibility(flowName, conn, errors, warnings) {
|
|
6773
7423
|
const fromOuts = Object.entries(conn.from.examples).filter(([, ex]) => hasComparableOut(ex.out)).map(([name, ex]) => ({ name, value: ex.out }));
|
|
6774
7424
|
const toIns = Object.entries(conn.to.examples).filter(([, ex]) => ex.in !== void 0 && !ex.command).map(([name, ex]) => ({ name, value: ex.in }));
|
|
6775
|
-
const
|
|
7425
|
+
const path23 = `flows.${flowName}.${conn.from.type}s.${conn.from.name} \u2192 ${conn.to.type}s.${conn.to.name}`;
|
|
6776
7426
|
if (fromOuts.length === 0 || toIns.length === 0) {
|
|
6777
7427
|
warnings.push({
|
|
6778
|
-
path:
|
|
7428
|
+
path: path23,
|
|
6779
7429
|
message: "Cannot check compatibility: missing out or in examples",
|
|
6780
7430
|
suggestion: "Add out examples to the source step or in examples to the target step",
|
|
6781
7431
|
code: "EXAMPLES_INCOMPLETE"
|
|
@@ -6789,7 +7439,7 @@ function checkCompatibility(flowName, conn, errors, warnings) {
|
|
|
6789
7439
|
);
|
|
6790
7440
|
if (!hasMatch) {
|
|
6791
7441
|
errors.push({
|
|
6792
|
-
path:
|
|
7442
|
+
path: path23,
|
|
6793
7443
|
message: "No compatible out/in pair found between connected steps",
|
|
6794
7444
|
code: "INCOMPATIBLE_EXAMPLES"
|
|
6795
7445
|
});
|
|
@@ -6799,21 +7449,21 @@ function isStepOut(value) {
|
|
|
6799
7449
|
return Array.isArray(value) && value.every((entry) => Array.isArray(entry) && typeof entry[0] === "string");
|
|
6800
7450
|
}
|
|
6801
7451
|
function returnedEvents(value) {
|
|
6802
|
-
if (
|
|
7452
|
+
if (isObject7(value)) return [isObject7(value.event) ? value.event : value];
|
|
6803
7453
|
if (Array.isArray(value)) return value.flatMap(returnedEvents);
|
|
6804
7454
|
return [];
|
|
6805
7455
|
}
|
|
6806
7456
|
function outEvents(out) {
|
|
6807
7457
|
if (isStepOut(out)) {
|
|
6808
7458
|
return out.flatMap(([head, first]) => {
|
|
6809
|
-
if (head === "elb") return
|
|
7459
|
+
if (head === "elb") return isObject7(first) ? [first] : [];
|
|
6810
7460
|
if (head === "return") return returnedEvents(first);
|
|
6811
7461
|
return [];
|
|
6812
7462
|
});
|
|
6813
7463
|
}
|
|
6814
7464
|
if (Array.isArray(out) || typeof out === "string")
|
|
6815
7465
|
return out.length > 0 ? [out] : [];
|
|
6816
|
-
return
|
|
7466
|
+
return isObject7(out) && Object.keys(out).length > 0 ? [out] : [];
|
|
6817
7467
|
}
|
|
6818
7468
|
function hasComparableOut(out) {
|
|
6819
7469
|
return outEvents(out).length > 0;
|
|
@@ -6850,17 +7500,17 @@ function lintFlowRoutes(flowName, flow, errors, warnings) {
|
|
|
6850
7500
|
check(dest.next, `${at}.destinations.${name}.next`);
|
|
6851
7501
|
}
|
|
6852
7502
|
}
|
|
6853
|
-
function routeAt(spec,
|
|
7503
|
+
function routeAt(spec, path23) {
|
|
6854
7504
|
let current = spec;
|
|
6855
|
-
for (const key of
|
|
7505
|
+
for (const key of path23) {
|
|
6856
7506
|
if (typeof key === "number")
|
|
6857
7507
|
current = Array.isArray(current) ? current[key] : void 0;
|
|
6858
|
-
else current =
|
|
7508
|
+
else current = isObject7(current) ? current[key] : void 0;
|
|
6859
7509
|
}
|
|
6860
7510
|
return current;
|
|
6861
7511
|
}
|
|
6862
7512
|
function lintRoute(spec, position, known, errors, warnings) {
|
|
6863
|
-
const where = (
|
|
7513
|
+
const where = (path23) => path23.length > 0 ? `${position}.${path23.join(".")}` : position;
|
|
6864
7514
|
const reported = /* @__PURE__ */ new Set();
|
|
6865
7515
|
const once = (key) => {
|
|
6866
7516
|
if (reported.has(key)) return false;
|
|
@@ -6880,7 +7530,7 @@ function lintRoute(spec, position, known, errors, warnings) {
|
|
|
6880
7530
|
if (node.stop && !node.match && node.kind !== "many") {
|
|
6881
7531
|
const self = routeAt(spec, node.path);
|
|
6882
7532
|
const list = routeAt(spec, node.path.slice(0, -1));
|
|
6883
|
-
if (
|
|
7533
|
+
if (isObject7(self) && self.stop === true && typeof last === "number" && Array.isArray(list) && last < list.length - 1 && once(`stop:${where(node.path)}`)) {
|
|
6884
7534
|
const at = where(node.path);
|
|
6885
7535
|
warnings.push({
|
|
6886
7536
|
path: at,
|
|
@@ -6937,38 +7587,73 @@ function resolveStepContracts(entries, contract) {
|
|
|
6937
7587
|
if (contract) {
|
|
6938
7588
|
try {
|
|
6939
7589
|
resolved = resolveContracts(contract);
|
|
6940
|
-
} catch {
|
|
6941
|
-
return
|
|
7590
|
+
} catch (error) {
|
|
7591
|
+
return {
|
|
7592
|
+
ok: false,
|
|
7593
|
+
message: `the root contract does not resolve (${error instanceof Error ? error.message : String(error)})`
|
|
7594
|
+
};
|
|
6942
7595
|
}
|
|
6943
7596
|
}
|
|
6944
7597
|
const sources = [];
|
|
6945
|
-
for (const entry of entries) {
|
|
6946
|
-
if (
|
|
7598
|
+
for (const [index, entry] of entries.entries()) {
|
|
7599
|
+
if (isObject7(entry)) {
|
|
6947
7600
|
sources.push(entry);
|
|
6948
7601
|
continue;
|
|
6949
7602
|
}
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
7603
|
+
const match = typeof entry === "string" ? entry.match(REF_CONTRACT) : null;
|
|
7604
|
+
if (!match)
|
|
7605
|
+
return {
|
|
7606
|
+
ok: false,
|
|
7607
|
+
index,
|
|
7608
|
+
message: "an entry must be a $contract reference or a JSON Schema"
|
|
7609
|
+
};
|
|
7610
|
+
if (!(match[1] in resolved))
|
|
7611
|
+
return {
|
|
7612
|
+
ok: false,
|
|
7613
|
+
index,
|
|
7614
|
+
message: `contract "${match[1]}" is not defined in the root contract (defined: ${Object.keys(resolved).join(", ") || "none"})`
|
|
7615
|
+
};
|
|
6953
7616
|
const rule = match[2] ? getByPath(resolved[match[1]], match[2]) : resolved[match[1]];
|
|
6954
|
-
if (!
|
|
7617
|
+
if (!isObject7(rule))
|
|
7618
|
+
return {
|
|
7619
|
+
ok: false,
|
|
7620
|
+
index,
|
|
7621
|
+
message: `${match[0]} does not point at a contract rule object`
|
|
7622
|
+
};
|
|
6955
7623
|
sources.push(rule);
|
|
6956
7624
|
}
|
|
6957
|
-
return sources;
|
|
6958
|
-
}
|
|
6959
|
-
function checkValidateStepExamples(stepPath, step, contract, errors, warnings, strict) {
|
|
6960
|
-
|
|
6961
|
-
const
|
|
6962
|
-
if (settings.contract !== void 0 && !Array.isArray(settings.contract))
|
|
7625
|
+
return { ok: true, sources };
|
|
7626
|
+
}
|
|
7627
|
+
function checkValidateStepExamples(stepPath, step, contract, errors, warnings, strict, skipped, resolvedSettings) {
|
|
7628
|
+
const settings = resolvedSettings ?? (isObject7(step.config) && isObject7(step.config.settings) ? step.config.settings : {});
|
|
7629
|
+
const contractPath = `${stepPath}.config.settings.contract`;
|
|
7630
|
+
if (settings.contract !== void 0 && !Array.isArray(settings.contract)) {
|
|
7631
|
+
if (step.examples)
|
|
7632
|
+
skipped?.push({
|
|
7633
|
+
path: stepPath,
|
|
7634
|
+
check: "flow:contract-examples",
|
|
7635
|
+
reason: "config.settings.contract is not a list, so the step cannot be judged statically",
|
|
7636
|
+
code: "CONTRACT_NOT_STATIC"
|
|
7637
|
+
});
|
|
7638
|
+
return;
|
|
7639
|
+
}
|
|
7640
|
+
const resolution = Array.isArray(settings.contract) ? resolveStepContracts(settings.contract, contract) : { ok: true, sources: [] };
|
|
7641
|
+
if (!resolution.ok) {
|
|
7642
|
+
errors.push({
|
|
7643
|
+
path: resolution.index === void 0 ? contractPath : `${contractPath}.${resolution.index}`,
|
|
7644
|
+
message: `The validate step's contract does not resolve: ${resolution.message}`,
|
|
7645
|
+
code: "UNRESOLVED_CONTRACT"
|
|
7646
|
+
});
|
|
6963
7647
|
return;
|
|
6964
|
-
|
|
6965
|
-
if (!
|
|
7648
|
+
}
|
|
7649
|
+
if (!step.examples) return;
|
|
7650
|
+
const contracts = resolution.sources;
|
|
6966
7651
|
const mode = settings.mode === "strict" ? "strict" : "pass";
|
|
6967
7652
|
const format = settings.format === true;
|
|
6968
|
-
const output =
|
|
7653
|
+
const output = isObject7(settings.output) ? settings.output : {};
|
|
6969
7654
|
const isValidPath = typeof output.isValid === "string" ? output.isValid : "source.valid";
|
|
6970
7655
|
for (const [exName, example] of Object.entries(step.examples)) {
|
|
6971
|
-
if (example.command || !
|
|
7656
|
+
if (example.command || !isObject7(example.in)) continue;
|
|
6972
7657
|
if (example.out === void 0) continue;
|
|
6973
7658
|
const event = example.in;
|
|
6974
7659
|
const verdict = validateEventAgainstContract(event, void 0, {
|
|
@@ -6990,13 +7675,13 @@ function checkValidateStepExamples(stepPath, step, contract, errors, warnings, s
|
|
|
6990
7675
|
if (agrees) continue;
|
|
6991
7676
|
const reason = verdict.isValid ? "the event satisfies the contract" : `the event breaks the contract (${verdict.errors.map((e) => `${e.path || "/"}: ${e.message}`).join("; ")})`;
|
|
6992
7677
|
const expected = mode === "strict" && !verdict.isValid ? 'drops it (["return", false])' : `passes it on${isValidPath ? ` with ${isValidPath} ${verdict.isValid}` : ""}`;
|
|
6993
|
-
const
|
|
7678
|
+
const path23 = `${stepPath}.examples.${exName}.out`;
|
|
6994
7679
|
const message = `Example out disagrees with the validate step: ${reason}, so with mode "${mode}" the step ${expected}.`;
|
|
6995
7680
|
if (strict) {
|
|
6996
|
-
errors.push({ path:
|
|
7681
|
+
errors.push({ path: path23, message, code: "CONTRACT_VIOLATION" });
|
|
6997
7682
|
} else {
|
|
6998
7683
|
warnings.push({
|
|
6999
|
-
path:
|
|
7684
|
+
path: path23,
|
|
7000
7685
|
message,
|
|
7001
7686
|
suggestion: "Make the example out show what the validate step does with its settings.",
|
|
7002
7687
|
code: "CONTRACT_VIOLATION"
|
|
@@ -7006,14 +7691,14 @@ function checkValidateStepExamples(stepPath, step, contract, errors, warnings, s
|
|
|
7006
7691
|
}
|
|
7007
7692
|
|
|
7008
7693
|
// src/commands/validate/validators/mapping.ts
|
|
7009
|
-
import { isObject as
|
|
7694
|
+
import { isObject as isObject8 } from "@walkeros/core";
|
|
7010
7695
|
import { schemas as schemas5 } from "@walkeros/core/dev";
|
|
7011
7696
|
var { RuleSchema } = schemas5.MappingSchemas;
|
|
7012
7697
|
function isRule(value) {
|
|
7013
|
-
return
|
|
7698
|
+
return isObject8(value) && RuleSchema.safeParse(value).success;
|
|
7014
7699
|
}
|
|
7015
7700
|
function isNestedActions(key, value) {
|
|
7016
|
-
if (key.includes(" ") || !
|
|
7701
|
+
if (key.includes(" ") || !isObject8(value)) return false;
|
|
7017
7702
|
const rules = Object.values(value);
|
|
7018
7703
|
return rules.length > 0 && rules.every(
|
|
7019
7704
|
(rule) => Array.isArray(rule) ? rule.length > 0 && rule.every(isRule) : isRule(rule)
|
|
@@ -7023,7 +7708,7 @@ function validateMapping(input) {
|
|
|
7023
7708
|
const errors = [];
|
|
7024
7709
|
const warnings = [];
|
|
7025
7710
|
const details = {};
|
|
7026
|
-
if (!
|
|
7711
|
+
if (!isObject8(input)) {
|
|
7027
7712
|
errors.push({
|
|
7028
7713
|
path: "root",
|
|
7029
7714
|
message: "Mapping must be an object with event patterns as keys",
|
|
@@ -7083,83 +7768,43 @@ function validateMapping(input) {
|
|
|
7083
7768
|
}
|
|
7084
7769
|
|
|
7085
7770
|
// src/commands/validate/validators/entry.ts
|
|
7086
|
-
|
|
7087
|
-
|
|
7088
|
-
var CLIENT_HEADER = "walkeros-cli/4.7.0-next-1790722899482";
|
|
7089
|
-
function pointerSegments(pointer) {
|
|
7090
|
-
if (pointer === "") return [];
|
|
7091
|
-
return pointer.split("/").slice(1).map((segment) => segment.replace(/~1/g, "/").replace(/~0/g, "~"));
|
|
7092
|
-
}
|
|
7093
|
-
function valueAt(root, segments) {
|
|
7094
|
-
let current = root;
|
|
7095
|
-
for (const segment of segments) {
|
|
7096
|
-
if (Array.isArray(current)) current = current[Number(segment)];
|
|
7097
|
-
else if (isObject8(current)) current = current[segment];
|
|
7098
|
-
else return void 0;
|
|
7099
|
-
}
|
|
7100
|
-
return current;
|
|
7101
|
-
}
|
|
7102
|
-
async function checkEntrySettings(target, errors, skipped, packages) {
|
|
7103
|
-
const at = `flows.${target.flow}.${target.section}.${target.key}`;
|
|
7104
|
-
const packageName = typeof target.entry.package === "string" ? target.entry.package : "";
|
|
7105
|
-
if (!packageName) {
|
|
7106
|
-
skipped.push({
|
|
7107
|
-
path: at,
|
|
7108
|
-
check: "entry:settings",
|
|
7109
|
-
reason: "No package field, so there is no settings schema to fetch",
|
|
7110
|
-
code: "NO_PACKAGE"
|
|
7111
|
-
});
|
|
7112
|
-
return;
|
|
7113
|
-
}
|
|
7114
|
-
packages.push({ path: at, package: packageName });
|
|
7115
|
-
let settingsSchema;
|
|
7116
|
-
try {
|
|
7117
|
-
const info = await fetchPackageSchema(packageName, {
|
|
7118
|
-
client: CLIENT_HEADER
|
|
7119
|
-
});
|
|
7120
|
-
settingsSchema = info.schemas?.settings;
|
|
7121
|
-
} catch (error) {
|
|
7122
|
-
skipped.push({
|
|
7123
|
-
path: at,
|
|
7124
|
-
check: "entry:settings",
|
|
7125
|
-
reason: `Schema for ${packageName} could not be fetched: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
7126
|
-
code: "SCHEMA_UNAVAILABLE"
|
|
7127
|
-
});
|
|
7128
|
-
return;
|
|
7129
|
-
}
|
|
7130
|
-
if (!isObject8(settingsSchema)) {
|
|
7131
|
-
skipped.push({
|
|
7132
|
-
path: at,
|
|
7133
|
-
check: "entry:settings",
|
|
7134
|
-
reason: `Package ${packageName} has no settings schema`,
|
|
7135
|
-
code: "NO_SETTINGS_SCHEMA"
|
|
7136
|
-
});
|
|
7137
|
-
return;
|
|
7138
|
-
}
|
|
7139
|
-
const config = isObject8(target.entry.config) ? target.entry.config : {};
|
|
7140
|
-
const settings = config.settings ?? {};
|
|
7141
|
-
const ajv = new Ajv({ allErrors: true, validateFormats: false });
|
|
7142
|
-
const validate2 = ajv.compile(settingsSchema);
|
|
7143
|
-
if (validate2(settings)) return;
|
|
7144
|
-
for (const e of validate2.errors || []) {
|
|
7145
|
-
const segments = pointerSegments(e.instancePath);
|
|
7146
|
-
const error = {
|
|
7147
|
-
path: [`${at}.config.settings`, ...segments].join("."),
|
|
7148
|
-
message: e.message || "Unknown error",
|
|
7149
|
-
code: "ENTRY_SCHEMA",
|
|
7150
|
-
keyword: e.keyword
|
|
7151
|
-
};
|
|
7152
|
-
if (segments.length > 0) error.value = valueAt(settings, segments);
|
|
7153
|
-
errors.push(error);
|
|
7154
|
-
}
|
|
7155
|
-
}
|
|
7156
|
-
async function validateEntry(path20, flowConfig, options = {}) {
|
|
7157
|
-
const resolved = resolveScope(flowConfig, { flow: options.flow, path: path20 });
|
|
7771
|
+
async function validateEntry(path23, flowConfig, options = {}) {
|
|
7772
|
+
const resolved = resolveScope(flowConfig, { flow: options.flow, path: path23 });
|
|
7158
7773
|
const errors = [...resolved.errors];
|
|
7159
7774
|
const skipped = [];
|
|
7775
|
+
const deferred = [];
|
|
7160
7776
|
const packages = [];
|
|
7777
|
+
const context2 = createSettingsContext(options.configDir);
|
|
7778
|
+
const file = isFlowJson2(flowConfig) ? flowConfig : void 0;
|
|
7779
|
+
const resolutions = /* @__PURE__ */ new Map();
|
|
7161
7780
|
for (const target of resolved.entries) {
|
|
7162
|
-
|
|
7781
|
+
const at = `flows.${target.flow}.${target.section}.${target.key}`;
|
|
7782
|
+
let resolution = resolutions.get(target.flow);
|
|
7783
|
+
if (!resolution && file) {
|
|
7784
|
+
resolution = resolveFlow2(file, target.flow);
|
|
7785
|
+
resolutions.set(target.flow, resolution);
|
|
7786
|
+
if (!resolution.ok) errors.push(resolution.error);
|
|
7787
|
+
}
|
|
7788
|
+
if (!resolution?.ok) {
|
|
7789
|
+
skipped.push({
|
|
7790
|
+
path: at,
|
|
7791
|
+
check: "entry:settings",
|
|
7792
|
+
reason: `flows.${target.flow} does not resolve, so its settings cannot be checked`,
|
|
7793
|
+
code: "GATED_BY_ERRORS"
|
|
7794
|
+
});
|
|
7795
|
+
continue;
|
|
7796
|
+
}
|
|
7797
|
+
const outcome = await checkStepSettings(
|
|
7798
|
+
target,
|
|
7799
|
+
resolution.flow,
|
|
7800
|
+
file?.flows[target.flow],
|
|
7801
|
+
"entry:settings",
|
|
7802
|
+
context2
|
|
7803
|
+
);
|
|
7804
|
+
errors.push(...outcome.findings);
|
|
7805
|
+
skipped.push(...outcome.skipped);
|
|
7806
|
+
deferred.push(...outcome.deferred);
|
|
7807
|
+
if (outcome.checked) packages.push(outcome.checked);
|
|
7163
7808
|
}
|
|
7164
7809
|
return {
|
|
7165
7810
|
valid: errors.length === 0,
|
|
@@ -7169,18 +7814,105 @@ async function validateEntry(path20, flowConfig, options = {}) {
|
|
|
7169
7814
|
details: {
|
|
7170
7815
|
scope: describeScope(resolved, ["entry:settings"]),
|
|
7171
7816
|
skipped,
|
|
7817
|
+
deferred,
|
|
7172
7818
|
...packages.length > 0 ? { packages } : {}
|
|
7173
7819
|
}
|
|
7174
7820
|
};
|
|
7175
7821
|
}
|
|
7176
7822
|
|
|
7177
7823
|
// src/commands/validate/types.ts
|
|
7824
|
+
var VALIDATE_CODES = [
|
|
7825
|
+
// Input and options
|
|
7826
|
+
"INPUT_ERROR",
|
|
7827
|
+
"SERIALIZATION_ERROR",
|
|
7828
|
+
"OPTION_NOT_APPLICABLE",
|
|
7829
|
+
// Scope (--flow, --path)
|
|
7830
|
+
"FLOW_NOT_FOUND",
|
|
7831
|
+
"ENTRY_NOT_FOUND",
|
|
7832
|
+
"AMBIGUOUS_ENTRY",
|
|
7833
|
+
"UNSUPPORTED_SECTION",
|
|
7834
|
+
"INVALID_PATH",
|
|
7835
|
+
// Flow file
|
|
7836
|
+
"SCHEMA_VALIDATION",
|
|
7837
|
+
"CONFIG_WARNING",
|
|
7838
|
+
"EMPTY_FLOWS",
|
|
7839
|
+
"UNKNOWN_KEY",
|
|
7840
|
+
"CONFLICT",
|
|
7841
|
+
"MISSING_PACKAGE",
|
|
7842
|
+
"OBSOLETE_CODE_STRING",
|
|
7843
|
+
"INVALID_IMPORT",
|
|
7844
|
+
"INVALID_CODE_SHAPE",
|
|
7845
|
+
"PACKAGE_VERSION_MISSING",
|
|
7846
|
+
"DEPRECATED_PACKAGE",
|
|
7847
|
+
"UNKNOWN_ROUTE_TARGET",
|
|
7848
|
+
"ROUTE_DEAD_CODE",
|
|
7849
|
+
"ROUTE_EMPTY_MANY",
|
|
7850
|
+
"ROUTE_SINGLE_MANY",
|
|
7851
|
+
"ROUTE_FIRST_MATCH",
|
|
7852
|
+
"INCOMPATIBLE_EXAMPLES",
|
|
7853
|
+
"EXAMPLES_INCOMPLETE",
|
|
7854
|
+
"CONTRACT_VIOLATION",
|
|
7855
|
+
"MAPPING_DOT_KEY",
|
|
7856
|
+
"FLOW_REF_WARNING",
|
|
7857
|
+
"FLOW_CYCLE",
|
|
7858
|
+
"VAR_CYCLE",
|
|
7859
|
+
// Structure (the bundler's own preflight, validateFlowStructure)
|
|
7860
|
+
"INVALID_COMPONENT_NAME",
|
|
7861
|
+
"INVALID_REFERENCE",
|
|
7862
|
+
"STORE_REFERENCE_NOT_FOUND",
|
|
7863
|
+
// Resolution (getFlowSettings, as the bundler resolves the flow)
|
|
7864
|
+
"UNRESOLVED_REFERENCE",
|
|
7865
|
+
"MISSING_ENV",
|
|
7866
|
+
"WEB_SECRET_REF",
|
|
7867
|
+
"UNRESOLVED_CONTRACT",
|
|
7868
|
+
// Entry settings against the package schema
|
|
7869
|
+
"ENTRY_SCHEMA",
|
|
7870
|
+
// Contract
|
|
7871
|
+
"NO_CONTRACT_SECTION",
|
|
7872
|
+
"INVALID_CONTRACT",
|
|
7873
|
+
"FLAT_CONTRACT_SHAPE",
|
|
7874
|
+
"INVALID_CONTRACT_ENTRY",
|
|
7875
|
+
"UNKNOWN_CONTRACT_KEY",
|
|
7876
|
+
"INVALID_TAGGING",
|
|
7877
|
+
"INVALID_SCHEMA",
|
|
7878
|
+
"INVALID_EXTENDS",
|
|
7879
|
+
"INVALID_SECTION",
|
|
7880
|
+
"INVALID_EVENTS",
|
|
7881
|
+
"CIRCULAR_EXTENDS",
|
|
7882
|
+
"INVALID_ENTITY_KEY",
|
|
7883
|
+
"INVALID_ENTITY",
|
|
7884
|
+
"INVALID_ACTION_KEY",
|
|
7885
|
+
"INVALID_SCHEMA_ENTRY",
|
|
7886
|
+
// Event
|
|
7887
|
+
"NOT_AN_OBJECT",
|
|
7888
|
+
"MISSING_EVENT_NAME",
|
|
7889
|
+
"EMPTY_EVENT_NAME",
|
|
7890
|
+
"INVALID_EVENT_NAME",
|
|
7891
|
+
// Mapping
|
|
7892
|
+
"INVALID_MAPPING_TYPE",
|
|
7893
|
+
"INVALID_EVENT_PATTERN",
|
|
7894
|
+
"INVALID_RULE_TYPE",
|
|
7895
|
+
"CATCH_ALL_NOT_LAST",
|
|
7896
|
+
// Skips (details.skipped[].code)
|
|
7897
|
+
"GATED_BY_ERRORS",
|
|
7898
|
+
"CONTRACT_NOT_STATIC",
|
|
7899
|
+
"NO_PACKAGE",
|
|
7900
|
+
"NO_SETTINGS_SCHEMA",
|
|
7901
|
+
"SCHEMA_UNAVAILABLE"
|
|
7902
|
+
];
|
|
7178
7903
|
var USAGE_CODES = ["OPTION_NOT_APPLICABLE"];
|
|
7179
7904
|
|
|
7180
7905
|
// src/commands/validate/index.ts
|
|
7181
7906
|
function inapplicableOptions(type, options) {
|
|
7182
|
-
if (type === "flow") return [];
|
|
7183
7907
|
const errors = [];
|
|
7908
|
+
if (options.offline === true && (type !== "flow" || options.path)) {
|
|
7909
|
+
errors.push({
|
|
7910
|
+
path: "options.offline",
|
|
7911
|
+
message: type === "flow" ? "--offline removes the package settings check, which is all --path checks; drop one of them" : `--offline applies to a whole flow file and does not apply to -t ${type}`,
|
|
7912
|
+
code: "OPTION_NOT_APPLICABLE"
|
|
7913
|
+
});
|
|
7914
|
+
}
|
|
7915
|
+
if (type === "flow") return errors;
|
|
7184
7916
|
if (options.path !== void 0) {
|
|
7185
7917
|
errors.push({
|
|
7186
7918
|
path: "options.path",
|
|
@@ -7197,6 +7929,31 @@ function inapplicableOptions(type, options) {
|
|
|
7197
7929
|
}
|
|
7198
7930
|
return errors;
|
|
7199
7931
|
}
|
|
7932
|
+
function validateContractInput(input) {
|
|
7933
|
+
if (!isFlowJson2(input)) return validateContract(input);
|
|
7934
|
+
const contract = isObject9(input) ? input.contract : void 0;
|
|
7935
|
+
if (contract === void 0) {
|
|
7936
|
+
return {
|
|
7937
|
+
valid: false,
|
|
7938
|
+
type: "contract",
|
|
7939
|
+
errors: [
|
|
7940
|
+
{
|
|
7941
|
+
path: "contract",
|
|
7942
|
+
message: "The flow file has no contract section to validate",
|
|
7943
|
+
code: "NO_CONTRACT_SECTION"
|
|
7944
|
+
}
|
|
7945
|
+
],
|
|
7946
|
+
warnings: [],
|
|
7947
|
+
details: {}
|
|
7948
|
+
};
|
|
7949
|
+
}
|
|
7950
|
+
return validateContract(contract);
|
|
7951
|
+
}
|
|
7952
|
+
function configDirOf(input) {
|
|
7953
|
+
if (typeof input !== "string") return void 0;
|
|
7954
|
+
const candidate = path20.resolve(input);
|
|
7955
|
+
return fs20.existsSync(candidate) && fs20.statSync(candidate).isFile() ? path20.dirname(candidate) : void 0;
|
|
7956
|
+
}
|
|
7200
7957
|
function withDocumentScope(result, check) {
|
|
7201
7958
|
return {
|
|
7202
7959
|
...result,
|
|
@@ -7223,18 +7980,32 @@ async function validate(type, input, options = {}) {
|
|
|
7223
7980
|
details: { scope: { flows: [], checks: [] }, skipped: [] }
|
|
7224
7981
|
};
|
|
7225
7982
|
}
|
|
7983
|
+
const result = await validateByType(type, input, resolved, options);
|
|
7984
|
+
return options.strict === true ? escalateStrict(result) : result;
|
|
7985
|
+
}
|
|
7986
|
+
function escalateStrict(result) {
|
|
7987
|
+
const skipped = result.details.skipped ?? [];
|
|
7988
|
+
if (result.warnings.length === 0 && skipped.length === 0) return result;
|
|
7989
|
+
return { ...result, valid: false };
|
|
7990
|
+
}
|
|
7991
|
+
async function validateByType(type, input, resolved, options) {
|
|
7226
7992
|
switch (type) {
|
|
7227
7993
|
case "contract":
|
|
7228
|
-
return withDocumentScope(
|
|
7994
|
+
return withDocumentScope(validateContractInput(resolved), "contract");
|
|
7229
7995
|
case "event":
|
|
7230
7996
|
return withDocumentScope(validateEvent2(resolved), "event");
|
|
7231
7997
|
case "flow":
|
|
7232
7998
|
if (options.path !== void 0) {
|
|
7233
|
-
return validateEntry(options.path, resolved, {
|
|
7999
|
+
return validateEntry(options.path, resolved, {
|
|
8000
|
+
flow: options.flow,
|
|
8001
|
+
configDir: options.configDir ?? configDirOf(input)
|
|
8002
|
+
});
|
|
7234
8003
|
}
|
|
7235
|
-
return
|
|
8004
|
+
return validateFlowWithPackages(resolved, {
|
|
7236
8005
|
flow: options.flow,
|
|
7237
|
-
strict: options.strict
|
|
8006
|
+
strict: options.strict,
|
|
8007
|
+
offline: options.offline,
|
|
8008
|
+
configDir: options.configDir ?? configDirOf(input)
|
|
7238
8009
|
});
|
|
7239
8010
|
case "mapping":
|
|
7240
8011
|
return withDocumentScope(validateMapping(resolved), "mapping");
|
|
@@ -7255,6 +8026,7 @@ function formatScope(result) {
|
|
|
7255
8026
|
);
|
|
7256
8027
|
}
|
|
7257
8028
|
parts.push(`${scope.checks.length} check(s): ${scope.checks.join(", ")}`);
|
|
8029
|
+
if (scope.offline) parts.push("offline: package settings not checked");
|
|
7258
8030
|
return `Scope: ${parts.join("; ")}`;
|
|
7259
8031
|
}
|
|
7260
8032
|
function formatResult(result, options) {
|
|
@@ -7293,7 +8065,13 @@ function formatResult(result, options) {
|
|
|
7293
8065
|
chalk2.gray(` - skipped ${skip.check} at ${skip.path}: ${skip.reason}`)
|
|
7294
8066
|
);
|
|
7295
8067
|
}
|
|
7296
|
-
if (
|
|
8068
|
+
if (options.exitCode === 2) {
|
|
8069
|
+
lines.push(
|
|
8070
|
+
chalk2.red(
|
|
8071
|
+
` \u2717 Failed under --strict: ${result.warnings.length} warning(s) and ${skipped.length} skipped check(s) count as failures`
|
|
8072
|
+
)
|
|
8073
|
+
);
|
|
8074
|
+
} else if (result.valid && skipped.length === 0) {
|
|
7297
8075
|
lines.push(chalk2.green(` \u2713 All checks passed`));
|
|
7298
8076
|
} else if (result.valid) {
|
|
7299
8077
|
lines.push(
|
|
@@ -7326,16 +8104,18 @@ async function validateCommand(options) {
|
|
|
7326
8104
|
const result = await validate(options.type, input, {
|
|
7327
8105
|
flow: options.flow,
|
|
7328
8106
|
path: options.path,
|
|
7329
|
-
strict: options.strict
|
|
8107
|
+
strict: options.strict,
|
|
8108
|
+
offline: options.offline
|
|
7330
8109
|
});
|
|
8110
|
+
exitCode = exitCodeOf(result, options.strict === true);
|
|
7331
8111
|
if (!options.silent || options.output) {
|
|
7332
8112
|
const formatted = formatResult(result, {
|
|
7333
8113
|
json: options.json,
|
|
7334
|
-
verbose: options.verbose
|
|
8114
|
+
verbose: options.verbose,
|
|
8115
|
+
exitCode
|
|
7335
8116
|
});
|
|
7336
8117
|
await writeResult(formatted + "\n", { output: options.output });
|
|
7337
8118
|
}
|
|
7338
|
-
exitCode = exitCodeOf(result, options.strict === true);
|
|
7339
8119
|
} catch (error) {
|
|
7340
8120
|
const errorMessage = getErrorMessage(error);
|
|
7341
8121
|
if (options.json) {
|
|
@@ -7347,7 +8127,7 @@ async function validateCommand(options) {
|
|
|
7347
8127
|
{ path: "input", message: errorMessage, code: "INPUT_ERROR" }
|
|
7348
8128
|
],
|
|
7349
8129
|
warnings: [],
|
|
7350
|
-
details: {}
|
|
8130
|
+
details: { scope: { flows: [], checks: [] }, skipped: [] }
|
|
7351
8131
|
},
|
|
7352
8132
|
null,
|
|
7353
8133
|
2
|
|
@@ -7365,10 +8145,10 @@ function exitCodeOf(result, strict) {
|
|
|
7365
8145
|
(e) => USAGE_CODES.some((usageCode) => usageCode === e.code)
|
|
7366
8146
|
))
|
|
7367
8147
|
return 3;
|
|
7368
|
-
if (
|
|
8148
|
+
if (result.errors.length > 0) return 1;
|
|
7369
8149
|
const skipped = result.details.skipped ?? [];
|
|
7370
8150
|
if (strict && (result.warnings.length > 0 || skipped.length > 0)) return 2;
|
|
7371
|
-
return 0;
|
|
8151
|
+
return result.valid ? 0 : 1;
|
|
7372
8152
|
}
|
|
7373
8153
|
|
|
7374
8154
|
// src/commands/login/index.ts
|
|
@@ -7386,7 +8166,7 @@ async function openInBrowser(url) {
|
|
|
7386
8166
|
await open(url);
|
|
7387
8167
|
}
|
|
7388
8168
|
function delay3(ms) {
|
|
7389
|
-
return new Promise((
|
|
8169
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
7390
8170
|
}
|
|
7391
8171
|
async function loginCommand(options) {
|
|
7392
8172
|
const logger = createCLILogger(options);
|
|
@@ -7450,14 +8230,11 @@ async function completeDeviceLogin(deviceCode, options = {}) {
|
|
|
7450
8230
|
break;
|
|
7451
8231
|
attempts += 1;
|
|
7452
8232
|
await delay3(intervalMs);
|
|
7453
|
-
const
|
|
7454
|
-
|
|
7455
|
-
deviceCode,
|
|
7456
|
-
fetchFn,
|
|
7457
|
-
AbortSignal.timeout(Math.max(1, deadline - Date.now()))
|
|
7458
|
-
);
|
|
8233
|
+
const signal = AbortSignal.timeout(Math.max(1, deadline - Date.now()));
|
|
8234
|
+
const poll = await pollDeviceToken(appUrl, deviceCode, fetchFn, signal);
|
|
7459
8235
|
if (poll.status === "pending") {
|
|
7460
8236
|
waiting = "pending";
|
|
8237
|
+
if (signal.aborted) break;
|
|
7461
8238
|
continue;
|
|
7462
8239
|
}
|
|
7463
8240
|
if (poll.status === "slow_down") {
|
|
@@ -7559,18 +8336,18 @@ async function logout() {
|
|
|
7559
8336
|
import createClient from "openapi-fetch";
|
|
7560
8337
|
|
|
7561
8338
|
// src/core/contract.ts
|
|
7562
|
-
import { createHash } from "crypto";
|
|
8339
|
+
import { createHash as createHash2 } from "crypto";
|
|
7563
8340
|
import semver4 from "semver";
|
|
7564
8341
|
var bakedContractVersion = true ? "4.7.0" : PLACEHOLDER;
|
|
7565
8342
|
var bakedContractHash = true ? "1758bf6b37ad72eb37dd8176f240ae64b16c5b1f9da376cab6357027c835a833" : "";
|
|
7566
|
-
function
|
|
8343
|
+
function isRecord4(value) {
|
|
7567
8344
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
7568
8345
|
}
|
|
7569
8346
|
function canonicalize(value) {
|
|
7570
8347
|
if (Array.isArray(value)) {
|
|
7571
8348
|
return value.map(canonicalize);
|
|
7572
8349
|
}
|
|
7573
|
-
if (
|
|
8350
|
+
if (isRecord4(value)) {
|
|
7574
8351
|
const result = {};
|
|
7575
8352
|
for (const key of Object.keys(value).sort()) {
|
|
7576
8353
|
result[key] = canonicalize(value[key]);
|
|
@@ -7580,7 +8357,7 @@ function canonicalize(value) {
|
|
|
7580
8357
|
return value;
|
|
7581
8358
|
}
|
|
7582
8359
|
function stripInfoVersion(doc) {
|
|
7583
|
-
if (!
|
|
8360
|
+
if (!isRecord4(doc) || !isRecord4(doc.info)) {
|
|
7584
8361
|
return doc;
|
|
7585
8362
|
}
|
|
7586
8363
|
const restInfo = {};
|
|
@@ -7591,7 +8368,7 @@ function stripInfoVersion(doc) {
|
|
|
7591
8368
|
}
|
|
7592
8369
|
function canonicalContractHash(doc) {
|
|
7593
8370
|
const canonical = canonicalize(stripInfoVersion(doc));
|
|
7594
|
-
return
|
|
8371
|
+
return createHash2("sha256").update(JSON.stringify(canonical)).digest("hex");
|
|
7595
8372
|
}
|
|
7596
8373
|
var HEALTH_TIMEOUT_MS = 5e3;
|
|
7597
8374
|
async function fetchHealth(baseUrl) {
|
|
@@ -7601,7 +8378,7 @@ async function fetchHealth(baseUrl) {
|
|
|
7601
8378
|
});
|
|
7602
8379
|
const body = await res.json().catch(() => void 0);
|
|
7603
8380
|
const result = { reachable: true };
|
|
7604
|
-
if (
|
|
8381
|
+
if (isRecord4(body)) {
|
|
7605
8382
|
const record = body;
|
|
7606
8383
|
if (typeof record.status === "string") result.status = record.status;
|
|
7607
8384
|
if (typeof record.appVersion === "string")
|
|
@@ -8051,19 +8828,17 @@ async function getFlowCommand(flowId, options) {
|
|
|
8051
8828
|
);
|
|
8052
8829
|
}
|
|
8053
8830
|
async function createFlowCommand(name, options) {
|
|
8054
|
-
|
|
8055
|
-
|
|
8056
|
-
|
|
8057
|
-
|
|
8058
|
-
);
|
|
8831
|
+
await handleResult2(async () => {
|
|
8832
|
+
const content = options.content ? await loadFlowContent(options.content) : JSON.parse(await readFlowStdin());
|
|
8833
|
+
return createFlow({ name, content, projectId: options.project });
|
|
8834
|
+
}, options);
|
|
8059
8835
|
}
|
|
8060
8836
|
async function updateFlowCommand(flowId, options) {
|
|
8061
|
-
const content = options.content ? JSON.parse(options.content) : void 0;
|
|
8062
8837
|
await handleResult2(
|
|
8063
|
-
() => updateFlow({
|
|
8838
|
+
async () => updateFlow({
|
|
8064
8839
|
flowId,
|
|
8065
8840
|
name: options.name,
|
|
8066
|
-
content,
|
|
8841
|
+
content: options.content ? await loadFlowContent(options.content) : void 0,
|
|
8067
8842
|
projectId: options.project
|
|
8068
8843
|
}),
|
|
8069
8844
|
options
|
|
@@ -8081,6 +8856,9 @@ async function duplicateFlowCommand(flowId, options) {
|
|
|
8081
8856
|
options
|
|
8082
8857
|
);
|
|
8083
8858
|
}
|
|
8859
|
+
function loadFlowContent(input) {
|
|
8860
|
+
return loadJsonConfig(input);
|
|
8861
|
+
}
|
|
8084
8862
|
async function readFlowStdin() {
|
|
8085
8863
|
if (!isStdinPiped()) {
|
|
8086
8864
|
throw new Error("Content required: use --content or pipe via stdin");
|
|
@@ -8231,7 +9009,7 @@ async function deploySettings(options) {
|
|
|
8231
9009
|
if (e instanceof ApiError && e.retryable) {
|
|
8232
9010
|
const waitSeconds = Math.min(e.retryAfterSeconds ?? 5, 60);
|
|
8233
9011
|
options.onStatus?.("rate_limited", `retrying in ${waitSeconds}s`);
|
|
8234
|
-
await new Promise((
|
|
9012
|
+
await new Promise((resolve5) => setTimeout(resolve5, waitSeconds * 1e3));
|
|
8235
9013
|
response = await triggerDeploy();
|
|
8236
9014
|
} else {
|
|
8237
9015
|
throw e;
|
|
@@ -8355,32 +9133,7 @@ async function getDeploymentCommand(flowId, options) {
|
|
|
8355
9133
|
}
|
|
8356
9134
|
|
|
8357
9135
|
// src/commands/deployments/index.ts
|
|
8358
|
-
import { getPlatform as getPlatform4, isObject as
|
|
8359
|
-
|
|
8360
|
-
// src/version.ts
|
|
8361
|
-
import { readFileSync as readFileSync2 } from "fs";
|
|
8362
|
-
import { fileURLToPath } from "url";
|
|
8363
|
-
import { dirname as dirname3, join as join4 } from "path";
|
|
8364
|
-
var versionFilename = fileURLToPath(import.meta.url);
|
|
8365
|
-
var versionDirname = dirname3(versionFilename);
|
|
8366
|
-
function findPackageJson() {
|
|
8367
|
-
const paths = [
|
|
8368
|
-
join4(versionDirname, "../package.json"),
|
|
8369
|
-
// dist/ or src/
|
|
8370
|
-
join4(versionDirname, "../../package.json")
|
|
8371
|
-
// src/core/ (not used, but safe)
|
|
8372
|
-
];
|
|
8373
|
-
for (const p of paths) {
|
|
8374
|
-
try {
|
|
8375
|
-
return readFileSync2(p, "utf-8");
|
|
8376
|
-
} catch {
|
|
8377
|
-
}
|
|
8378
|
-
}
|
|
8379
|
-
return JSON.stringify({ version: "0.0.0" });
|
|
8380
|
-
}
|
|
8381
|
-
var VERSION = JSON.parse(findPackageJson()).version;
|
|
8382
|
-
|
|
8383
|
-
// src/commands/deployments/index.ts
|
|
9136
|
+
import { getPlatform as getPlatform4, isObject as isObject10 } from "@walkeros/core";
|
|
8384
9137
|
async function listDeployments(options = {}) {
|
|
8385
9138
|
const id = options.projectId ?? requireProjectId();
|
|
8386
9139
|
const params = new URLSearchParams();
|
|
@@ -8541,8 +9294,8 @@ async function createDeployCommand(config, options) {
|
|
|
8541
9294
|
const flowName = options.flow ?? Object.keys(flows)[0];
|
|
8542
9295
|
if (!flowName) throw new Error("No flows found in config");
|
|
8543
9296
|
const flowSettings = flows[flowName];
|
|
8544
|
-
if (!
|
|
8545
|
-
const platform =
|
|
9297
|
+
if (!isObject10(flowSettings)) throw new Error("Invalid flow config");
|
|
9298
|
+
const platform = isObject10(flowSettings.config) ? flowSettings.config.platform : void 0;
|
|
8546
9299
|
if (platform !== "web" && platform !== "server")
|
|
8547
9300
|
throw new Error(
|
|
8548
9301
|
`Flow "${flowName}" must have config.platform set to "web" or "server"`
|
|
@@ -8664,14 +9417,14 @@ async function feedbackCommand(text) {
|
|
|
8664
9417
|
}
|
|
8665
9418
|
}
|
|
8666
9419
|
function promptUser(question) {
|
|
8667
|
-
return new Promise((
|
|
9420
|
+
return new Promise((resolve5) => {
|
|
8668
9421
|
const rl = createInterface({
|
|
8669
9422
|
input: process.stdin,
|
|
8670
9423
|
output: process.stderr
|
|
8671
9424
|
});
|
|
8672
9425
|
rl.question(question, (answer) => {
|
|
8673
9426
|
rl.close();
|
|
8674
|
-
|
|
9427
|
+
resolve5(answer);
|
|
8675
9428
|
});
|
|
8676
9429
|
});
|
|
8677
9430
|
}
|
|
@@ -8744,12 +9497,12 @@ function telemetryDisableCommand() {
|
|
|
8744
9497
|
}
|
|
8745
9498
|
|
|
8746
9499
|
// src/index.ts
|
|
8747
|
-
import { validateFlowStructure } from "@walkeros/core/dev";
|
|
9500
|
+
import { validateFlowStructure as validateFlowStructure2 } from "@walkeros/core/dev";
|
|
8748
9501
|
|
|
8749
9502
|
// src/commands/bundle/wrap.ts
|
|
8750
|
-
import * as
|
|
9503
|
+
import * as path21 from "path";
|
|
8751
9504
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
8752
|
-
import
|
|
9505
|
+
import fs21 from "fs-extra";
|
|
8753
9506
|
import * as esbuild3 from "esbuild";
|
|
8754
9507
|
function extractDevExternals(skeletonText) {
|
|
8755
9508
|
const pattern = /import\(\s*['"]([^'"]+\/dev)['"]\s*\)/g;
|
|
@@ -8761,13 +9514,13 @@ function extractDevExternals(skeletonText) {
|
|
|
8761
9514
|
return Array.from(found);
|
|
8762
9515
|
}
|
|
8763
9516
|
function getNodeResolutionPaths() {
|
|
8764
|
-
const here =
|
|
9517
|
+
const here = path21.dirname(fileURLToPath2(import.meta.url));
|
|
8765
9518
|
const candidates = [];
|
|
8766
9519
|
let dir = here;
|
|
8767
9520
|
for (let i = 0; i < 8; i++) {
|
|
8768
|
-
const candidate =
|
|
9521
|
+
const candidate = path21.join(dir, "node_modules");
|
|
8769
9522
|
candidates.push(candidate);
|
|
8770
|
-
const parent =
|
|
9523
|
+
const parent = path21.dirname(dir);
|
|
8771
9524
|
if (parent === dir) break;
|
|
8772
9525
|
dir = parent;
|
|
8773
9526
|
}
|
|
@@ -8794,11 +9547,11 @@ async function wrapSkeleton(options) {
|
|
|
8794
9547
|
`Invalid previewOrigin "${options.preview.previewOrigin}". Must be a bare hostname matching /^[a-z0-9.-]+$/.`
|
|
8795
9548
|
);
|
|
8796
9549
|
}
|
|
8797
|
-
if (!await
|
|
9550
|
+
if (!await fs21.pathExists(skeletonPath)) {
|
|
8798
9551
|
throw new Error(`wrapSkeleton: skeleton not found at ${skeletonPath}`);
|
|
8799
9552
|
}
|
|
8800
|
-
const absoluteSkeletonPath =
|
|
8801
|
-
const skeletonText = await
|
|
9553
|
+
const absoluteSkeletonPath = path21.resolve(skeletonPath);
|
|
9554
|
+
const skeletonText = await fs21.readFile(absoluteSkeletonPath, "utf-8");
|
|
8802
9555
|
const devExternals = extractDevExternals(skeletonText);
|
|
8803
9556
|
const entryText = platform === "browser" ? generateWrapEntry(absoluteSkeletonPath, {
|
|
8804
9557
|
...windowCollector ? { windowCollector } : {},
|
|
@@ -8809,10 +9562,10 @@ async function wrapSkeleton(options) {
|
|
|
8809
9562
|
...options.observe ? { observe: options.observe } : {}
|
|
8810
9563
|
}) : generateWrapEntryServer(absoluteSkeletonPath);
|
|
8811
9564
|
const entryDir = await tmpRunDir("wrap");
|
|
8812
|
-
const entryPath =
|
|
9565
|
+
const entryPath = path21.join(entryDir, "flow.mjs");
|
|
8813
9566
|
try {
|
|
8814
|
-
await
|
|
8815
|
-
await
|
|
9567
|
+
await fs21.writeFile(entryPath, entryText);
|
|
9568
|
+
await fs21.ensureDir(path21.dirname(outputPath));
|
|
8816
9569
|
const esbuildOptions = {
|
|
8817
9570
|
entryPoints: [entryPath],
|
|
8818
9571
|
bundle: true,
|
|
@@ -8853,16 +9606,16 @@ async function wrapSkeleton(options) {
|
|
|
8853
9606
|
}
|
|
8854
9607
|
await esbuild3.build(esbuildOptions);
|
|
8855
9608
|
} finally {
|
|
8856
|
-
await
|
|
9609
|
+
await fs21.remove(entryDir).catch(() => {
|
|
8857
9610
|
});
|
|
8858
9611
|
}
|
|
8859
9612
|
}
|
|
8860
9613
|
|
|
8861
9614
|
// src/commands/bundle/manifest.ts
|
|
8862
9615
|
import crypto2 from "crypto";
|
|
8863
|
-
import
|
|
8864
|
-
import
|
|
8865
|
-
import { FlowReferenceError } from "@walkeros/core";
|
|
9616
|
+
import path22 from "path";
|
|
9617
|
+
import fs22 from "fs-extra";
|
|
9618
|
+
import { FlowReferenceError as FlowReferenceError2 } from "@walkeros/core";
|
|
8866
9619
|
|
|
8867
9620
|
// src/schemas/build-manifest.ts
|
|
8868
9621
|
import { z as z3 } from "@walkeros/core/dev";
|
|
@@ -9015,6 +9768,66 @@ var BuildResultSchema = z3.object({
|
|
|
9015
9768
|
}).optional()
|
|
9016
9769
|
}).meta({ id: "BuildResult", title: "walkeros bundle --manifest result" });
|
|
9017
9770
|
|
|
9771
|
+
// src/commands/bundle/fetch-retry.ts
|
|
9772
|
+
var BACKOFF_MS = [1e3, 3e3];
|
|
9773
|
+
function defaultSleep(ms) {
|
|
9774
|
+
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
9775
|
+
}
|
|
9776
|
+
function isTransientStatus(status) {
|
|
9777
|
+
return status >= 500 || status === 429;
|
|
9778
|
+
}
|
|
9779
|
+
function causeDetail(error) {
|
|
9780
|
+
if (!("cause" in error)) return void 0;
|
|
9781
|
+
const cause = error.cause;
|
|
9782
|
+
if (typeof cause !== "object" || cause === null) return void 0;
|
|
9783
|
+
if ("code" in cause && typeof cause.code === "string") return cause.code;
|
|
9784
|
+
if ("name" in cause && typeof cause.name === "string" && cause.name !== "Error") {
|
|
9785
|
+
return cause.name;
|
|
9786
|
+
}
|
|
9787
|
+
return void 0;
|
|
9788
|
+
}
|
|
9789
|
+
function describeFetchError(failure, timeoutMs) {
|
|
9790
|
+
if (failure instanceof Response) return `HTTP ${failure.status}`;
|
|
9791
|
+
if (typeof failure !== "object" || failure === null) return "fetch failed";
|
|
9792
|
+
if ("name" in failure && failure.name === "TimeoutError") {
|
|
9793
|
+
return timeoutMs === void 0 ? "timed out" : `timed out after ${timeoutMs / 1e3}s`;
|
|
9794
|
+
}
|
|
9795
|
+
const detail = causeDetail(failure);
|
|
9796
|
+
if (detail) return `fetch failed (${detail})`;
|
|
9797
|
+
return "fetch failed";
|
|
9798
|
+
}
|
|
9799
|
+
async function fetchWithRetry(url, init, options) {
|
|
9800
|
+
const { label, timeoutMs, warn, sleep = defaultSleep } = options;
|
|
9801
|
+
const maxAttempts = BACKOFF_MS.length + 1;
|
|
9802
|
+
for (let attempt = 1; ; attempt++) {
|
|
9803
|
+
let failure;
|
|
9804
|
+
try {
|
|
9805
|
+
const response = await fetch(url, {
|
|
9806
|
+
...init,
|
|
9807
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
9808
|
+
});
|
|
9809
|
+
if (response.ok) return response;
|
|
9810
|
+
failure = response;
|
|
9811
|
+
} catch (error) {
|
|
9812
|
+
failure = error;
|
|
9813
|
+
}
|
|
9814
|
+
const reason = describeFetchError(failure, timeoutMs);
|
|
9815
|
+
if (failure instanceof Response && !isTransientStatus(failure.status)) {
|
|
9816
|
+
throw new Error(`${label} failed: ${reason}`);
|
|
9817
|
+
}
|
|
9818
|
+
const delay4 = BACKOFF_MS[attempt - 1];
|
|
9819
|
+
if (delay4 === void 0) {
|
|
9820
|
+
throw new Error(
|
|
9821
|
+
`${label} failed after ${maxAttempts} attempts: ${reason}`
|
|
9822
|
+
);
|
|
9823
|
+
}
|
|
9824
|
+
warn?.(
|
|
9825
|
+
`${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${delay4 / 1e3}s`
|
|
9826
|
+
);
|
|
9827
|
+
await sleep(delay4);
|
|
9828
|
+
}
|
|
9829
|
+
}
|
|
9830
|
+
|
|
9018
9831
|
// src/commands/bundle/manifest.ts
|
|
9019
9832
|
var BUILD_MANIFEST_ENV = "BUILD_MANIFEST_URL";
|
|
9020
9833
|
var BuildError = class extends Error {
|
|
@@ -9063,7 +9876,7 @@ function assertNoLocalPaths(loaded) {
|
|
|
9063
9876
|
}
|
|
9064
9877
|
function classify(error, phase) {
|
|
9065
9878
|
if (error instanceof BuildError) return error.code;
|
|
9066
|
-
if (error instanceof
|
|
9879
|
+
if (error instanceof FlowReferenceError2) {
|
|
9067
9880
|
return error.code === "MISSING_ENV" ? "MISSING_BUILD_ENV" : "WEB_SECRET_REF";
|
|
9068
9881
|
}
|
|
9069
9882
|
if (error instanceof UnsupportedPackageSpecError) {
|
|
@@ -9074,20 +9887,17 @@ function classify(error, phase) {
|
|
|
9074
9887
|
function isHttpUrl(source) {
|
|
9075
9888
|
return source.startsWith("http://") || source.startsWith("https://");
|
|
9076
9889
|
}
|
|
9077
|
-
async function readManifestSource(source) {
|
|
9890
|
+
async function readManifestSource(source, retry) {
|
|
9078
9891
|
let text;
|
|
9079
9892
|
if (isHttpUrl(source)) {
|
|
9080
|
-
const response = await
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
|
|
9084
|
-
|
|
9085
|
-
`Manifest fetch failed: ${response.status} ${sanitizeUrl(source)}`
|
|
9086
|
-
);
|
|
9087
|
-
}
|
|
9893
|
+
const response = await fetchWithRetry(
|
|
9894
|
+
source,
|
|
9895
|
+
{},
|
|
9896
|
+
{ ...retry, label: "Manifest download", timeoutMs: 3e4 }
|
|
9897
|
+
);
|
|
9088
9898
|
text = await response.text();
|
|
9089
9899
|
} else {
|
|
9090
|
-
text = await
|
|
9900
|
+
text = await fs22.readFile(source, "utf-8");
|
|
9091
9901
|
}
|
|
9092
9902
|
return JSON.parse(text);
|
|
9093
9903
|
}
|
|
@@ -9098,46 +9908,42 @@ function contentTypeFor(outputName) {
|
|
|
9098
9908
|
}
|
|
9099
9909
|
return "application/javascript";
|
|
9100
9910
|
}
|
|
9101
|
-
async function put(url, body, contentType, headers
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9911
|
+
async function put(url, body, contentType, headers, retry) {
|
|
9912
|
+
try {
|
|
9913
|
+
await fetchWithRetry(
|
|
9914
|
+
url,
|
|
9915
|
+
{
|
|
9105
9916
|
method: "PUT",
|
|
9106
9917
|
body,
|
|
9107
|
-
headers: { ...headers, "Content-Type": contentType }
|
|
9108
|
-
|
|
9109
|
-
}
|
|
9110
|
-
} catch {
|
|
9111
|
-
return void 0;
|
|
9112
|
-
}
|
|
9113
|
-
};
|
|
9114
|
-
let response = await attempt();
|
|
9115
|
-
if (!response || response.status >= 500) response = await attempt();
|
|
9116
|
-
if (!response || !response.ok) {
|
|
9117
|
-
throw new BuildError(
|
|
9118
|
-
"UPLOAD_FAILED",
|
|
9119
|
-
`Upload failed: ${response ? response.status : "network error"} ${sanitizeUrl(url)}`
|
|
9918
|
+
headers: { ...headers, "Content-Type": contentType }
|
|
9919
|
+
},
|
|
9920
|
+
{ ...retry, label: "Upload", timeoutMs: 6e4 }
|
|
9120
9921
|
);
|
|
9922
|
+
} catch (error) {
|
|
9923
|
+
throw new BuildError("UPLOAD_FAILED", getErrorMessage(error));
|
|
9121
9924
|
}
|
|
9122
9925
|
}
|
|
9123
|
-
async function download(url, dest) {
|
|
9124
|
-
|
|
9125
|
-
|
|
9126
|
-
|
|
9127
|
-
|
|
9128
|
-
|
|
9926
|
+
async function download(url, dest, retry) {
|
|
9927
|
+
let response;
|
|
9928
|
+
try {
|
|
9929
|
+
response = await fetchWithRetry(
|
|
9930
|
+
url,
|
|
9931
|
+
{},
|
|
9932
|
+
{ ...retry, label: "Skeleton download", timeoutMs: 6e4 }
|
|
9129
9933
|
);
|
|
9934
|
+
} catch (error) {
|
|
9935
|
+
throw new BuildError("BUILD_FAILED", getErrorMessage(error));
|
|
9130
9936
|
}
|
|
9131
|
-
await
|
|
9937
|
+
await fs22.writeFile(dest, Buffer.from(await response.arrayBuffer()));
|
|
9132
9938
|
}
|
|
9133
|
-
async function buildArtifact(manifest, configPath, artifact, workDir, index, outputs) {
|
|
9134
|
-
const output =
|
|
9135
|
-
await
|
|
9939
|
+
async function buildArtifact(manifest, configPath, artifact, workDir, index, outputs, retry) {
|
|
9940
|
+
const output = path22.join(workDir, "out", artifact.outputName);
|
|
9941
|
+
await fs22.ensureDir(path22.dirname(output));
|
|
9136
9942
|
if (artifact.target === "wrap") {
|
|
9137
9943
|
let skeletonPath;
|
|
9138
9944
|
if ("url" in artifact.skeleton) {
|
|
9139
|
-
skeletonPath =
|
|
9140
|
-
await download(artifact.skeleton.url, skeletonPath);
|
|
9945
|
+
skeletonPath = path22.join(workDir, `skeleton-${index}.mjs`);
|
|
9946
|
+
await download(artifact.skeleton.url, skeletonPath, retry);
|
|
9141
9947
|
} else {
|
|
9142
9948
|
const built = outputs.get(artifact.skeleton.artifact);
|
|
9143
9949
|
if (!built) {
|
|
@@ -9156,8 +9962,8 @@ async function buildArtifact(manifest, configPath, artifact, workDir, index, out
|
|
|
9156
9962
|
});
|
|
9157
9963
|
return output;
|
|
9158
9964
|
}
|
|
9159
|
-
const scratch =
|
|
9160
|
-
await
|
|
9965
|
+
const scratch = path22.join(workDir, `cli-${index}`);
|
|
9966
|
+
await fs22.ensureDir(scratch);
|
|
9161
9967
|
await bundle(configPath, {
|
|
9162
9968
|
...manifest.flowName ? { flowName: manifest.flowName } : {},
|
|
9163
9969
|
target: artifact.target,
|
|
@@ -9170,14 +9976,15 @@ async function buildArtifact(manifest, configPath, artifact, workDir, index, out
|
|
|
9170
9976
|
});
|
|
9171
9977
|
return output;
|
|
9172
9978
|
}
|
|
9173
|
-
async function runBuildManifest(source) {
|
|
9979
|
+
async function runBuildManifest(source, retry = {}) {
|
|
9980
|
+
const report = (url, result2) => reportResult(url, result2, retry);
|
|
9174
9981
|
const result = { ok: false, toolchain: VERSION, artifacts: [] };
|
|
9175
9982
|
const fail = (code, message, outputName) => {
|
|
9176
9983
|
result.error = outputName ? { code, message, outputName } : { code, message };
|
|
9177
9984
|
};
|
|
9178
9985
|
let raw;
|
|
9179
9986
|
try {
|
|
9180
|
-
raw = await readManifestSource(source);
|
|
9987
|
+
raw = await readManifestSource(source, retry);
|
|
9181
9988
|
} catch (error) {
|
|
9182
9989
|
fail("INVALID_MANIFEST", getErrorMessage(error));
|
|
9183
9990
|
return { result, reported: false };
|
|
@@ -9204,10 +10011,10 @@ async function runBuildManifest(source) {
|
|
|
9204
10011
|
}
|
|
9205
10012
|
const workDir = await tmpRunDir("build");
|
|
9206
10013
|
try {
|
|
9207
|
-
const configPath =
|
|
10014
|
+
const configPath = path22.join(workDir, "flow.json");
|
|
9208
10015
|
if (manifest.flowConfig) {
|
|
9209
10016
|
try {
|
|
9210
|
-
await
|
|
10017
|
+
await fs22.writeJson(configPath, manifest.flowConfig);
|
|
9211
10018
|
const loaded = loadBundleConfig(manifest.flowConfig, {
|
|
9212
10019
|
configPath,
|
|
9213
10020
|
flowName: manifest.flowName,
|
|
@@ -9231,15 +10038,17 @@ async function runBuildManifest(source) {
|
|
|
9231
10038
|
artifact,
|
|
9232
10039
|
workDir,
|
|
9233
10040
|
index,
|
|
9234
|
-
outputs
|
|
10041
|
+
outputs,
|
|
10042
|
+
retry
|
|
9235
10043
|
);
|
|
9236
10044
|
outputs.set(artifact.outputName, output);
|
|
9237
|
-
const content = await
|
|
10045
|
+
const content = await fs22.readFile(output);
|
|
9238
10046
|
await put(
|
|
9239
10047
|
artifact.putUrl,
|
|
9240
10048
|
content,
|
|
9241
10049
|
artifact.contentType ?? contentTypeFor(artifact.outputName),
|
|
9242
|
-
artifact.headers
|
|
10050
|
+
artifact.headers ?? {},
|
|
10051
|
+
retry
|
|
9243
10052
|
);
|
|
9244
10053
|
result.artifacts.push({
|
|
9245
10054
|
target: artifact.target,
|
|
@@ -9262,13 +10071,13 @@ async function runBuildManifest(source) {
|
|
|
9262
10071
|
result.ok = true;
|
|
9263
10072
|
return { result, reported: await report(manifest.resultPutUrl, result) };
|
|
9264
10073
|
} finally {
|
|
9265
|
-
await
|
|
10074
|
+
await fs22.remove(workDir).catch(() => {
|
|
9266
10075
|
});
|
|
9267
10076
|
}
|
|
9268
10077
|
}
|
|
9269
|
-
async function
|
|
10078
|
+
async function reportResult(url, result, retry) {
|
|
9270
10079
|
try {
|
|
9271
|
-
await put(url, JSON.stringify(result), "application/json");
|
|
10080
|
+
await put(url, JSON.stringify(result), "application/json", {}, retry);
|
|
9272
10081
|
return true;
|
|
9273
10082
|
} catch {
|
|
9274
10083
|
return false;
|
|
@@ -9476,7 +10285,7 @@ async function endObserveSession(options) {
|
|
|
9476
10285
|
}
|
|
9477
10286
|
|
|
9478
10287
|
// src/commands/hub/index.ts
|
|
9479
|
-
async function
|
|
10288
|
+
async function readJson3(response, fallback) {
|
|
9480
10289
|
if (!response.ok) {
|
|
9481
10290
|
const body = await response.json().catch(() => ({}));
|
|
9482
10291
|
throwApiResponseError(response, body, fallback);
|
|
@@ -9492,7 +10301,7 @@ async function listReleases(options) {
|
|
|
9492
10301
|
const response = await apiFetch(
|
|
9493
10302
|
`/api/projects/${pid}/flows/${options.flowId}/releases?${params.toString()}`
|
|
9494
10303
|
);
|
|
9495
|
-
return
|
|
10304
|
+
return readJson3(response, "Failed to list releases");
|
|
9496
10305
|
}
|
|
9497
10306
|
async function getRelease(options) {
|
|
9498
10307
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9500,7 +10309,7 @@ async function getRelease(options) {
|
|
|
9500
10309
|
const response = await apiFetch(
|
|
9501
10310
|
`/api/projects/${pid}/flows/${options.flowId}/releases/${encodeURIComponent(segment)}`
|
|
9502
10311
|
);
|
|
9503
|
-
return
|
|
10312
|
+
return readJson3(response, "Failed to read release");
|
|
9504
10313
|
}
|
|
9505
10314
|
async function listStepHistory(options) {
|
|
9506
10315
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9510,7 +10319,7 @@ async function listStepHistory(options) {
|
|
|
9510
10319
|
const response = await apiFetch(
|
|
9511
10320
|
`/api/projects/${pid}/flows/${options.flowId}/releases/step-history?${params.toString()}`
|
|
9512
10321
|
);
|
|
9513
|
-
return
|
|
10322
|
+
return readJson3(response, "Failed to read step history");
|
|
9514
10323
|
}
|
|
9515
10324
|
async function setReleaseRationale(options) {
|
|
9516
10325
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9525,7 +10334,7 @@ async function setReleaseRationale(options) {
|
|
|
9525
10334
|
})
|
|
9526
10335
|
}
|
|
9527
10336
|
);
|
|
9528
|
-
return
|
|
10337
|
+
return readJson3(response, "Failed to write release rationale");
|
|
9529
10338
|
}
|
|
9530
10339
|
async function listThreads(options) {
|
|
9531
10340
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9540,7 +10349,7 @@ async function listThreads(options) {
|
|
|
9540
10349
|
const response = await apiFetch(
|
|
9541
10350
|
`/api/projects/${pid}/flows/${options.flowId}/threads?${params.toString()}`
|
|
9542
10351
|
);
|
|
9543
|
-
return
|
|
10352
|
+
return readJson3(response, "Failed to list threads");
|
|
9544
10353
|
}
|
|
9545
10354
|
async function createThread(options) {
|
|
9546
10355
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9557,7 +10366,7 @@ async function createThread(options) {
|
|
|
9557
10366
|
})
|
|
9558
10367
|
}
|
|
9559
10368
|
);
|
|
9560
|
-
return
|
|
10369
|
+
return readJson3(response, "Failed to open thread");
|
|
9561
10370
|
}
|
|
9562
10371
|
async function addThreadMessage(options) {
|
|
9563
10372
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9569,7 +10378,7 @@ async function addThreadMessage(options) {
|
|
|
9569
10378
|
body: JSON.stringify({ text: options.text })
|
|
9570
10379
|
}
|
|
9571
10380
|
);
|
|
9572
|
-
return
|
|
10381
|
+
return readJson3(response, "Failed to add message");
|
|
9573
10382
|
}
|
|
9574
10383
|
async function listKnowledge(options) {
|
|
9575
10384
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9582,11 +10391,11 @@ async function listKnowledge(options) {
|
|
|
9582
10391
|
const response = await apiFetch(
|
|
9583
10392
|
`/api/projects/${pid}/knowledge?${params.toString()}`
|
|
9584
10393
|
);
|
|
9585
|
-
return
|
|
10394
|
+
return readJson3(response, "Failed to read knowledge");
|
|
9586
10395
|
}
|
|
9587
10396
|
|
|
9588
10397
|
// src/commands/frames/index.ts
|
|
9589
|
-
async function
|
|
10398
|
+
async function readJson4(response, fallback) {
|
|
9590
10399
|
if (!response.ok) {
|
|
9591
10400
|
const body = await response.json().catch(() => ({}));
|
|
9592
10401
|
throwApiResponseError(response, body, fallback);
|
|
@@ -9596,7 +10405,7 @@ async function readJson3(response, fallback) {
|
|
|
9596
10405
|
async function listFrames(options = {}) {
|
|
9597
10406
|
const pid = options.projectId ?? requireProjectId();
|
|
9598
10407
|
const response = await apiFetch(`/api/projects/${pid}/frames`);
|
|
9599
|
-
return
|
|
10408
|
+
return readJson4(response, "Failed to list frames");
|
|
9600
10409
|
}
|
|
9601
10410
|
async function listPageFrames(options) {
|
|
9602
10411
|
const pid = options.projectId ?? requireProjectId();
|
|
@@ -9604,14 +10413,14 @@ async function listPageFrames(options) {
|
|
|
9604
10413
|
const response = await apiFetch(
|
|
9605
10414
|
`/api/projects/${pid}/frames?${params.toString()}`
|
|
9606
10415
|
);
|
|
9607
|
-
return
|
|
10416
|
+
return readJson4(response, "Failed to list page frames");
|
|
9608
10417
|
}
|
|
9609
10418
|
async function getFrame(options) {
|
|
9610
10419
|
const pid = options.projectId ?? requireProjectId();
|
|
9611
10420
|
const response = await apiFetch(
|
|
9612
10421
|
`/api/projects/${pid}/frames/${encodeURIComponent(options.frameId)}`
|
|
9613
10422
|
);
|
|
9614
|
-
return
|
|
10423
|
+
return readJson4(response, "Failed to read frame");
|
|
9615
10424
|
}
|
|
9616
10425
|
|
|
9617
10426
|
// src/commands/secrets/index.ts
|
|
@@ -9881,6 +10690,7 @@ export {
|
|
|
9881
10690
|
BuildWrapArtifactSchema,
|
|
9882
10691
|
BuildWrapOptionsSchema,
|
|
9883
10692
|
DeploymentAmbiguityError,
|
|
10693
|
+
VALIDATE_CODES,
|
|
9884
10694
|
VERSION,
|
|
9885
10695
|
addThreadMessage,
|
|
9886
10696
|
annotateErrorWithDrift,
|
|
@@ -9968,7 +10778,6 @@ export {
|
|
|
9968
10778
|
loginCommand,
|
|
9969
10779
|
logout,
|
|
9970
10780
|
logoutCommand,
|
|
9971
|
-
maskKnownNumbers,
|
|
9972
10781
|
mergeAuthHeaders,
|
|
9973
10782
|
parseSSEEvents,
|
|
9974
10783
|
publicFetch,
|
|
@@ -10007,7 +10816,7 @@ export {
|
|
|
10007
10816
|
updateSecret,
|
|
10008
10817
|
validate,
|
|
10009
10818
|
validateCommand,
|
|
10010
|
-
validateFlowStructure,
|
|
10819
|
+
validateFlowStructure2 as validateFlowStructure,
|
|
10011
10820
|
whoami,
|
|
10012
10821
|
whoamiCommand,
|
|
10013
10822
|
wrapSkeleton,
|