@rakay-technology/kraft 0.7.9 → 0.7.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bare-5S7IYNHZ.js +27 -0
- package/dist/{chunk-VFPLICBX.js → chunk-3AZY56JP.js} +107 -32
- package/dist/{chunk-IGTODKUA.js → chunk-5RWL7EFH.js} +5 -5
- package/dist/{chunk-ZQJU5CTZ.js → chunk-7VMXN646.js} +1 -1
- package/dist/{chunk-DJNKEVZ7.js → chunk-AADWLI2S.js} +1 -1
- package/dist/{chunk-MOSINQAM.js → chunk-AFUXAAFQ.js} +16 -388
- package/dist/{chunk-2UQFOUSZ.js → chunk-B2CUYCGY.js} +49 -16
- package/dist/{chunk-7O6MARHJ.js → chunk-B6B42QMZ.js} +9 -9
- package/dist/{chunk-HFOE2IXZ.js → chunk-BIOW6K3V.js} +1 -1
- package/dist/{chunk-YY5DEAZI.js → chunk-BQMBJ32I.js} +2 -2
- package/dist/{chunk-ULEEWX5M.js → chunk-C3LRTROB.js} +39 -8
- package/dist/{chunk-DFVWR6JM.js → chunk-C74WJ3U4.js} +2 -2
- package/dist/{chunk-K24SBFI2.js → chunk-D2IM25JV.js} +1 -1
- package/dist/{chunk-MC4X55BW.js → chunk-DNC4A3MZ.js} +3 -3
- package/dist/{chunk-3RCXJZJD.js → chunk-E3J47WO3.js} +1 -1
- package/dist/chunk-G4VGNFGV.js +27374 -0
- package/dist/{chunk-JK7KKBXI.js → chunk-KHAT3OZP.js} +4 -4
- package/dist/{chunk-7UKBMDUF.js → chunk-MK6GYBO4.js} +9 -9
- package/dist/{chunk-SPKRI7MF.js → chunk-N7AJ2D4I.js} +96 -12
- package/dist/{chunk-ZNVAHQRY.js → chunk-Q7FAE2MB.js} +6 -6
- package/dist/{chunk-2Y62WP2D.js → chunk-QCGVPIYN.js} +2 -2
- package/dist/{chunk-PCOTSRS4.js → chunk-QLPQ5NFE.js} +3 -3
- package/dist/{chunk-DI54Y66N.js → chunk-QPUEAYB3.js} +3 -3
- package/dist/{chunk-XBGSR22I.js → chunk-XAEYWDBX.js} +53 -9
- package/dist/{chunk-HLF5PMKE.js → chunk-Y2MET6MX.js} +1 -1
- package/dist/{chunk-BN23UUSF.js → chunk-YXXWTBXB.js} +1 -1
- package/dist/{detect-N4HFQZ6Y.js → detect-NDVA2MAF.js} +4 -4
- package/dist/{docker-DU7JA2AK.js → docker-Z2ILAC7A.js} +8 -8
- package/dist/{docker-edge-executor-MPIPQHNF.js → docker-edge-executor-JID2Q2HZ.js} +7 -7
- package/dist/{edge-import-RZD7MMOE.js → edge-import-WRU5JQ43.js} +22 -22
- package/dist/{edge-preflight-6YO27PPQ.js → edge-preflight-6FYNGFIH.js} +13 -13
- package/dist/{ensure-container-edge-ZKEKC47H.js → ensure-container-edge-VFCVCXW3.js} +11 -11
- package/dist/{executor-ZWF2J7GS.js → executor-LNKX5OMQ.js} +6 -6
- package/dist/{host-channel-preflight-Z64G3NIM.js → host-channel-preflight-V7Q6GPXE.js} +22 -22
- package/dist/index.js +40 -40
- package/dist/{local-executor-W3O5HDLM.js → local-executor-NPLQMF6A.js} +3 -3
- package/dist/{nginx-XLDZIG4E.js → nginx-V6DQWKON.js} +11 -9
- package/dist/{openresty-lua-ZNE6IBYU.js → openresty-lua-OECMHHON.js} +21 -7
- package/dist/{privilege-IMARWVU2.js → privilege-KI56M7OQ.js} +5 -5
- package/dist/server/index.js +1897 -58664
- package/dist/{setup-Q6GGIJ4Q.js → setup-A2LJ4IWU.js} +12 -12
- package/dist/{ssh-client-LOCZTEUC.js → ssh-client-NRBHQJVZ.js} +2 -2
- package/dist/{up-TU7622HW.js → up-XHQK2O2M.js} +25 -25
- package/package.json +1 -1
- package/dist/bare-JM3EX7S4.js +0 -27
- package/dist/chunk-ND23EK7Y.js +0 -81645
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
":" //# ; exec "$(command -v node || command -v bun)" "$0" "$@"
|
|
3
|
+
import { createRequire as __ospCreateRequire } from "node:module";
|
|
4
|
+
const require = __ospCreateRequire(import.meta.url);
|
|
5
|
+
import {
|
|
6
|
+
BareRuntime,
|
|
7
|
+
STATIC_RELEASE_BASE
|
|
8
|
+
} from "./chunk-MK6GYBO4.js";
|
|
9
|
+
import "./chunk-C74WJ3U4.js";
|
|
10
|
+
import "./chunk-N7AJ2D4I.js";
|
|
11
|
+
import "./chunk-ZVFS4LUA.js";
|
|
12
|
+
import "./chunk-D2IM25JV.js";
|
|
13
|
+
import "./chunk-AADWLI2S.js";
|
|
14
|
+
import "./chunk-BIOW6K3V.js";
|
|
15
|
+
import "./chunk-QPUEAYB3.js";
|
|
16
|
+
import "./chunk-QCGVPIYN.js";
|
|
17
|
+
import "./chunk-E3J47WO3.js";
|
|
18
|
+
import "./chunk-7VMXN646.js";
|
|
19
|
+
import "./chunk-BQMBJ32I.js";
|
|
20
|
+
import "./chunk-3CJLKL6E.js";
|
|
21
|
+
import "./chunk-YXXWTBXB.js";
|
|
22
|
+
import "./chunk-G4VGNFGV.js";
|
|
23
|
+
import "./chunk-PXKCZB2I.js";
|
|
24
|
+
export {
|
|
25
|
+
BareRuntime,
|
|
26
|
+
STATIC_RELEASE_BASE
|
|
27
|
+
};
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-I3DPMTSF.js";
|
|
10
10
|
import {
|
|
11
11
|
edgeFailureReason
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QLPQ5NFE.js";
|
|
13
13
|
import {
|
|
14
14
|
probeHostedHttp
|
|
15
15
|
} from "./chunk-ZVFS4LUA.js";
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
EDGE_CHALLENGE_DIR,
|
|
20
20
|
EDGE_CHALLENGE_LOCATION,
|
|
21
21
|
EDGE_CHALLENGE_URL_PREFIX,
|
|
22
|
+
EDGE_LISTEN_443,
|
|
23
|
+
EDGE_LISTEN_80,
|
|
22
24
|
EDGE_SAME_PATH_MOUNTS,
|
|
23
25
|
LUA_LOGGER_PATH,
|
|
24
26
|
OPENRESTY_DEFAULT_PATHS,
|
|
@@ -30,25 +32,26 @@ import {
|
|
|
30
32
|
isCloudFrontedHost,
|
|
31
33
|
luaSourceAvailable,
|
|
32
34
|
reloadBareOpenResty
|
|
33
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-XAEYWDBX.js";
|
|
34
36
|
import {
|
|
35
37
|
probeListeningPort
|
|
36
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-QCGVPIYN.js";
|
|
37
39
|
import {
|
|
38
40
|
EXECUTOR_DELEGATE
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-BQMBJ32I.js";
|
|
40
42
|
import {
|
|
41
43
|
logEntry,
|
|
42
44
|
sq
|
|
43
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-YXXWTBXB.js";
|
|
44
46
|
import {
|
|
45
47
|
PROXY_DIRECTIVES,
|
|
46
48
|
parseProxyValue,
|
|
49
|
+
renderHstsValue,
|
|
47
50
|
resolveProxyDirectives,
|
|
48
51
|
resolveRedirectStatus,
|
|
49
52
|
safeErrorMessage,
|
|
50
53
|
sanitizeProxySettings
|
|
51
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-G4VGNFGV.js";
|
|
52
55
|
|
|
53
56
|
// ../../packages/adapters/src/infra/nginx.ts
|
|
54
57
|
import {
|
|
@@ -386,6 +389,7 @@ var PROXY_HEADERS = `proxy_set_header Host $host;
|
|
|
386
389
|
proxy_set_header X-Real-IP $remote_addr;
|
|
387
390
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
388
391
|
proxy_set_header X-Forwarded-Proto $kraft_fwd_proto;
|
|
392
|
+
proxy_set_header X-Request-ID $request_id;
|
|
389
393
|
proxy_http_version 1.1;
|
|
390
394
|
proxy_set_header Upgrade $http_upgrade;
|
|
391
395
|
proxy_set_header Connection "upgrade";
|
|
@@ -396,7 +400,7 @@ var FORWARD_VARS = ` set $kraft_fwd_proto $scheme;
|
|
|
396
400
|
set $kraft_fwd_proto https;
|
|
397
401
|
set $kraft_redirect_https 0;
|
|
398
402
|
}`;
|
|
399
|
-
var VHOST_GENERATION =
|
|
403
|
+
var VHOST_GENERATION = 3;
|
|
400
404
|
var GENERATION_MARKER = `# kraft-vhost-gen: ${VHOST_GENERATION}`;
|
|
401
405
|
var GENERATED_HEADER = `# Auto-generated by Kraft - do not edit manually
|
|
402
406
|
${GENERATION_MARKER}`;
|
|
@@ -584,6 +588,12 @@ function renderProxyOptions(proxy, nginxVersion) {
|
|
|
584
588
|
function renderProxyTlsOptions(proxy, nginxVersion) {
|
|
585
589
|
return renderProxyDirectives(proxy, { tlsOnly: true, nginxVersion });
|
|
586
590
|
}
|
|
591
|
+
function renderHstsHeader(route, opts) {
|
|
592
|
+
if (!opts.realTls || !route.hsts) return "";
|
|
593
|
+
const value = renderHstsValue(route.hsts);
|
|
594
|
+
if (!value) return "";
|
|
595
|
+
return ` add_header Strict-Transport-Security "${value}" always;`;
|
|
596
|
+
}
|
|
587
597
|
function renderGeoEntries(whitelist) {
|
|
588
598
|
const entries = [
|
|
589
599
|
" default 0;",
|
|
@@ -1228,6 +1238,77 @@ eab-hmac-key = ${this.acmeEabHmacKey}
|
|
|
1228
1238
|
async registerRoute(route) {
|
|
1229
1239
|
assertValidDomain(route.domain);
|
|
1230
1240
|
await this._mkdir(this.sitesDir);
|
|
1241
|
+
await this.applyVhostBatch([await this.renderVhost(route)]);
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Register MANY routes with ONE config test + ONE reload (C5).
|
|
1245
|
+
*
|
|
1246
|
+
* `registerRoute` costs a whole-config `openresty -t` + a reload PER route,
|
|
1247
|
+
* so a multi-domain deploy (or a VHOST_GENERATION bump) paid N tests + N
|
|
1248
|
+
* serial reloads per box. This renders every vhost first — a validation throw
|
|
1249
|
+
* aborts before anything is written — then writes all files and reloads once.
|
|
1250
|
+
* A failed reload restores every file (same self-rollback as the single
|
|
1251
|
+
* route) and reloads once more, so the box never keeps a half-applied set.
|
|
1252
|
+
*
|
|
1253
|
+
* Isolation trade-off, stated plainly: one unrenderable-among-many cannot
|
|
1254
|
+
* happen (rendering precedes all writes and throws first), but one
|
|
1255
|
+
* reload-failing set rolls back the whole set. Callers that need
|
|
1256
|
+
* per-route isolation (a sweep over unrelated projects) keep calling
|
|
1257
|
+
* `registerRoute`; callers that register one deployment's domains together
|
|
1258
|
+
* use this and fall back per-route on failure.
|
|
1259
|
+
*/
|
|
1260
|
+
async registerRoutes(routes) {
|
|
1261
|
+
if (routes.length === 0) return;
|
|
1262
|
+
if (routes.length === 1) {
|
|
1263
|
+
await this.registerRoute(routes[0]);
|
|
1264
|
+
return;
|
|
1265
|
+
}
|
|
1266
|
+
for (const route of routes) assertValidDomain(route.domain);
|
|
1267
|
+
await this._mkdir(this.sitesDir);
|
|
1268
|
+
const rendered = [];
|
|
1269
|
+
for (const route of routes) rendered.push(await this.renderVhost(route));
|
|
1270
|
+
await this.applyVhostBatch(rendered);
|
|
1271
|
+
}
|
|
1272
|
+
/** A vhost rendered to memory: what to write where, and whether the emitted
|
|
1273
|
+
* conf references its bootstrap placeholder (which decides the cleanup). */
|
|
1274
|
+
async applyVhostBatch(rendered) {
|
|
1275
|
+
const snapshots = /* @__PURE__ */ new Map();
|
|
1276
|
+
for (const r of rendered) {
|
|
1277
|
+
if (!snapshots.has(r.configPath)) {
|
|
1278
|
+
snapshots.set(r.configPath, await this._captureFile(r.configPath));
|
|
1279
|
+
}
|
|
1280
|
+
await this._writeFile(r.configPath, r.conf);
|
|
1281
|
+
}
|
|
1282
|
+
try {
|
|
1283
|
+
await this.reload();
|
|
1284
|
+
} catch (err) {
|
|
1285
|
+
for (const r of rendered) {
|
|
1286
|
+
await this._restoreFile(r.configPath, snapshots.get(r.configPath));
|
|
1287
|
+
}
|
|
1288
|
+
await this.reload().catch(() => void 0);
|
|
1289
|
+
throw err;
|
|
1290
|
+
}
|
|
1291
|
+
for (const r of rendered) {
|
|
1292
|
+
if (!r.bootstrapServed) {
|
|
1293
|
+
await this._rm(this.bootstrapCertDir(r.route.domain)).catch(
|
|
1294
|
+
() => void 0
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
await this._writeFile(
|
|
1298
|
+
this.routeStatePath(r.slug),
|
|
1299
|
+
JSON.stringify(r.route)
|
|
1300
|
+
).catch(() => void 0);
|
|
1301
|
+
}
|
|
1302
|
+
}
|
|
1303
|
+
/**
|
|
1304
|
+
* Render a route to its vhost file content WITHOUT writing or reloading.
|
|
1305
|
+
*
|
|
1306
|
+
* Pure render (plus the cert-exists/bootstrap-cert reads that decide which
|
|
1307
|
+
* shape to emit). `registerRoute` / `registerRoutes` share it, so the batch
|
|
1308
|
+
* path cannot drift from the single path — one renderer, two writers.
|
|
1309
|
+
*/
|
|
1310
|
+
async renderVhost(route) {
|
|
1311
|
+
assertValidDomain(route.domain);
|
|
1231
1312
|
const slug = await this.resolveSlug(route.domain);
|
|
1232
1313
|
const configPath = join(this.sitesDir, `${slug}.conf`);
|
|
1233
1314
|
if ("staticRoot" in route && route.staticRoot) {
|
|
@@ -1237,6 +1318,7 @@ eab-hmac-key = ${this.acmeEabHmacKey}
|
|
|
1237
1318
|
} else {
|
|
1238
1319
|
assertValidUpstream(route.targetUrl);
|
|
1239
1320
|
}
|
|
1321
|
+
if (route.webhookProxy) assertValidUpstream(route.webhookProxy);
|
|
1240
1322
|
const hostRedirect = renderHostRedirect(route);
|
|
1241
1323
|
const locationBody = hostRedirect ? hostRedirect : "staticRoot" in route && route.staticRoot ? `root ${route.staticRoot};
|
|
1242
1324
|
index index.html;
|
|
@@ -1259,6 +1341,7 @@ ${FORWARD_VARS}` : FORWARD_VARS;
|
|
|
1259
1341
|
proxy_set_header X-Real-IP $remote_addr;
|
|
1260
1342
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
1261
1343
|
proxy_set_header X-Forwarded-Proto $kraft_fwd_proto;
|
|
1344
|
+
proxy_set_header X-Request-ID $request_id;
|
|
1262
1345
|
}
|
|
1263
1346
|
` : "";
|
|
1264
1347
|
const edgeLua = luaSourceAvailable();
|
|
@@ -1277,9 +1360,12 @@ ${renderSlashFallback(route.staticRoot)}` : "";
|
|
|
1277
1360
|
${webhookLocation}${extraLocations}`;
|
|
1278
1361
|
const httpsUpgradeBody = `${serverHeaders}${proxyOpts}
|
|
1279
1362
|
${webhookLocation}${upgradingExtraLocations}`;
|
|
1363
|
+
const hstsHeader = renderHstsHeader(route, { realTls: true });
|
|
1364
|
+
const sharedBodyTls = hstsHeader ? `${sharedBody}
|
|
1365
|
+
${hstsHeader}` : sharedBody;
|
|
1280
1366
|
const httpOnlyBlock = `${GENERATED_HEADER}
|
|
1281
1367
|
server {
|
|
1282
|
-
|
|
1368
|
+
${EDGE_LISTEN_80}
|
|
1283
1369
|
server_name ${route.domain};
|
|
1284
1370
|
|
|
1285
1371
|
${preamble}
|
|
@@ -1300,7 +1386,7 @@ ${serveLocation}
|
|
|
1300
1386
|
const keyPath = join(this.certDir, route.domain, "privkey.pem");
|
|
1301
1387
|
serverBlock = `${GENERATED_HEADER}
|
|
1302
1388
|
server {
|
|
1303
|
-
|
|
1389
|
+
${EDGE_LISTEN_80}
|
|
1304
1390
|
server_name ${route.domain};
|
|
1305
1391
|
|
|
1306
1392
|
${preamble}
|
|
@@ -1315,7 +1401,7 @@ ${redirectOrServeLocation}
|
|
|
1315
1401
|
}
|
|
1316
1402
|
|
|
1317
1403
|
server {
|
|
1318
|
-
|
|
1404
|
+
${EDGE_LISTEN_443}
|
|
1319
1405
|
server_name ${route.domain};
|
|
1320
1406
|
|
|
1321
1407
|
${preamble}
|
|
@@ -1324,7 +1410,7 @@ ${luaProxy}
|
|
|
1324
1410
|
|
|
1325
1411
|
ssl_certificate ${certPath};
|
|
1326
1412
|
ssl_certificate_key ${keyPath};${proxyTlsOpts}
|
|
1327
|
-
${
|
|
1413
|
+
${sharedBodyTls}
|
|
1328
1414
|
${serveLocation}
|
|
1329
1415
|
}
|
|
1330
1416
|
`;
|
|
@@ -1336,7 +1422,7 @@ ${serveLocation}
|
|
|
1336
1422
|
# certificate because its real certificate has not been issued yet. Kraft
|
|
1337
1423
|
# replaces this file automatically once it lands. Do not adopt this material.
|
|
1338
1424
|
server {
|
|
1339
|
-
|
|
1425
|
+
${EDGE_LISTEN_80}
|
|
1340
1426
|
server_name ${route.domain};
|
|
1341
1427
|
|
|
1342
1428
|
${preamble}
|
|
@@ -1351,7 +1437,7 @@ ${serveLocation}
|
|
|
1351
1437
|
}
|
|
1352
1438
|
|
|
1353
1439
|
server {
|
|
1354
|
-
|
|
1440
|
+
${EDGE_LISTEN_443}
|
|
1355
1441
|
server_name ${route.domain};
|
|
1356
1442
|
|
|
1357
1443
|
${preamble}
|
|
@@ -1367,24 +1453,13 @@ ${serveLocation}
|
|
|
1367
1453
|
} else {
|
|
1368
1454
|
serverBlock = httpOnlyBlock;
|
|
1369
1455
|
}
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
throw err;
|
|
1378
|
-
}
|
|
1379
|
-
if (!bootstrapServed) {
|
|
1380
|
-
await this._rm(this.bootstrapCertDir(route.domain)).catch(
|
|
1381
|
-
() => void 0
|
|
1382
|
-
);
|
|
1383
|
-
}
|
|
1384
|
-
await this._writeFile(
|
|
1385
|
-
this.routeStatePath(slug),
|
|
1386
|
-
JSON.stringify(route)
|
|
1387
|
-
).catch(() => void 0);
|
|
1456
|
+
return {
|
|
1457
|
+
route,
|
|
1458
|
+
slug,
|
|
1459
|
+
configPath,
|
|
1460
|
+
conf: `${prelude}${serverBlock}`,
|
|
1461
|
+
bootstrapServed
|
|
1462
|
+
};
|
|
1388
1463
|
}
|
|
1389
1464
|
routeStatePath(slug) {
|
|
1390
1465
|
return join(this.sitesDir, `${slug}.route.json`);
|
|
@@ -2259,12 +2334,12 @@ export {
|
|
|
2259
2334
|
readMaybeInContainer,
|
|
2260
2335
|
edgeContainerExecutor,
|
|
2261
2336
|
validateCertFor,
|
|
2262
|
-
isSafeCertPath,
|
|
2263
2337
|
readDeclaredPair,
|
|
2264
2338
|
VHOST_GENERATION,
|
|
2265
2339
|
readVhostGeneration,
|
|
2266
2340
|
renderProxyOptions,
|
|
2267
2341
|
renderProxyTlsOptions,
|
|
2342
|
+
renderHstsHeader,
|
|
2268
2343
|
renderGeoEntries,
|
|
2269
2344
|
acmeKeyArgs,
|
|
2270
2345
|
assertValidChallengeToken,
|
|
@@ -19,16 +19,16 @@ import {
|
|
|
19
19
|
rollbackEdgeTakeover,
|
|
20
20
|
scanImportableSites,
|
|
21
21
|
unreachableStaticRoots
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-AFUXAAFQ.js";
|
|
23
23
|
import {
|
|
24
24
|
ourEdgeContainerRunning
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-QLPQ5NFE.js";
|
|
26
26
|
import {
|
|
27
27
|
LocalExecutor
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-BIOW6K3V.js";
|
|
29
29
|
import {
|
|
30
30
|
isOurEdgeContainer
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-E3J47WO3.js";
|
|
32
32
|
|
|
33
33
|
// src/lib/edge-preflight.ts
|
|
34
34
|
import { spawnSync } from "child_process";
|
|
@@ -263,7 +263,7 @@ async function repairEdgeConflict(mode, apiPort, onLog) {
|
|
|
263
263
|
}
|
|
264
264
|
spawnSync("docker", ["restart", "kraft-edge"], { stdio: "ignore" });
|
|
265
265
|
if (mode === "migrate" && scan.sites.length > 0) {
|
|
266
|
-
const { importMigratedSites } = await import("./edge-import-
|
|
266
|
+
const { importMigratedSites } = await import("./edge-import-WRU5JQ43.js");
|
|
267
267
|
const outcome = await importMigratedSites(apiPort, scan.sites, certPems);
|
|
268
268
|
if (outcome.registered.length === 0) {
|
|
269
269
|
return {
|