@walkeros/cli 4.8.1 → 4.8.3-next-1793115089237
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 +115 -3
- package/README.md +2 -2
- package/dist/cli.js +4149 -4149
- package/dist/dev.d.ts +51 -3
- package/dist/dev.js +186 -0
- package/dist/dev.js.map +1 -1
- package/dist/examples/README.md +12 -1
- package/dist/examples/contracts/app.json +261 -0
- package/dist/examples/contracts/base.json +708 -0
- package/dist/examples/contracts/ecommerce.json +963 -0
- package/dist/examples/contracts/leadgen.json +240 -0
- package/dist/examples/contracts/publisher.json +372 -0
- package/dist/examples/contracts/saas.json +229 -0
- package/dist/examples/contracts/travel.json +234 -0
- package/dist/examples/customers/README.md +4 -1
- package/dist/examples/event.json +1 -1
- package/dist/examples/flow-complete.json +107 -130
- package/dist/examples/flow-complete.md +12 -10
- package/dist/examples/flow-order-complete.json +1 -1
- package/dist/examples/flow.json +1 -1
- package/dist/examples/index.d.ts +34 -4
- package/dist/examples/index.js +128 -139
- package/dist/examples/index.js.map +1 -1
- package/dist/examples/shared/README.md +4 -0
- package/dist/index.d.ts +63 -223
- package/dist/index.js +572 -992
- package/dist/index.js.map +1 -1
- package/dist/validate.d.ts +1 -1
- package/dist/validate.js +337 -204
- package/dist/validate.js.map +1 -1
- package/examples/README.md +12 -1
- package/examples/contracts/app.json +261 -0
- package/examples/contracts/base.json +708 -0
- package/examples/contracts/ecommerce.json +963 -0
- package/examples/contracts/leadgen.json +240 -0
- package/examples/contracts/publisher.json +372 -0
- package/examples/contracts/saas.json +229 -0
- package/examples/contracts/travel.json +234 -0
- package/examples/customers/README.md +4 -1
- package/examples/event.json +1 -1
- package/examples/flow-complete.json +107 -130
- package/examples/flow-complete.md +12 -10
- package/examples/flow-order-complete.json +1 -1
- package/examples/flow.json +1 -1
- package/examples/shared/README.md +4 -0
- package/package.json +30 -30
- package/src/telemetry/flow.json +42 -34
- package/dist/examples/test.html +0 -43
- package/dist/examples/web-serve.js +0 -25503
- package/examples/test.html +0 -43
- package/examples/web-serve.js +0 -25503
package/dist/index.js
CHANGED
|
@@ -350,479 +350,10 @@ async function readStdinToTempFile(label) {
|
|
|
350
350
|
return tmpPath;
|
|
351
351
|
}
|
|
352
352
|
|
|
353
|
-
// src/lib/config-file.ts
|
|
354
|
-
import {
|
|
355
|
-
readFileSync,
|
|
356
|
-
writeFileSync,
|
|
357
|
-
mkdirSync,
|
|
358
|
-
unlinkSync,
|
|
359
|
-
existsSync,
|
|
360
|
-
chmodSync,
|
|
361
|
-
renameSync
|
|
362
|
-
} from "fs";
|
|
363
|
-
import { randomBytes } from "crypto";
|
|
364
|
-
import { join } from "path";
|
|
365
|
-
import { homedir } from "os";
|
|
366
|
-
function getConfigDir() {
|
|
367
|
-
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
368
|
-
const base = xdgConfig || join(homedir(), ".config");
|
|
369
|
-
return join(base, "walkeros");
|
|
370
|
-
}
|
|
371
|
-
function getConfigPath() {
|
|
372
|
-
return join(getConfigDir(), "config.json");
|
|
373
|
-
}
|
|
374
|
-
function readConfig() {
|
|
375
|
-
const configPath = getConfigPath();
|
|
376
|
-
try {
|
|
377
|
-
const content = readFileSync(configPath, "utf-8");
|
|
378
|
-
return JSON.parse(content);
|
|
379
|
-
} catch {
|
|
380
|
-
return null;
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
function replaceConfigFile(config) {
|
|
384
|
-
const dir = getConfigDir();
|
|
385
|
-
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
386
|
-
const configPath = getConfigPath();
|
|
387
|
-
const tempPath = `${configPath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
388
|
-
try {
|
|
389
|
-
writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
390
|
-
chmodSync(tempPath, 384);
|
|
391
|
-
renameSync(tempPath, configPath);
|
|
392
|
-
} catch (error) {
|
|
393
|
-
try {
|
|
394
|
-
unlinkSync(tempPath);
|
|
395
|
-
} catch {
|
|
396
|
-
}
|
|
397
|
-
throw error;
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
function writeConfig(config) {
|
|
401
|
-
replaceConfigFile({ ...readConfig() ?? {}, ...config });
|
|
402
|
-
}
|
|
403
|
-
function clearAuthFields() {
|
|
404
|
-
const config = readConfig();
|
|
405
|
-
if (!config) return;
|
|
406
|
-
const {
|
|
407
|
-
token: _token,
|
|
408
|
-
accessToken: _accessToken,
|
|
409
|
-
accessTokenExpiresAt: _accessTokenExpiresAt,
|
|
410
|
-
refreshToken: _refreshToken,
|
|
411
|
-
email: _email,
|
|
412
|
-
...rest
|
|
413
|
-
} = config;
|
|
414
|
-
replaceConfigFile(rest);
|
|
415
|
-
}
|
|
416
|
-
function writeTelemetryOnlyConfig(partial) {
|
|
417
|
-
writeConfig(partial);
|
|
418
|
-
}
|
|
419
|
-
function deleteConfig() {
|
|
420
|
-
const configPath = getConfigPath();
|
|
421
|
-
if (existsSync(configPath)) {
|
|
422
|
-
unlinkSync(configPath);
|
|
423
|
-
return true;
|
|
424
|
-
}
|
|
425
|
-
return false;
|
|
426
|
-
}
|
|
427
|
-
function hasStoredCredential(config) {
|
|
428
|
-
return Boolean(config?.token || config?.accessToken);
|
|
429
|
-
}
|
|
430
|
-
function resolveToken() {
|
|
431
|
-
const envToken = process.env.WALKEROS_TOKEN;
|
|
432
|
-
if (envToken) return { token: envToken, source: "env" };
|
|
433
|
-
const config = readConfig();
|
|
434
|
-
if (config?.token) return { token: config.token, source: "config" };
|
|
435
|
-
return null;
|
|
436
|
-
}
|
|
437
|
-
function resolveAppUrl() {
|
|
438
|
-
const envUrl = process.env.WALKEROS_APP_URL;
|
|
439
|
-
if (envUrl) return envUrl;
|
|
440
|
-
const config = readConfig();
|
|
441
|
-
if (config?.appUrl) return config.appUrl;
|
|
442
|
-
return "https://app.walkeros.io";
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// src/lib/config-lock.ts
|
|
446
|
-
import { closeSync, mkdirSync as mkdirSync2, openSync, statSync, unlinkSync as unlinkSync2 } from "fs";
|
|
447
|
-
var STALE_MS = 15e3;
|
|
448
|
-
var RETRY_MS = 100;
|
|
449
|
-
var TIMEOUT_MS = 1e4;
|
|
450
|
-
function getConfigLockPath() {
|
|
451
|
-
return `${getConfigPath()}.lock`;
|
|
452
|
-
}
|
|
453
|
-
function hasCode(value) {
|
|
454
|
-
return typeof value === "object" && value !== null && "code" in value;
|
|
455
|
-
}
|
|
456
|
-
function isAlreadyLocked(error) {
|
|
457
|
-
return hasCode(error) && error.code === "EEXIST";
|
|
458
|
-
}
|
|
459
|
-
function delay(ms) {
|
|
460
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
461
|
-
}
|
|
462
|
-
function breakIfStale(lockPath) {
|
|
463
|
-
try {
|
|
464
|
-
const age = Date.now() - statSync(lockPath).mtimeMs;
|
|
465
|
-
if (age < STALE_MS) return false;
|
|
466
|
-
unlinkSync2(lockPath);
|
|
467
|
-
return true;
|
|
468
|
-
} catch {
|
|
469
|
-
return false;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
async function withConfigLock(fn) {
|
|
473
|
-
const lockPath = getConfigLockPath();
|
|
474
|
-
mkdirSync2(getConfigDir(), { recursive: true, mode: 448 });
|
|
475
|
-
const deadline = Date.now() + TIMEOUT_MS;
|
|
476
|
-
for (; ; ) {
|
|
477
|
-
let handle;
|
|
478
|
-
try {
|
|
479
|
-
handle = openSync(lockPath, "wx", 384);
|
|
480
|
-
} catch (error) {
|
|
481
|
-
if (!isAlreadyLocked(error)) throw error;
|
|
482
|
-
if (breakIfStale(lockPath)) continue;
|
|
483
|
-
if (Date.now() >= deadline) {
|
|
484
|
-
throw new Error(
|
|
485
|
-
`Timed out waiting for the walkerOS config lock at ${lockPath}. Remove the file if no other walkeros process is running.`
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
await delay(RETRY_MS);
|
|
489
|
-
continue;
|
|
490
|
-
}
|
|
491
|
-
closeSync(handle);
|
|
492
|
-
try {
|
|
493
|
-
return await fn();
|
|
494
|
-
} finally {
|
|
495
|
-
try {
|
|
496
|
-
unlinkSync2(lockPath);
|
|
497
|
-
} catch {
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// src/core/oauth-client.ts
|
|
504
|
-
import { z as z2 } from "zod";
|
|
505
|
-
|
|
506
|
-
// src/lib/secure-url.ts
|
|
507
|
-
function isLoopback(hostname) {
|
|
508
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
509
|
-
}
|
|
510
|
-
function requireSecureUrl(url) {
|
|
511
|
-
let parsed;
|
|
512
|
-
try {
|
|
513
|
-
parsed = new URL(url);
|
|
514
|
-
} catch {
|
|
515
|
-
return url;
|
|
516
|
-
}
|
|
517
|
-
if (parsed.protocol !== "http:" || isLoopback(parsed.hostname)) return url;
|
|
518
|
-
throw new Error(
|
|
519
|
-
`Refusing to send walkerOS credentials over plain http to ${url}. Use https, or localhost / 127.0.0.1 / [::1] for local development.`
|
|
520
|
-
);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
// src/core/app-fetch.ts
|
|
524
|
-
import { z } from "zod";
|
|
525
|
-
|
|
526
|
-
// src/core/client-context.ts
|
|
527
|
-
var context;
|
|
528
|
-
function setClientContext(input) {
|
|
529
|
-
const envType = process.env.WALKEROS_CLIENT_TYPE;
|
|
530
|
-
const type = envType ?? input.type ?? "cli";
|
|
531
|
-
context = { type, version: input.version };
|
|
532
|
-
}
|
|
533
|
-
function getClientContext() {
|
|
534
|
-
return context;
|
|
535
|
-
}
|
|
536
|
-
function resetClientContext() {
|
|
537
|
-
context = void 0;
|
|
538
|
-
}
|
|
539
|
-
function clientContextHeaders() {
|
|
540
|
-
if (!context) return {};
|
|
541
|
-
return {
|
|
542
|
-
"User-Agent": `walkeros-${context.type}/${context.version}`,
|
|
543
|
-
"X-WalkerOS-Client": context.type,
|
|
544
|
-
"X-WalkerOS-Client-Version": context.version
|
|
545
|
-
};
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
// src/core/app-fetch.ts
|
|
549
|
-
var AppErrorSchema = z.object({
|
|
550
|
-
error: z.object({ message: z.string().min(1) })
|
|
551
|
-
});
|
|
552
|
-
function appErrorMessage(body) {
|
|
553
|
-
const parsed = AppErrorSchema.safeParse(body);
|
|
554
|
-
return parsed.success ? parsed.data.error.message : void 0;
|
|
555
|
-
}
|
|
556
|
-
async function appFetch(path23, init = {}) {
|
|
557
|
-
const url = `${(init.baseUrl ?? resolveAppUrl()).replace(/\/+$/, "")}${path23}`;
|
|
558
|
-
const headers = new Headers(clientContextHeaders());
|
|
559
|
-
for (const [name, value] of Object.entries(init.headers ?? {}))
|
|
560
|
-
headers.set(name, value);
|
|
561
|
-
if (init.token && !headers.has("Authorization"))
|
|
562
|
-
headers.set("Authorization", `Bearer ${init.token}`);
|
|
563
|
-
if (headers.has("Authorization")) requireSecureUrl(url);
|
|
564
|
-
const request = { headers };
|
|
565
|
-
if (init.method && init.method !== "GET") request.method = init.method;
|
|
566
|
-
if (init.body !== void 0) request.body = init.body;
|
|
567
|
-
if (init.signal) request.signal = init.signal;
|
|
568
|
-
if (init.redirect) request.redirect = init.redirect;
|
|
569
|
-
return (init.fetch ?? fetch)(url, request);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
// src/core/app-paths.ts
|
|
573
|
-
var APP_PATHS = {
|
|
574
|
-
deviceAuthorization: "/api/oauth/device_authorization",
|
|
575
|
-
token: "/api/oauth/token",
|
|
576
|
-
revoke: "/api/oauth/revoke",
|
|
577
|
-
whoami: "/api/auth/whoami",
|
|
578
|
-
health: "/api/health",
|
|
579
|
-
telemetry: "/api/telemetry",
|
|
580
|
-
openapi: "/api/openapi.json"
|
|
581
|
-
};
|
|
582
|
-
|
|
583
|
-
// src/core/oauth-client.ts
|
|
584
|
-
var CLI_CLIENT_ID = "walkeros-cli";
|
|
585
|
-
var CLI_SCOPE = "read write offline_access";
|
|
586
|
-
var DEVICE_CODE_GRANT = "urn:ietf:params:oauth:grant-type:device_code";
|
|
587
|
-
var REFRESH_TIMEOUT_MS = 1e4;
|
|
588
|
-
var REVOKE_TIMEOUT_MS = 5e3;
|
|
589
|
-
var DEVICE_AUTHORIZATION_TIMEOUT_MS = 1e4;
|
|
590
|
-
var DeviceAuthorizationSchema = z2.object({
|
|
591
|
-
device_code: z2.string().min(1),
|
|
592
|
-
user_code: z2.string().min(1),
|
|
593
|
-
verification_uri: z2.string().min(1),
|
|
594
|
-
verification_uri_complete: z2.string().min(1).optional(),
|
|
595
|
-
expires_in: z2.number().int().nonnegative(),
|
|
596
|
-
interval: z2.number().int().nonnegative()
|
|
597
|
-
});
|
|
598
|
-
var TokenSchema = z2.object({
|
|
599
|
-
access_token: z2.string().min(1),
|
|
600
|
-
expires_in: z2.number().int().nonnegative(),
|
|
601
|
-
refresh_token: z2.string().min(1).optional()
|
|
602
|
-
});
|
|
603
|
-
var ErrorSchema = z2.object({
|
|
604
|
-
error: z2.string().min(1),
|
|
605
|
-
error_description: z2.string().optional()
|
|
606
|
-
});
|
|
607
|
-
async function readJson(response) {
|
|
608
|
-
try {
|
|
609
|
-
return await response.json();
|
|
610
|
-
} catch {
|
|
611
|
-
return null;
|
|
612
|
-
}
|
|
613
|
-
}
|
|
614
|
-
function errorCode(body) {
|
|
615
|
-
const parsed = ErrorSchema.safeParse(body);
|
|
616
|
-
return parsed.success ? parsed.data.error : null;
|
|
617
|
-
}
|
|
618
|
-
function describe(response, body) {
|
|
619
|
-
const parsed = ErrorSchema.safeParse(body);
|
|
620
|
-
if (parsed.success) {
|
|
621
|
-
return parsed.data.error_description ? `${parsed.data.error}: ${parsed.data.error_description}` : parsed.data.error;
|
|
622
|
-
}
|
|
623
|
-
return appErrorMessage(body) ?? `HTTP ${response.status}`;
|
|
624
|
-
}
|
|
625
|
-
function postForm(appUrl, path23, form, fetchFn, signal) {
|
|
626
|
-
return appFetch(path23, {
|
|
627
|
-
method: "POST",
|
|
628
|
-
baseUrl: requireSecureUrl(appUrl),
|
|
629
|
-
headers: {
|
|
630
|
-
Accept: "application/json",
|
|
631
|
-
"Content-Type": "application/x-www-form-urlencoded"
|
|
632
|
-
},
|
|
633
|
-
body: new URLSearchParams(form).toString(),
|
|
634
|
-
redirect: "error",
|
|
635
|
-
fetch: fetchFn,
|
|
636
|
-
signal
|
|
637
|
-
});
|
|
638
|
-
}
|
|
639
|
-
function toTokenSet(body) {
|
|
640
|
-
const parsed = TokenSchema.safeParse(body);
|
|
641
|
-
if (!parsed.success) throw new Error("Malformed token response");
|
|
642
|
-
return {
|
|
643
|
-
accessToken: parsed.data.access_token,
|
|
644
|
-
accessTokenExpiresAt: new Date(
|
|
645
|
-
Date.now() + parsed.data.expires_in * 1e3
|
|
646
|
-
).toISOString(),
|
|
647
|
-
refreshToken: parsed.data.refresh_token ?? null
|
|
648
|
-
};
|
|
649
|
-
}
|
|
650
|
-
async function startDeviceAuthorization(appUrl, fetchFn = globalThis.fetch) {
|
|
651
|
-
const response = await postForm(
|
|
652
|
-
appUrl,
|
|
653
|
-
APP_PATHS.deviceAuthorization,
|
|
654
|
-
{
|
|
655
|
-
client_id: CLI_CLIENT_ID,
|
|
656
|
-
scope: CLI_SCOPE,
|
|
657
|
-
// RFC 8707. The token comes back bound to the API, so a leaked CLI token
|
|
658
|
-
// cannot be replayed against the MCP resource.
|
|
659
|
-
resource: `${appUrl}/api`
|
|
660
|
-
},
|
|
661
|
-
fetchFn,
|
|
662
|
-
AbortSignal.timeout(DEVICE_AUTHORIZATION_TIMEOUT_MS)
|
|
663
|
-
);
|
|
664
|
-
const body = await readJson(response);
|
|
665
|
-
if (!response.ok) throw new Error(describe(response, body));
|
|
666
|
-
const parsed = DeviceAuthorizationSchema.safeParse(body);
|
|
667
|
-
if (!parsed.success)
|
|
668
|
-
throw new Error("Malformed device authorization response");
|
|
669
|
-
return {
|
|
670
|
-
deviceCode: parsed.data.device_code,
|
|
671
|
-
userCode: parsed.data.user_code,
|
|
672
|
-
verificationUri: parsed.data.verification_uri,
|
|
673
|
-
verificationUriComplete: parsed.data.verification_uri_complete ?? parsed.data.verification_uri,
|
|
674
|
-
expiresIn: parsed.data.expires_in,
|
|
675
|
-
interval: parsed.data.interval
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
async function pollDeviceToken(appUrl, deviceCode, fetchFn = globalThis.fetch, signal) {
|
|
679
|
-
let response;
|
|
680
|
-
try {
|
|
681
|
-
response = await postForm(
|
|
682
|
-
appUrl,
|
|
683
|
-
APP_PATHS.token,
|
|
684
|
-
{
|
|
685
|
-
grant_type: DEVICE_CODE_GRANT,
|
|
686
|
-
device_code: deviceCode,
|
|
687
|
-
client_id: CLI_CLIENT_ID
|
|
688
|
-
},
|
|
689
|
-
fetchFn,
|
|
690
|
-
signal
|
|
691
|
-
);
|
|
692
|
-
} catch (error) {
|
|
693
|
-
if (signal?.aborted) return { status: "pending" };
|
|
694
|
-
throw error;
|
|
695
|
-
}
|
|
696
|
-
const body = await readJson(response);
|
|
697
|
-
if (response.ok) {
|
|
698
|
-
try {
|
|
699
|
-
return { status: "ok", tokens: toTokenSet(body) };
|
|
700
|
-
} catch (error) {
|
|
701
|
-
return {
|
|
702
|
-
status: "error",
|
|
703
|
-
error: error instanceof Error ? error.message : String(error)
|
|
704
|
-
};
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
switch (errorCode(body)) {
|
|
708
|
-
case "authorization_pending":
|
|
709
|
-
return { status: "pending" };
|
|
710
|
-
case "slow_down":
|
|
711
|
-
return { status: "slow_down" };
|
|
712
|
-
case "access_denied":
|
|
713
|
-
return { status: "denied" };
|
|
714
|
-
case "expired_token":
|
|
715
|
-
return { status: "expired" };
|
|
716
|
-
default:
|
|
717
|
-
return { status: "error", error: describe(response, body) };
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
async function refreshTokens(appUrl, refreshToken, fetchFn = globalThis.fetch) {
|
|
721
|
-
const response = await postForm(
|
|
722
|
-
appUrl,
|
|
723
|
-
APP_PATHS.token,
|
|
724
|
-
{
|
|
725
|
-
grant_type: "refresh_token",
|
|
726
|
-
refresh_token: refreshToken,
|
|
727
|
-
client_id: CLI_CLIENT_ID
|
|
728
|
-
},
|
|
729
|
-
fetchFn,
|
|
730
|
-
AbortSignal.timeout(REFRESH_TIMEOUT_MS)
|
|
731
|
-
);
|
|
732
|
-
const body = await readJson(response);
|
|
733
|
-
if (!response.ok) {
|
|
734
|
-
if (errorCode(body) === "invalid_grant") return null;
|
|
735
|
-
throw new Error(describe(response, body));
|
|
736
|
-
}
|
|
737
|
-
return toTokenSet(body);
|
|
738
|
-
}
|
|
739
|
-
async function revokeRefreshToken(appUrl, refreshToken, fetchFn = globalThis.fetch) {
|
|
740
|
-
try {
|
|
741
|
-
await postForm(
|
|
742
|
-
appUrl,
|
|
743
|
-
APP_PATHS.revoke,
|
|
744
|
-
{
|
|
745
|
-
token: refreshToken,
|
|
746
|
-
token_type_hint: "refresh_token",
|
|
747
|
-
client_id: CLI_CLIENT_ID
|
|
748
|
-
},
|
|
749
|
-
fetchFn,
|
|
750
|
-
AbortSignal.timeout(REVOKE_TIMEOUT_MS)
|
|
751
|
-
);
|
|
752
|
-
} catch {
|
|
753
|
-
}
|
|
754
|
-
}
|
|
755
|
-
|
|
756
353
|
// src/core/auth.ts
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
if (legacyNoticeShown) return;
|
|
761
|
-
legacyNoticeShown = true;
|
|
762
|
-
process.stderr.write(
|
|
763
|
-
"walkerOS: using a static token from your config. Run `walkeros auth login` to switch to a session that refreshes automatically.\n"
|
|
764
|
-
);
|
|
765
|
-
}
|
|
766
|
-
function isFresh(config, nowMs) {
|
|
767
|
-
if (!config.accessToken || !config.accessTokenExpiresAt) return false;
|
|
768
|
-
const expiresAt = Date.parse(config.accessTokenExpiresAt);
|
|
769
|
-
if (Number.isNaN(expiresAt)) return false;
|
|
770
|
-
return expiresAt - nowMs > REFRESH_SKEW_MS;
|
|
771
|
-
}
|
|
772
|
-
async function resolveAccessToken(opts) {
|
|
773
|
-
const envToken = process.env.WALKEROS_TOKEN;
|
|
774
|
-
if (envToken) return envToken;
|
|
775
|
-
const now = opts?.now ?? Date.now;
|
|
776
|
-
const config = readConfig();
|
|
777
|
-
if (!config) return null;
|
|
778
|
-
if (config.token) {
|
|
779
|
-
noticeLegacyToken();
|
|
780
|
-
return config.token;
|
|
781
|
-
}
|
|
782
|
-
if (!config.refreshToken) {
|
|
783
|
-
return isFresh(config, now()) ? config.accessToken ?? null : null;
|
|
784
|
-
}
|
|
785
|
-
if (isFresh(config, now())) return config.accessToken ?? null;
|
|
786
|
-
return withConfigLock(async () => {
|
|
787
|
-
const current = readConfig();
|
|
788
|
-
if (!current?.refreshToken) return current?.accessToken ?? null;
|
|
789
|
-
if (isFresh(current, now())) return current.accessToken ?? null;
|
|
790
|
-
let rotated;
|
|
791
|
-
try {
|
|
792
|
-
rotated = await refreshTokens(
|
|
793
|
-
resolveAppUrl(),
|
|
794
|
-
current.refreshToken,
|
|
795
|
-
opts?.fetch
|
|
796
|
-
);
|
|
797
|
-
} catch (error) {
|
|
798
|
-
const reason = error instanceof Error ? error.message : String(error);
|
|
799
|
-
throw new Error(
|
|
800
|
-
`Could not reach ${resolveAppUrl()} to refresh your session: ${reason}. Your saved session was kept, so try again once the connection is back.`
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
|
-
if (rotated === null) {
|
|
804
|
-
clearAuthFields();
|
|
805
|
-
return null;
|
|
806
|
-
}
|
|
807
|
-
writeConfig({
|
|
808
|
-
accessToken: rotated.accessToken,
|
|
809
|
-
accessTokenExpiresAt: rotated.accessTokenExpiresAt,
|
|
810
|
-
// A server that rotates no new refresh token leaves the current one in
|
|
811
|
-
// force; overwriting it with null would end the session on the next call.
|
|
812
|
-
refreshToken: rotated.refreshToken ?? current.refreshToken
|
|
813
|
-
});
|
|
814
|
-
return rotated.accessToken;
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
async function getAuthHeaders() {
|
|
818
|
-
const token = await resolveAccessToken();
|
|
819
|
-
if (!token) return {};
|
|
820
|
-
return { Authorization: `Bearer ${token}` };
|
|
821
|
-
}
|
|
822
|
-
function credentialSource() {
|
|
823
|
-
if (process.env.WALKEROS_TOKEN) return "env";
|
|
824
|
-
if (hasStoredCredential(readConfig())) return "config";
|
|
825
|
-
return null;
|
|
354
|
+
function resolveAccessToken() {
|
|
355
|
+
const token = process.env.WALKEROS_TOKEN;
|
|
356
|
+
return token ? token : null;
|
|
826
357
|
}
|
|
827
358
|
|
|
828
359
|
// src/core/event-validation.ts
|
|
@@ -1017,6 +548,7 @@ function getDefaultOutput(platform) {
|
|
|
1017
548
|
import path8 from "path";
|
|
1018
549
|
import fs8 from "fs-extra";
|
|
1019
550
|
import { getFlowSettings, getPlatform } from "@walkeros/core";
|
|
551
|
+
import { validateFlowStructure } from "@walkeros/core/dev";
|
|
1020
552
|
|
|
1021
553
|
// src/core/content-digest.ts
|
|
1022
554
|
import { createHash } from "crypto";
|
|
@@ -1095,11 +627,22 @@ function assertWindowCollector(value, source = {}) {
|
|
|
1095
627
|
|
|
1096
628
|
// src/config/loader.ts
|
|
1097
629
|
var DEFAULT_INCLUDE_FOLDER = "./shared";
|
|
630
|
+
function assertFlowStructure(config, flowName) {
|
|
631
|
+
const { errors } = validateFlowStructure({
|
|
632
|
+
...config,
|
|
633
|
+
flows: { [flowName]: config.flows[flowName] }
|
|
634
|
+
});
|
|
635
|
+
if (errors.length === 0) return;
|
|
636
|
+
const lines = errors.map((error) => ` - ${error.path}: ${error.message}`);
|
|
637
|
+
throw new Error(`Invalid configuration:
|
|
638
|
+
${lines.join("\n")}`);
|
|
639
|
+
}
|
|
1098
640
|
function loadBundleConfig(rawConfig, options) {
|
|
1099
641
|
const sanitized = stripLegacyBundleExternal(rawConfig, options.logger);
|
|
1100
642
|
const config = validateFlowConfig(sanitized);
|
|
1101
643
|
const availableFlows = getAvailableFlows(config);
|
|
1102
644
|
const flowName = resolveFlow(config, options.flowName, availableFlows);
|
|
645
|
+
assertFlowStructure(config, flowName);
|
|
1103
646
|
assertLiteralBuildEnv(config, flowName);
|
|
1104
647
|
let flowSettings = getFlowSettings(config, flowName, { deferred: true });
|
|
1105
648
|
const platform = getPlatform(flowSettings);
|
|
@@ -1255,10 +798,12 @@ import path14 from "path";
|
|
|
1255
798
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1256
799
|
import fs14 from "fs-extra";
|
|
1257
800
|
import {
|
|
801
|
+
getPlatform as getPlatform2,
|
|
1258
802
|
packageNameToVariable as packageNameToVariable2,
|
|
1259
803
|
getStepRuntimeProps,
|
|
1260
804
|
ENV_MARKER_PREFIX,
|
|
1261
805
|
SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX2,
|
|
806
|
+
STEP_FUNCTION_KEYS,
|
|
1262
807
|
isPathStepEntry,
|
|
1263
808
|
isObject as isObject3
|
|
1264
809
|
} from "@walkeros/core";
|
|
@@ -1317,6 +862,9 @@ function getFlowSection(flow, section) {
|
|
|
1317
862
|
return flow.stores;
|
|
1318
863
|
}
|
|
1319
864
|
}
|
|
865
|
+
function isLocalPath(spec) {
|
|
866
|
+
return spec.startsWith(".") || spec.startsWith("/");
|
|
867
|
+
}
|
|
1320
868
|
function parsePackageSpec(spec) {
|
|
1321
869
|
const at = spec.lastIndexOf("@");
|
|
1322
870
|
if (at <= 0) return { name: spec };
|
|
@@ -1372,8 +920,7 @@ function applyStepPackages(flowSettings, packages, logger) {
|
|
|
1372
920
|
}
|
|
1373
921
|
};
|
|
1374
922
|
for (const pkg of stepPackages) {
|
|
1375
|
-
|
|
1376
|
-
if (isLocalPath) {
|
|
923
|
+
if (isLocalPath(pkg)) {
|
|
1377
924
|
const varName = packageNameToVariable(pkg);
|
|
1378
925
|
if (!packages[varName]) {
|
|
1379
926
|
packages[varName] = {
|
|
@@ -1418,6 +965,40 @@ function applyStepPackages(flowSettings, packages, logger) {
|
|
|
1418
965
|
}
|
|
1419
966
|
}
|
|
1420
967
|
}
|
|
968
|
+
var KIND_TO_SECTION = {
|
|
969
|
+
source: "sources",
|
|
970
|
+
transformer: "transformers",
|
|
971
|
+
destination: "destinations",
|
|
972
|
+
store: "stores"
|
|
973
|
+
};
|
|
974
|
+
function resolveStepPackage(flow, kind, id, logger) {
|
|
975
|
+
const normalizedFlow = structuredClone(flow);
|
|
976
|
+
const packages = structuredClone(
|
|
977
|
+
normalizedFlow.config?.bundle?.packages ?? {}
|
|
978
|
+
);
|
|
979
|
+
applyStepPackages(normalizedFlow, packages, logger);
|
|
980
|
+
const bucket = getFlowSection(normalizedFlow, KIND_TO_SECTION[kind]);
|
|
981
|
+
const step = bucket?.[id];
|
|
982
|
+
if (!step) {
|
|
983
|
+
const available = Object.keys(bucket ?? {}).join(", ") || "(none)";
|
|
984
|
+
throw new Error(
|
|
985
|
+
`${kind} "${id}" not found in flow. Available: ${available}`
|
|
986
|
+
);
|
|
987
|
+
}
|
|
988
|
+
if (typeof step.package !== "string") {
|
|
989
|
+
throw new Error(
|
|
990
|
+
`${kind}.${id} has no "package" (inline code cannot be set up).`
|
|
991
|
+
);
|
|
992
|
+
}
|
|
993
|
+
const declared = getFlowSection(flow, KIND_TO_SECTION[kind])?.[id]?.package;
|
|
994
|
+
return {
|
|
995
|
+
packageName: step.package,
|
|
996
|
+
label: declared !== void 0 && isLocalPath(declared) ? declared : step.package,
|
|
997
|
+
spec: packages[step.package] ?? {},
|
|
998
|
+
overrides: normalizedFlow.config?.bundle?.overrides ?? {},
|
|
999
|
+
normalizedFlow
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
1421
1002
|
|
|
1422
1003
|
// src/core/package-manager.ts
|
|
1423
1004
|
import pacote from "pacote";
|
|
@@ -1473,7 +1054,7 @@ function tempSibling(dest) {
|
|
|
1473
1054
|
).join("");
|
|
1474
1055
|
return `${dest}${TMP_INFIX}${rand}`;
|
|
1475
1056
|
}
|
|
1476
|
-
function
|
|
1057
|
+
function errorCode(error) {
|
|
1477
1058
|
if (typeof error === "object" && error !== null && "code" in error) {
|
|
1478
1059
|
const code = error.code;
|
|
1479
1060
|
return typeof code === "string" ? code : void 0;
|
|
@@ -1481,7 +1062,7 @@ function errorCode2(error) {
|
|
|
1481
1062
|
return void 0;
|
|
1482
1063
|
}
|
|
1483
1064
|
function isOccupied(error) {
|
|
1484
|
-
const code =
|
|
1065
|
+
const code = errorCode(error);
|
|
1485
1066
|
return code === "EEXIST" || code === "ENOTEMPTY";
|
|
1486
1067
|
}
|
|
1487
1068
|
function isCacheTempName(name) {
|
|
@@ -1520,7 +1101,7 @@ async function replaceIncomplete(tmp, dest) {
|
|
|
1520
1101
|
await fs9.rename(dest, aside);
|
|
1521
1102
|
moved = true;
|
|
1522
1103
|
} catch (error) {
|
|
1523
|
-
if (
|
|
1104
|
+
if (errorCode(error) !== "ENOENT") throw error;
|
|
1524
1105
|
}
|
|
1525
1106
|
const restore = moved && await isCacheDirComplete(aside);
|
|
1526
1107
|
const winner = restore ? aside : tmp;
|
|
@@ -1698,7 +1279,7 @@ function backoffForAttempt(index) {
|
|
|
1698
1279
|
const spread = base * JITTER;
|
|
1699
1280
|
return base + (Math.random() * 2 - 1) * spread;
|
|
1700
1281
|
}
|
|
1701
|
-
function
|
|
1282
|
+
function delay(ms) {
|
|
1702
1283
|
return new Promise((resolve5) => {
|
|
1703
1284
|
setTimeout(resolve5, ms);
|
|
1704
1285
|
});
|
|
@@ -1740,7 +1321,7 @@ async function withPacoteRetry(fn, label, options = {}) {
|
|
|
1740
1321
|
maxTotalMs - (Date.now() - start)
|
|
1741
1322
|
);
|
|
1742
1323
|
if (sleepMs <= 0) break;
|
|
1743
|
-
await
|
|
1324
|
+
await delay(sleepMs);
|
|
1744
1325
|
}
|
|
1745
1326
|
throw new Error(
|
|
1746
1327
|
`Failed ${label} after ${made} attempts: ${describeError(lastError)}`
|
|
@@ -2567,21 +2148,21 @@ async function ensureCodeOnDisk(codeContent, compiledCode, tmpDir, inputs) {
|
|
|
2567
2148
|
}
|
|
2568
2149
|
|
|
2569
2150
|
// src/version.ts
|
|
2570
|
-
import { readFileSync
|
|
2151
|
+
import { readFileSync } from "fs";
|
|
2571
2152
|
import { fileURLToPath } from "url";
|
|
2572
|
-
import { dirname as dirname3, join as
|
|
2153
|
+
import { dirname as dirname3, join as join3 } from "path";
|
|
2573
2154
|
var versionFilename = fileURLToPath(import.meta.url);
|
|
2574
2155
|
var versionDirname = dirname3(versionFilename);
|
|
2575
2156
|
function findPackageJson() {
|
|
2576
2157
|
const paths = [
|
|
2577
|
-
|
|
2158
|
+
join3(versionDirname, "../package.json"),
|
|
2578
2159
|
// dist/ or src/
|
|
2579
|
-
|
|
2160
|
+
join3(versionDirname, "../../package.json")
|
|
2580
2161
|
// src/core/ (not used, but safe)
|
|
2581
2162
|
];
|
|
2582
2163
|
for (const p of paths) {
|
|
2583
2164
|
try {
|
|
2584
|
-
return
|
|
2165
|
+
return readFileSync(p, "utf-8");
|
|
2585
2166
|
} catch {
|
|
2586
2167
|
}
|
|
2587
2168
|
}
|
|
@@ -2597,9 +2178,11 @@ function hasCodeReference(code) {
|
|
|
2597
2178
|
return isInlineCode(code) || typeof code === "string";
|
|
2598
2179
|
}
|
|
2599
2180
|
function generateInlineCode(inline, runtimeProps, isDestination) {
|
|
2600
|
-
const pushFn = inline.push.replace("$code:", "");
|
|
2601
|
-
const initFn = inline.init ? inline.init.replace("$code:", "") : void 0;
|
|
2602
2181
|
const typeLine = inline.type ? `type: '${inline.type}',` : "";
|
|
2182
|
+
const functionLines = STEP_FUNCTION_KEYS.flatMap((key) => {
|
|
2183
|
+
const fn = inline[key];
|
|
2184
|
+
return fn ? [`${key}: ${fn.replace("$code:", "")}`] : [];
|
|
2185
|
+
}).join(",\n ");
|
|
2603
2186
|
const props = {
|
|
2604
2187
|
config: {},
|
|
2605
2188
|
env: {},
|
|
@@ -2611,8 +2194,7 @@ function generateInlineCode(inline, runtimeProps, isDestination) {
|
|
|
2611
2194
|
code: {
|
|
2612
2195
|
${typeLine}
|
|
2613
2196
|
config: ${processConfigValue(props.config)},
|
|
2614
|
-
${
|
|
2615
|
-
push: ${pushFn}
|
|
2197
|
+
${functionLines}
|
|
2616
2198
|
},
|
|
2617
2199
|
${propLines}
|
|
2618
2200
|
}`;
|
|
@@ -2621,8 +2203,7 @@ function generateInlineCode(inline, runtimeProps, isDestination) {
|
|
|
2621
2203
|
code: async (context) => ({
|
|
2622
2204
|
${typeLine}
|
|
2623
2205
|
config: context.config,
|
|
2624
|
-
${
|
|
2625
|
-
push: ${pushFn}
|
|
2206
|
+
${functionLines}
|
|
2626
2207
|
}),
|
|
2627
2208
|
${propLines}
|
|
2628
2209
|
}`;
|
|
@@ -2768,6 +2349,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false,
|
|
|
2768
2349
|
packagePaths
|
|
2769
2350
|
);
|
|
2770
2351
|
const versionsHash = await getHashServer3(sortedVersions.join("\n"), 12);
|
|
2352
|
+
applyCollectorDefaults(flowSettings);
|
|
2771
2353
|
if (provenance) {
|
|
2772
2354
|
applyCollectorProvenance(
|
|
2773
2355
|
flowSettings,
|
|
@@ -2939,7 +2521,7 @@ ${dataDeclaration}${needs}`;
|
|
|
2939
2521
|
};
|
|
2940
2522
|
if (buildOptions.platform === "browser") {
|
|
2941
2523
|
stage2Options.format = "iife";
|
|
2942
|
-
stage2Options.plugins = [
|
|
2524
|
+
stage2Options.plugins = [cliPackagesPlugin()];
|
|
2943
2525
|
stage2Options.define = {
|
|
2944
2526
|
"process.env.NODE_ENV": '"production"',
|
|
2945
2527
|
global: "globalThis",
|
|
@@ -3107,22 +2689,25 @@ function getNodeExternals() {
|
|
|
3107
2689
|
}
|
|
3108
2690
|
return externals;
|
|
3109
2691
|
}
|
|
3110
|
-
var
|
|
3111
|
-
function
|
|
2692
|
+
var CLI_PACKAGES = "walkeros-cli-packages";
|
|
2693
|
+
function cliPackagesPlugin() {
|
|
3112
2694
|
const resolveDir = path14.dirname(fileURLToPath2(import.meta.url));
|
|
3113
2695
|
return {
|
|
3114
|
-
name:
|
|
2696
|
+
name: CLI_PACKAGES,
|
|
3115
2697
|
setup(build2) {
|
|
3116
|
-
build2.onResolve(
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
2698
|
+
build2.onResolve(
|
|
2699
|
+
{ filter: /^@walkeros\/(core|web-core)$/ },
|
|
2700
|
+
async (args) => {
|
|
2701
|
+
if (args.pluginData === CLI_PACKAGES) return void 0;
|
|
2702
|
+
const resolved = await build2.resolve(args.path, {
|
|
2703
|
+
kind: args.kind,
|
|
2704
|
+
resolveDir,
|
|
2705
|
+
pluginData: CLI_PACKAGES
|
|
2706
|
+
});
|
|
2707
|
+
if (resolved.errors.length > 0) return { errors: resolved.errors };
|
|
2708
|
+
return { path: resolved.path, sideEffects: resolved.sideEffects };
|
|
2709
|
+
}
|
|
2710
|
+
);
|
|
3126
2711
|
}
|
|
3127
2712
|
};
|
|
3128
2713
|
}
|
|
@@ -3439,6 +3024,12 @@ ${firstError.text}`
|
|
|
3439
3024
|
function buildDataPayload(flowSettings) {
|
|
3440
3025
|
return buildSplitConfigObject(flowSettings, detectNamedImports(flowSettings)).dataPayloadObj;
|
|
3441
3026
|
}
|
|
3027
|
+
function applyCollectorDefaults(flowSettings) {
|
|
3028
|
+
if (getPlatform2(flowSettings) !== "server") return;
|
|
3029
|
+
const collector = flowSettings.collector ?? {};
|
|
3030
|
+
collector.consentDenied ??= "skip";
|
|
3031
|
+
flowSettings.collector = collector;
|
|
3032
|
+
}
|
|
3442
3033
|
function applyCollectorProvenance(flowSettings, flowName, release2, fallback) {
|
|
3443
3034
|
const collector = flowSettings.collector ?? {};
|
|
3444
3035
|
collector.name ??= flowName;
|
|
@@ -3557,6 +3148,34 @@ export function wireConfig(__data) {
|
|
|
3557
3148
|
|
|
3558
3149
|
export { startFlow };`;
|
|
3559
3150
|
}
|
|
3151
|
+
var HOST_LOGGER_MERGE = ` // The host's logger (masking, its error ring) joins the flow's own: the
|
|
3152
|
+
// flow's level and format win, unless the host forces a level (--verbose);
|
|
3153
|
+
// the flow's handler runs first, then the host's, once per line, always.
|
|
3154
|
+
// The flow handler's originalHandler does nothing, so no line prints a
|
|
3155
|
+
// second time unmasked. The host learns the flow's settings before the
|
|
3156
|
+
// collector starts, so every line, the first included, has its format.
|
|
3157
|
+
if (context.logger) {
|
|
3158
|
+
const own = config.logger || {};
|
|
3159
|
+
const host = context.logger;
|
|
3160
|
+
if (context.onLogger) context.onLogger({ level: own.level, format: own.format });
|
|
3161
|
+
const level = context.logLevel ?? own.level ?? host.level;
|
|
3162
|
+
const printedByHost = () => {};
|
|
3163
|
+
const handler = own.handler && host.handler
|
|
3164
|
+
? (lvl, message, ctx, scope) => {
|
|
3165
|
+
try {
|
|
3166
|
+
own.handler(lvl, message, ctx, scope, printedByHost);
|
|
3167
|
+
} finally {
|
|
3168
|
+
host.handler(lvl, message, ctx, scope, printedByHost);
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
: host.handler || own.handler;
|
|
3172
|
+
config.logger = {
|
|
3173
|
+
...host,
|
|
3174
|
+
...(level !== undefined ? { level } : {}),
|
|
3175
|
+
...(own.format ? { format: own.format } : {}),
|
|
3176
|
+
...(handler ? { handler } : {}),
|
|
3177
|
+
};
|
|
3178
|
+
}`;
|
|
3560
3179
|
function generateServerEntry(stage1Path, dataPayload) {
|
|
3561
3180
|
const stage1Specifier = toFileImportSpecifier(stage1Path);
|
|
3562
3181
|
return `import { startFlow, wireConfig } from '${stage1Specifier}';
|
|
@@ -3566,7 +3185,7 @@ const __configData = ${dataPayload};
|
|
|
3566
3185
|
export default async function(context = {}) {
|
|
3567
3186
|
const config = wireConfig(__configData);
|
|
3568
3187
|
|
|
3569
|
-
|
|
3188
|
+
${HOST_LOGGER_MERGE}
|
|
3570
3189
|
|
|
3571
3190
|
if (context.sourceSettings && config.sources) {
|
|
3572
3191
|
for (const src of Object.values(config.sources)) {
|
|
@@ -3626,6 +3245,7 @@ function readObserveConnect(flowSettings, logger) {
|
|
|
3626
3245
|
);
|
|
3627
3246
|
return void 0;
|
|
3628
3247
|
}
|
|
3248
|
+
var OBSERVE_SLOT_IMPORT = "import { pageObserveSlot } from '@walkeros/web-core';\n";
|
|
3629
3249
|
function emitObserveAssignment(observe) {
|
|
3630
3250
|
const literal = {
|
|
3631
3251
|
url: observe.url,
|
|
@@ -3635,9 +3255,9 @@ function emitObserveAssignment(observe) {
|
|
|
3635
3255
|
...observe.sample !== void 0 ? { sample: observe.sample } : {}
|
|
3636
3256
|
};
|
|
3637
3257
|
return `
|
|
3638
|
-
config.observe =
|
|
3258
|
+
config.observe = { ...${JSON.stringify(literal)}, slot: pageObserveSlot() };`;
|
|
3639
3259
|
}
|
|
3640
|
-
var MOIN_IMPORT = "import { moin } from '@walkeros/core';\n";
|
|
3260
|
+
var MOIN_IMPORT = "import { moin } from '@walkeros/web-core';\n";
|
|
3641
3261
|
function emitMoinCall(target) {
|
|
3642
3262
|
if (!target)
|
|
3643
3263
|
return `
|
|
@@ -3685,10 +3305,11 @@ function generateWebEntry(stage1Path, dataPayload, options = {}) {
|
|
|
3685
3305
|
}
|
|
3686
3306
|
}` : "";
|
|
3687
3307
|
const stage1Specifier = toFileImportSpecifier(stage1Path);
|
|
3308
|
+
const observeImport = options.observe ? OBSERVE_SLOT_IMPORT : "";
|
|
3688
3309
|
const observeBlock = options.observe ? emitObserveAssignment(options.observe) : "";
|
|
3689
3310
|
const loaderImport = platform === "browser" ? MOIN_IMPORT : "";
|
|
3690
3311
|
const loaderCall = platform === "browser" ? emitMoinCall() : "";
|
|
3691
|
-
return `${loaderImport}import { startFlow, wireConfig } from '${stage1Specifier}';
|
|
3312
|
+
return `${loaderImport}${observeImport}import { startFlow, wireConfig } from '${stage1Specifier}';
|
|
3692
3313
|
|
|
3693
3314
|
const __configData = ${dataPayload};
|
|
3694
3315
|
|
|
@@ -3712,7 +3333,7 @@ function generateWrapEntry(stage1Path, options = {}) {
|
|
|
3712
3333
|
}
|
|
3713
3334
|
const preview = options.preview;
|
|
3714
3335
|
const previewEnabled = !!preview?.enabled;
|
|
3715
|
-
const previewImport = previewEnabled ? `import { browserSwapActivator } from '@walkeros/core';
|
|
3336
|
+
const previewImport = previewEnabled ? `import { browserSwapActivator } from '@walkeros/web-core';
|
|
3716
3337
|
` : "";
|
|
3717
3338
|
const grantTargets = options.previewGrantTargets ?? [];
|
|
3718
3339
|
const previewGrantBlock = grantTargets.length > 0 ? `
|
|
@@ -3762,10 +3383,11 @@ ${grantTargets.map((key) => {
|
|
|
3762
3383
|
}
|
|
3763
3384
|
}` : "";
|
|
3764
3385
|
const stage1Specifier = toFileImportSpecifier(stage1Path);
|
|
3386
|
+
const observeImport = options.observe ? OBSERVE_SLOT_IMPORT : "";
|
|
3765
3387
|
const observeBlock = options.observe ? emitObserveAssignment(options.observe) : "";
|
|
3766
3388
|
const loaderImport = platform === "browser" ? MOIN_IMPORT : "";
|
|
3767
3389
|
const loaderCall = platform === "browser" ? emitMoinCall(options.moin) : "";
|
|
3768
|
-
return `${loaderImport}${previewImport}import { startFlow, wireConfig, __configData } from '${stage1Specifier}';
|
|
3390
|
+
return `${loaderImport}${previewImport}${observeImport}import { startFlow, wireConfig, __configData } from '${stage1Specifier}';
|
|
3769
3391
|
|
|
3770
3392
|
(async () => {${loaderCall}${previewBlock}
|
|
3771
3393
|
const config = wireConfig(__configData);${envBlock}${previewGrantBlock}${observeBlock}
|
|
@@ -3782,7 +3404,7 @@ function generateWrapEntryServer(stage1Path) {
|
|
|
3782
3404
|
export default async function(context = {}) {
|
|
3783
3405
|
const config = wireConfig(__configData);
|
|
3784
3406
|
|
|
3785
|
-
|
|
3407
|
+
${HOST_LOGGER_MERGE}
|
|
3786
3408
|
|
|
3787
3409
|
if (context.sourceSettings && config.sources) {
|
|
3788
3410
|
for (const src of Object.values(config.sources)) {
|
|
@@ -4268,7 +3890,7 @@ async function bundle(configOrPath, options = {}) {
|
|
|
4268
3890
|
// src/commands/push/index.ts
|
|
4269
3891
|
import path18 from "path";
|
|
4270
3892
|
import fs18 from "fs-extra";
|
|
4271
|
-
import { createIngest, getPlatform as
|
|
3893
|
+
import { createIngest, getPlatform as getPlatform4, stepId } from "@walkeros/core";
|
|
4272
3894
|
import {
|
|
4273
3895
|
enrichEvent,
|
|
4274
3896
|
transformerInit,
|
|
@@ -4497,13 +4119,13 @@ function installTimerInterception(options = {}) {
|
|
|
4497
4119
|
setInterval: Reflect.get(target, "setInterval"),
|
|
4498
4120
|
clearInterval: Reflect.get(target, "clearInterval")
|
|
4499
4121
|
});
|
|
4500
|
-
const trackedSetTimeout = (callback,
|
|
4122
|
+
const trackedSetTimeout = (callback, delay2, ...args) => {
|
|
4501
4123
|
if (typeof callback !== "function") return 0;
|
|
4502
4124
|
const id = nextId++;
|
|
4503
4125
|
pending.set(id, {
|
|
4504
4126
|
id,
|
|
4505
4127
|
callback,
|
|
4506
|
-
delay:
|
|
4128
|
+
delay: delay2 ?? 0,
|
|
4507
4129
|
type: "timeout",
|
|
4508
4130
|
args,
|
|
4509
4131
|
cleared: false
|
|
@@ -4516,13 +4138,13 @@ function installTimerInterception(options = {}) {
|
|
|
4516
4138
|
const entry = pending.get(numId);
|
|
4517
4139
|
if (entry) entry.cleared = true;
|
|
4518
4140
|
};
|
|
4519
|
-
const trackedSetInterval = (callback,
|
|
4141
|
+
const trackedSetInterval = (callback, delay2, ...args) => {
|
|
4520
4142
|
if (typeof callback !== "function") return 0;
|
|
4521
4143
|
const id = nextId++;
|
|
4522
4144
|
pending.set(id, {
|
|
4523
4145
|
id,
|
|
4524
4146
|
callback,
|
|
4525
|
-
delay:
|
|
4147
|
+
delay: delay2 ?? 0,
|
|
4526
4148
|
type: "interval",
|
|
4527
4149
|
args,
|
|
4528
4150
|
cleared: false
|
|
@@ -4962,7 +4584,7 @@ function buildSimulationResult(args) {
|
|
|
4962
4584
|
// src/commands/push/prepare.ts
|
|
4963
4585
|
import path17 from "path";
|
|
4964
4586
|
import fs17 from "fs-extra";
|
|
4965
|
-
import { getPlatform as
|
|
4587
|
+
import { getPlatform as getPlatform3 } from "@walkeros/core";
|
|
4966
4588
|
|
|
4967
4589
|
// src/core/known-secrets.ts
|
|
4968
4590
|
import { REF_SECRET } from "@walkeros/core";
|
|
@@ -5004,7 +4626,7 @@ async function prepareFlow(input) {
|
|
|
5004
4626
|
configPath: process.cwd(),
|
|
5005
4627
|
flowName: input.flow
|
|
5006
4628
|
});
|
|
5007
|
-
const platform =
|
|
4629
|
+
const platform = getPlatform3(flowSettings);
|
|
5008
4630
|
const overrides = buildOverrides(
|
|
5009
4631
|
{ simulate: input.simulate, mock: input.mock },
|
|
5010
4632
|
flowSettings
|
|
@@ -5580,7 +5202,7 @@ async function executeConfigPush(options, validatedEvent, logger, setTempDir, lo
|
|
|
5580
5202
|
logger,
|
|
5581
5203
|
raw: loaded.raw
|
|
5582
5204
|
});
|
|
5583
|
-
const platform =
|
|
5205
|
+
const platform = getPlatform4(flowSettings);
|
|
5584
5206
|
const overrides = buildOverrides({ mock: options.mock }, flowSettings);
|
|
5585
5207
|
logger.debug("Bundling flow configuration");
|
|
5586
5208
|
const tempDir = await tmpRunDir("push");
|
|
@@ -6448,19 +6070,12 @@ async function simulateDestination(configOrPath, event, options) {
|
|
|
6448
6070
|
import * as fs20 from "fs";
|
|
6449
6071
|
import * as path20 from "path";
|
|
6450
6072
|
import chalk2 from "chalk";
|
|
6451
|
-
import { isObject as
|
|
6073
|
+
import { isObject as isObject11 } from "@walkeros/core";
|
|
6452
6074
|
|
|
6453
6075
|
// src/commands/validate/validators/contract.ts
|
|
6454
|
-
import { isObject as isObject5 } from "@walkeros/core";
|
|
6076
|
+
import { CONTRACT_RULE_KEYS, isObject as isObject5 } from "@walkeros/core";
|
|
6077
|
+
var KNOWN_KEYS = new Set(CONTRACT_RULE_KEYS);
|
|
6455
6078
|
var SECTION_KEYS = ["globals", "context", "custom", "user", "consent"];
|
|
6456
|
-
var KNOWN_KEYS = /* @__PURE__ */ new Set([
|
|
6457
|
-
"extend",
|
|
6458
|
-
"tagging",
|
|
6459
|
-
"description",
|
|
6460
|
-
"events",
|
|
6461
|
-
"schema",
|
|
6462
|
-
...SECTION_KEYS
|
|
6463
|
-
]);
|
|
6464
6079
|
function validateContract(input) {
|
|
6465
6080
|
const errors = [];
|
|
6466
6081
|
const warnings = [];
|
|
@@ -6501,7 +6116,9 @@ function validateContract(input) {
|
|
|
6501
6116
|
const keys = Object.keys(obj);
|
|
6502
6117
|
const unknownKeys = keys.filter((k) => !KNOWN_KEYS.has(k));
|
|
6503
6118
|
const hasKnownKey = keys.some((k) => KNOWN_KEYS.has(k));
|
|
6504
|
-
const objectValuedUnknown = unknownKeys.filter(
|
|
6119
|
+
const objectValuedUnknown = unknownKeys.filter(
|
|
6120
|
+
(k) => isObject5(obj[k]) && !SECTION_KEYS.includes(k)
|
|
6121
|
+
);
|
|
6505
6122
|
if (!hasKnownKey && objectValuedUnknown.length > 0) {
|
|
6506
6123
|
errors.push({
|
|
6507
6124
|
path: name,
|
|
@@ -6511,9 +6128,9 @@ function validateContract(input) {
|
|
|
6511
6128
|
continue;
|
|
6512
6129
|
}
|
|
6513
6130
|
for (const key of unknownKeys) {
|
|
6514
|
-
|
|
6131
|
+
errors.push({
|
|
6515
6132
|
path: `${name}.${key}`,
|
|
6516
|
-
message: `Unknown contract key "${key}" is
|
|
6133
|
+
message: SECTION_KEYS.includes(key) ? `Contract section "${key}" is not enforced: the validate transformer reads only "events" and "schema". Put the rule into "schema" (a JSON Schema for the whole event), for example "schema": { "properties": { "${key}": { ... } } }.` : `Unknown contract key "${key}" is not supported. Known keys: ${[...KNOWN_KEYS].join(", ")}.`,
|
|
6517
6134
|
code: "UNKNOWN_CONTRACT_KEY"
|
|
6518
6135
|
});
|
|
6519
6136
|
}
|
|
@@ -6542,21 +6159,9 @@ function validateContract(input) {
|
|
|
6542
6159
|
errors.push({
|
|
6543
6160
|
path: `${name}.extend`,
|
|
6544
6161
|
message: `extend references non-existent contract "${obj.extend}"`,
|
|
6545
|
-
value: obj.extend,
|
|
6546
|
-
code: "INVALID_EXTENDS"
|
|
6547
|
-
});
|
|
6548
|
-
}
|
|
6549
|
-
}
|
|
6550
|
-
for (const key of SECTION_KEYS) {
|
|
6551
|
-
if (key in obj) {
|
|
6552
|
-
if (typeof obj[key] !== "object" || obj[key] === null) {
|
|
6553
|
-
errors.push({
|
|
6554
|
-
path: `${name}.${key}`,
|
|
6555
|
-
message: `Section "${key}" must be a JSON Schema object`,
|
|
6556
|
-
value: obj[key],
|
|
6557
|
-
code: "INVALID_SECTION"
|
|
6558
|
-
});
|
|
6559
|
-
}
|
|
6162
|
+
value: obj.extend,
|
|
6163
|
+
code: "INVALID_EXTENDS"
|
|
6164
|
+
});
|
|
6560
6165
|
}
|
|
6561
6166
|
}
|
|
6562
6167
|
if (obj.events !== void 0) {
|
|
@@ -6667,12 +6272,17 @@ import {
|
|
|
6667
6272
|
ENV_MARKER_PREFIX as ENV_MARKER_PREFIX3,
|
|
6668
6273
|
getByPath,
|
|
6669
6274
|
getRouteGraph,
|
|
6670
|
-
isObject as
|
|
6275
|
+
isObject as isObject9,
|
|
6671
6276
|
REF_CONTRACT,
|
|
6672
6277
|
resolveContracts,
|
|
6278
|
+
SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX4,
|
|
6673
6279
|
validateStepEntry
|
|
6674
6280
|
} from "@walkeros/core";
|
|
6675
|
-
import {
|
|
6281
|
+
import {
|
|
6282
|
+
checkStepKeys,
|
|
6283
|
+
schemas as schemas4,
|
|
6284
|
+
validateFlowStructure as validateFlowStructure2
|
|
6285
|
+
} from "@walkeros/core/dev";
|
|
6676
6286
|
import {
|
|
6677
6287
|
validateEventAgainstContract
|
|
6678
6288
|
} from "@walkeros/transformer-validate";
|
|
@@ -6861,19 +6471,52 @@ function resolutionCode(error) {
|
|
|
6861
6471
|
}
|
|
6862
6472
|
|
|
6863
6473
|
// src/commands/validate/validators/settings.ts
|
|
6864
|
-
import * as fs19 from "fs";
|
|
6865
|
-
import * as path19 from "path";
|
|
6866
6474
|
import Ajv from "ajv";
|
|
6867
6475
|
import {
|
|
6476
|
+
createLogger,
|
|
6868
6477
|
ENV_MARKER_PREFIX as ENV_MARKER_PREFIX2,
|
|
6869
|
-
fetchPackage,
|
|
6870
6478
|
getErrorMessage as getErrorMessage3,
|
|
6871
|
-
isObject as
|
|
6479
|
+
isObject as isObject8,
|
|
6872
6480
|
REF_CODE_PREFIX,
|
|
6873
6481
|
REF_STORE,
|
|
6874
6482
|
SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX3
|
|
6875
6483
|
} from "@walkeros/core";
|
|
6876
|
-
|
|
6484
|
+
|
|
6485
|
+
// src/core/package-info.ts
|
|
6486
|
+
import * as fs19 from "fs";
|
|
6487
|
+
import * as path19 from "path";
|
|
6488
|
+
import { fetchPackage, isObject as isObject7, parseWalkerOSJson } from "@walkeros/core";
|
|
6489
|
+
function readJson(file) {
|
|
6490
|
+
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
6491
|
+
}
|
|
6492
|
+
async function readStepPackageInfo(resolved, options) {
|
|
6493
|
+
const { packageName, spec } = resolved;
|
|
6494
|
+
if (spec.path === void 0)
|
|
6495
|
+
return fetchPackage(packageName, {
|
|
6496
|
+
...spec.version ? { version: spec.version } : {},
|
|
6497
|
+
client: options.client
|
|
6498
|
+
});
|
|
6499
|
+
if (options.configDir === void 0)
|
|
6500
|
+
throw new Error(
|
|
6501
|
+
"it is a local path package and the input is not a file, so there is no directory to read it from"
|
|
6502
|
+
);
|
|
6503
|
+
const root = path19.isAbsolute(spec.path) ? spec.path : path19.resolve(options.configDir, spec.path);
|
|
6504
|
+
const file = [
|
|
6505
|
+
path19.join(root, "dist", "walkerOS.json"),
|
|
6506
|
+
path19.join(root, "walkerOS.json")
|
|
6507
|
+
].find((candidate) => fs19.existsSync(candidate));
|
|
6508
|
+
if (!file) throw new Error(`no walkerOS.json under ${root}`);
|
|
6509
|
+
const meta = readJson(file);
|
|
6510
|
+
if (!isObject7(meta)) throw new Error(`${file} is not a JSON object`);
|
|
6511
|
+
const pkgFile = path19.join(root, "package.json");
|
|
6512
|
+
const pkg = fs19.existsSync(pkgFile) ? readJson(pkgFile) : void 0;
|
|
6513
|
+
const version = isObject7(pkg) && typeof pkg.version === "string" ? pkg.version : void 0;
|
|
6514
|
+
return { ...parseWalkerOSJson(meta), ...version ? { version } : {} };
|
|
6515
|
+
}
|
|
6516
|
+
|
|
6517
|
+
// src/commands/validate/validators/settings.ts
|
|
6518
|
+
var CLIENT_HEADER = "walkeros-cli/4.8.3-next-1793115089237";
|
|
6519
|
+
var LOGGER = createLogger();
|
|
6877
6520
|
function createSettingsContext(configDir) {
|
|
6878
6521
|
return { configDir, cache: /* @__PURE__ */ new Map(), compiled: /* @__PURE__ */ new Map() };
|
|
6879
6522
|
}
|
|
@@ -6884,7 +6527,7 @@ function selectSettingsSchema(pkg, packageLabel, exportName) {
|
|
|
6884
6527
|
pkg.exportSchemas,
|
|
6885
6528
|
exportName
|
|
6886
6529
|
) ? pkg.exportSchemas[exportName] : void 0;
|
|
6887
|
-
if (!
|
|
6530
|
+
if (!isObject8(entry))
|
|
6888
6531
|
return {
|
|
6889
6532
|
ok: false,
|
|
6890
6533
|
reason: `${packageLabel} has no export "${exportName}"`
|
|
@@ -6912,7 +6555,7 @@ function valueAt(root, segments) {
|
|
|
6912
6555
|
let current = root;
|
|
6913
6556
|
for (const segment of segments) {
|
|
6914
6557
|
if (Array.isArray(current)) current = current[Number(segment)];
|
|
6915
|
-
else if (
|
|
6558
|
+
else if (isObject8(current)) current = current[segment];
|
|
6916
6559
|
else return void 0;
|
|
6917
6560
|
}
|
|
6918
6561
|
return current;
|
|
@@ -6927,7 +6570,7 @@ function prepareSettings(settings) {
|
|
|
6927
6570
|
const walk = (value, segments) => {
|
|
6928
6571
|
if (Array.isArray(value))
|
|
6929
6572
|
return value.map((item, index) => walk(item, [...segments, `${index}`]));
|
|
6930
|
-
if (
|
|
6573
|
+
if (isObject8(value))
|
|
6931
6574
|
return Object.fromEntries(
|
|
6932
6575
|
Object.entries(value).map(([key, item]) => [
|
|
6933
6576
|
key,
|
|
@@ -6971,62 +6614,9 @@ function prepareSettings(settings) {
|
|
|
6971
6614
|
function isUnder(segments, prefix) {
|
|
6972
6615
|
return prefix.every((segment, index) => segments[index] === segment);
|
|
6973
6616
|
}
|
|
6974
|
-
function
|
|
6975
|
-
const
|
|
6976
|
-
|
|
6977
|
-
const packages = isObject7(bundle2) ? bundle2.packages : void 0;
|
|
6978
|
-
const pin = isObject7(packages) ? packages[name] : void 0;
|
|
6979
|
-
if (!isObject7(pin)) return {};
|
|
6980
|
-
return {
|
|
6981
|
-
...typeof pin.version === "string" ? { version: pin.version } : {},
|
|
6982
|
-
...typeof pin.path === "string" ? { path: pin.path } : {}
|
|
6983
|
-
};
|
|
6984
|
-
}
|
|
6985
|
-
function packageSource(spec, rawFlow) {
|
|
6986
|
-
if (spec.startsWith(".") || spec.startsWith("/"))
|
|
6987
|
-
return { name: spec, localPath: spec };
|
|
6988
|
-
const { name, version } = parsePackageSpec(spec);
|
|
6989
|
-
const pin = bundlePin(rawFlow, name);
|
|
6990
|
-
if (pin.path) return { name, localPath: pin.path };
|
|
6991
|
-
const pinned = pin.version ?? version;
|
|
6992
|
-
return pinned ? { name, version: pinned } : { name };
|
|
6993
|
-
}
|
|
6994
|
-
function readJson2(file) {
|
|
6995
|
-
return JSON.parse(fs19.readFileSync(file, "utf-8"));
|
|
6996
|
-
}
|
|
6997
|
-
function readLocalSchema(source, configDir) {
|
|
6998
|
-
const localPath = source.localPath ?? "";
|
|
6999
|
-
const root = path19.isAbsolute(localPath) ? localPath : path19.resolve(configDir, localPath);
|
|
7000
|
-
const file = [
|
|
7001
|
-
path19.join(root, "dist", "walkerOS.json"),
|
|
7002
|
-
path19.join(root, "walkerOS.json")
|
|
7003
|
-
].find((candidate) => fs19.existsSync(candidate));
|
|
7004
|
-
if (!file) throw new Error(`no walkerOS.json under ${root}`);
|
|
7005
|
-
const meta = readJson2(file);
|
|
7006
|
-
const pkgFile = path19.join(root, "package.json");
|
|
7007
|
-
const pkg = fs19.existsSync(pkgFile) ? readJson2(pkgFile) : void 0;
|
|
7008
|
-
const schemas6 = isObject7(meta) ? meta.schemas : void 0;
|
|
7009
|
-
const exportSchemas = isObject7(meta) ? meta.exportSchemas : void 0;
|
|
7010
|
-
const declared = isObject7(meta) && isObject7(meta.$meta) ? meta.$meta.exports : void 0;
|
|
7011
|
-
const version = isObject7(pkg) && typeof pkg.version === "string" ? pkg.version : void 0;
|
|
7012
|
-
return {
|
|
7013
|
-
...version ? { version } : {},
|
|
7014
|
-
settings: isObject7(schemas6) ? schemas6.settings : void 0,
|
|
7015
|
-
...isObject7(exportSchemas) ? { exportSchemas } : {},
|
|
7016
|
-
...isObject7(declared) ? { exports: Object.keys(declared) } : {}
|
|
7017
|
-
};
|
|
7018
|
-
}
|
|
7019
|
-
async function loadSchema(source, context2) {
|
|
7020
|
-
if (source.localPath !== void 0) {
|
|
7021
|
-
const configDir = context2.configDir;
|
|
7022
|
-
if (configDir === void 0)
|
|
7023
|
-
throw new Error(
|
|
7024
|
-
"it is a local path package and the input is not a file, so there is no directory to read it from"
|
|
7025
|
-
);
|
|
7026
|
-
return readLocalSchema(source, configDir);
|
|
7027
|
-
}
|
|
7028
|
-
const info = await fetchPackage(source.name, {
|
|
7029
|
-
...source.version ? { version: source.version } : {},
|
|
6617
|
+
async function loadSchema(resolved, context2) {
|
|
6618
|
+
const info = await readStepPackageInfo(resolved, {
|
|
6619
|
+
configDir: context2.configDir,
|
|
7030
6620
|
client: CLIENT_HEADER
|
|
7031
6621
|
});
|
|
7032
6622
|
return {
|
|
@@ -7037,7 +6627,7 @@ async function loadSchema(source, context2) {
|
|
|
7037
6627
|
};
|
|
7038
6628
|
}
|
|
7039
6629
|
function compileSettings(settings) {
|
|
7040
|
-
if (!
|
|
6630
|
+
if (!isObject8(settings)) return void 0;
|
|
7041
6631
|
const ajv = new Ajv({ allErrors: true, validateFormats: false });
|
|
7042
6632
|
try {
|
|
7043
6633
|
return { ok: true, validate: ajv.compile(settings) };
|
|
@@ -7045,26 +6635,26 @@ function compileSettings(settings) {
|
|
|
7045
6635
|
return { ok: false, message: getErrorMessage3(error) };
|
|
7046
6636
|
}
|
|
7047
6637
|
}
|
|
7048
|
-
function sourceKey(
|
|
7049
|
-
return
|
|
6638
|
+
function sourceKey({ packageName, spec }) {
|
|
6639
|
+
return spec.path !== void 0 ? `path:${spec.path}` : `${packageName}@${spec.version ?? "latest"}`;
|
|
7050
6640
|
}
|
|
7051
|
-
function cachedSchema(
|
|
7052
|
-
const key = sourceKey(
|
|
6641
|
+
function cachedSchema(resolved, context2) {
|
|
6642
|
+
const key = sourceKey(resolved);
|
|
7053
6643
|
let pending = context2.cache.get(key);
|
|
7054
6644
|
if (!pending) {
|
|
7055
|
-
pending = loadSchema(
|
|
6645
|
+
pending = loadSchema(resolved, context2);
|
|
7056
6646
|
context2.cache.set(key, pending);
|
|
7057
6647
|
}
|
|
7058
6648
|
return pending;
|
|
7059
6649
|
}
|
|
7060
|
-
function cachedCompile(
|
|
7061
|
-
const key = `${sourceKey(
|
|
6650
|
+
function cachedCompile(resolved, exportName, settings, context2) {
|
|
6651
|
+
const key = `${sourceKey(resolved)}#${exportName ?? ""}`;
|
|
7062
6652
|
if (context2.compiled.has(key)) return context2.compiled.get(key);
|
|
7063
6653
|
const compiled = compileSettings(settings);
|
|
7064
6654
|
context2.compiled.set(key, compiled);
|
|
7065
6655
|
return compiled;
|
|
7066
6656
|
}
|
|
7067
|
-
async function checkStepSettings(target, resolvedFlow,
|
|
6657
|
+
async function checkStepSettings(target, resolvedFlow, check, context2) {
|
|
7068
6658
|
const at = `flows.${target.flow}.${target.section}.${target.key}`;
|
|
7069
6659
|
const outcome = { findings: [], skipped: [], deferred: [] };
|
|
7070
6660
|
const spec = typeof target.entry.package === "string" ? target.entry.package : "";
|
|
@@ -7077,33 +6667,51 @@ async function checkStepSettings(target, resolvedFlow, rawFlow, check, context2)
|
|
|
7077
6667
|
});
|
|
7078
6668
|
return outcome;
|
|
7079
6669
|
}
|
|
7080
|
-
|
|
6670
|
+
let resolved;
|
|
6671
|
+
try {
|
|
6672
|
+
resolved = resolveStepPackage(
|
|
6673
|
+
resolvedFlow,
|
|
6674
|
+
SECTION_KIND[target.section],
|
|
6675
|
+
target.key,
|
|
6676
|
+
LOGGER
|
|
6677
|
+
);
|
|
6678
|
+
} catch (error) {
|
|
6679
|
+
outcome.skipped.push({
|
|
6680
|
+
path: at,
|
|
6681
|
+
check,
|
|
6682
|
+
reason: `Schema for ${spec} could not be loaded: ${getErrorMessage3(error)}`,
|
|
6683
|
+
code: "SCHEMA_UNAVAILABLE"
|
|
6684
|
+
});
|
|
6685
|
+
return outcome;
|
|
6686
|
+
}
|
|
6687
|
+
const { label } = resolved;
|
|
6688
|
+
const pinned = resolved.spec.path === void 0 ? resolved.spec.version : void 0;
|
|
7081
6689
|
let schema;
|
|
7082
6690
|
try {
|
|
7083
|
-
schema = await cachedSchema(
|
|
6691
|
+
schema = await cachedSchema(resolved, context2);
|
|
7084
6692
|
} catch (error) {
|
|
7085
6693
|
outcome.skipped.push({
|
|
7086
6694
|
path: at,
|
|
7087
6695
|
check,
|
|
7088
|
-
reason: `Schema for ${
|
|
6696
|
+
reason: `Schema for ${label}${pinned ? `@${pinned}` : ""} could not be loaded: ${getErrorMessage3(error)}`,
|
|
7089
6697
|
code: "SCHEMA_UNAVAILABLE"
|
|
7090
6698
|
});
|
|
7091
6699
|
return outcome;
|
|
7092
6700
|
}
|
|
7093
6701
|
outcome.checked = {
|
|
7094
6702
|
path: at,
|
|
7095
|
-
package:
|
|
6703
|
+
package: label,
|
|
7096
6704
|
...schema.version ? { version: schema.version } : {}
|
|
7097
6705
|
};
|
|
7098
6706
|
const { exportName } = resolveExportName(
|
|
7099
|
-
|
|
6707
|
+
resolved.normalizedFlow,
|
|
7100
6708
|
SECTION_KIND[target.section],
|
|
7101
6709
|
target.key
|
|
7102
6710
|
);
|
|
7103
|
-
const version = schema.version ??
|
|
6711
|
+
const version = schema.version ?? pinned;
|
|
7104
6712
|
const selection = selectSettingsSchema(
|
|
7105
6713
|
schema,
|
|
7106
|
-
version ? `${
|
|
6714
|
+
version ? `${label}@${version}` : label,
|
|
7107
6715
|
exportName
|
|
7108
6716
|
);
|
|
7109
6717
|
if (!selection.ok) {
|
|
@@ -7116,7 +6724,7 @@ async function checkStepSettings(target, resolvedFlow, rawFlow, check, context2)
|
|
|
7116
6724
|
return outcome;
|
|
7117
6725
|
}
|
|
7118
6726
|
const compiled = cachedCompile(
|
|
7119
|
-
|
|
6727
|
+
resolved,
|
|
7120
6728
|
exportName,
|
|
7121
6729
|
selection.settings,
|
|
7122
6730
|
context2
|
|
@@ -7125,7 +6733,7 @@ async function checkStepSettings(target, resolvedFlow, rawFlow, check, context2)
|
|
|
7125
6733
|
outcome.skipped.push({
|
|
7126
6734
|
path: at,
|
|
7127
6735
|
check,
|
|
7128
|
-
reason: `Package ${
|
|
6736
|
+
reason: `Package ${label} has no settings schema`,
|
|
7129
6737
|
code: "NO_SETTINGS_SCHEMA"
|
|
7130
6738
|
});
|
|
7131
6739
|
return outcome;
|
|
@@ -7134,14 +6742,14 @@ async function checkStepSettings(target, resolvedFlow, rawFlow, check, context2)
|
|
|
7134
6742
|
outcome.skipped.push({
|
|
7135
6743
|
path: at,
|
|
7136
6744
|
check,
|
|
7137
|
-
reason: `The settings schema of ${
|
|
6745
|
+
reason: `The settings schema of ${label} cannot be compiled: ${compiled.message}`,
|
|
7138
6746
|
code: "SCHEMA_UNAVAILABLE"
|
|
7139
6747
|
});
|
|
7140
6748
|
return outcome;
|
|
7141
6749
|
}
|
|
7142
6750
|
const validate2 = compiled.validate;
|
|
7143
6751
|
const step = stepOf(resolvedFlow, target.section, target.key);
|
|
7144
|
-
const config =
|
|
6752
|
+
const config = isObject8(step?.config) ? step.config : {};
|
|
7145
6753
|
const prepared = prepareSettings(config.settings ?? {});
|
|
7146
6754
|
const base = `${at}.config.settings`;
|
|
7147
6755
|
for (const { segments, reference } of prepared.deferred) {
|
|
@@ -7188,7 +6796,9 @@ var { validateFlowConfig: validateFlowConfig2 } = schemas4;
|
|
|
7188
6796
|
var DEPRECATED_PACKAGES = {
|
|
7189
6797
|
"@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."
|
|
7190
6798
|
};
|
|
7191
|
-
var
|
|
6799
|
+
var STEP_KINDS2 = [
|
|
6800
|
+
["sources", "Source"],
|
|
6801
|
+
["transformers", "Transformer"],
|
|
7192
6802
|
["destinations", "Destination"],
|
|
7193
6803
|
["stores", "Store"]
|
|
7194
6804
|
];
|
|
@@ -7220,24 +6830,22 @@ async function validateFlowWithPackages(input, options = {}) {
|
|
|
7220
6830
|
continue;
|
|
7221
6831
|
}
|
|
7222
6832
|
for (const section of ENTRY_SECTIONS) {
|
|
7223
|
-
const steps =
|
|
6833
|
+
const steps = isObject9(rawFlow[section]) ? rawFlow[section] : {};
|
|
7224
6834
|
for (const [key, entry] of Object.entries(steps)) {
|
|
7225
|
-
if (!
|
|
6835
|
+
if (!isObject9(entry) || entry.package === void 0) continue;
|
|
7226
6836
|
const target = { flow: name, section, key, entry };
|
|
7227
6837
|
pending.push(
|
|
7228
|
-
checkStepSettings(
|
|
7229
|
-
target,
|
|
7230
|
-
flow,
|
|
7231
|
-
rawFlow,
|
|
7232
|
-
"flow:package-settings",
|
|
7233
|
-
context2
|
|
7234
|
-
)
|
|
6838
|
+
checkStepSettings(target, flow, "flow:package-settings", context2)
|
|
7235
6839
|
);
|
|
7236
6840
|
}
|
|
7237
6841
|
}
|
|
7238
6842
|
}
|
|
7239
6843
|
for (const outcome of await Promise.all(pending)) {
|
|
7240
|
-
|
|
6844
|
+
for (const finding of outcome.findings) {
|
|
6845
|
+
if (finding.keyword === "additionalProperties")
|
|
6846
|
+
result.errors.push(finding);
|
|
6847
|
+
else result.warnings.push(finding);
|
|
6848
|
+
}
|
|
7241
6849
|
run.skipped.push(...outcome.skipped);
|
|
7242
6850
|
deferred.push(...outcome.deferred);
|
|
7243
6851
|
if (outcome.checked) packages.push(outcome.checked);
|
|
@@ -7245,6 +6853,7 @@ async function validateFlowWithPackages(input, options = {}) {
|
|
|
7245
6853
|
result.details.scope = describeScope(scope, run.checks);
|
|
7246
6854
|
result.details.deferred = [...result.details.deferred ?? [], ...deferred];
|
|
7247
6855
|
if (packages.length > 0) result.details.packages = packages;
|
|
6856
|
+
result.valid = result.errors.length === 0;
|
|
7248
6857
|
return result;
|
|
7249
6858
|
}
|
|
7250
6859
|
function runFlowChecks(input, options) {
|
|
@@ -7281,9 +6890,9 @@ function runFlowChecks(input, options) {
|
|
|
7281
6890
|
};
|
|
7282
6891
|
}
|
|
7283
6892
|
errors.push(...scope.errors);
|
|
7284
|
-
const config =
|
|
6893
|
+
const config = isObject9(input) ? input : {};
|
|
7285
6894
|
const flowsValue = config.flows;
|
|
7286
|
-
const flows =
|
|
6895
|
+
const flows = isObject9(flowsValue) ? flowsValue : void 0;
|
|
7287
6896
|
const allFlows = scope.allFlows;
|
|
7288
6897
|
const inScope = (path23) => {
|
|
7289
6898
|
const flow = flowOfPath(path23, allFlows);
|
|
@@ -7303,8 +6912,13 @@ function runFlowChecks(input, options) {
|
|
|
7303
6912
|
for (const issue of coreResult.errors) {
|
|
7304
6913
|
const path23 = issue.path || "root";
|
|
7305
6914
|
if (!inScope(path23)) continue;
|
|
7306
|
-
if (path23 === "contract" && contractErrors > 0)
|
|
7307
|
-
|
|
6915
|
+
if ((path23 === "contract" || path23.startsWith("contract.")) && contractErrors > 0)
|
|
6916
|
+
continue;
|
|
6917
|
+
errors.push({
|
|
6918
|
+
path: path23,
|
|
6919
|
+
message: issue.message,
|
|
6920
|
+
code: issue.code ?? "SCHEMA_VALIDATION"
|
|
6921
|
+
});
|
|
7308
6922
|
}
|
|
7309
6923
|
for (const issue of coreResult.warnings) {
|
|
7310
6924
|
const path23 = issue.path || "root";
|
|
@@ -7321,13 +6935,13 @@ function runFlowChecks(input, options) {
|
|
|
7321
6935
|
checks.push("flow:steps");
|
|
7322
6936
|
for (const flowName of scope.flows) {
|
|
7323
6937
|
const flowValue = flows?.[flowName];
|
|
7324
|
-
if (!
|
|
6938
|
+
if (!isObject9(flowValue)) continue;
|
|
7325
6939
|
const transformersValue = flowValue.transformers;
|
|
7326
|
-
if (
|
|
6940
|
+
if (isObject9(transformersValue)) {
|
|
7327
6941
|
for (const [name, transformerValue] of Object.entries(
|
|
7328
6942
|
transformersValue
|
|
7329
6943
|
)) {
|
|
7330
|
-
if (!
|
|
6944
|
+
if (!isObject9(transformerValue)) continue;
|
|
7331
6945
|
const result2 = validateStepEntry(transformerValue, "Transformer");
|
|
7332
6946
|
if (!result2.ok) {
|
|
7333
6947
|
errors.push({
|
|
@@ -7338,20 +6952,13 @@ function runFlowChecks(input, options) {
|
|
|
7338
6952
|
}
|
|
7339
6953
|
}
|
|
7340
6954
|
}
|
|
7341
|
-
for (const [section, kind] of
|
|
6955
|
+
for (const [section, kind] of STEP_KINDS2) {
|
|
7342
6956
|
const steps = flowValue[section];
|
|
7343
|
-
if (!
|
|
6957
|
+
if (!isObject9(steps)) continue;
|
|
7344
6958
|
for (const [name, step] of Object.entries(steps)) {
|
|
7345
|
-
if (!
|
|
6959
|
+
if (!isObject9(step)) continue;
|
|
7346
6960
|
const at = `flows.${flowName}.${section}.${name}`;
|
|
7347
|
-
|
|
7348
|
-
warnings.push({
|
|
7349
|
-
path: `${at}.${key}`,
|
|
7350
|
-
message: `Unknown key "${key}" on ${kind} is ignored by the runtime`,
|
|
7351
|
-
suggestion: "Remove the key, or move it to where it belongs.",
|
|
7352
|
-
code: "UNKNOWN_KEY"
|
|
7353
|
-
});
|
|
7354
|
-
}
|
|
6961
|
+
errors.push(...checkStepKeys(step, kind, at));
|
|
7355
6962
|
const pkg = step.package;
|
|
7356
6963
|
if (typeof pkg === "string" && pkg in DEPRECATED_PACKAGES) {
|
|
7357
6964
|
warnings.push({
|
|
@@ -7362,6 +6969,7 @@ function runFlowChecks(input, options) {
|
|
|
7362
6969
|
}
|
|
7363
6970
|
}
|
|
7364
6971
|
}
|
|
6972
|
+
checkWebLoggerFormat(flowName, flowValue, errors);
|
|
7365
6973
|
}
|
|
7366
6974
|
if (flows) {
|
|
7367
6975
|
details.flowNames = allFlows;
|
|
@@ -7371,15 +6979,15 @@ function runFlowChecks(input, options) {
|
|
|
7371
6979
|
let totalPackageCount = 0;
|
|
7372
6980
|
for (const flowName of scope.flows) {
|
|
7373
6981
|
const flowValue = flows?.[flowName];
|
|
7374
|
-
if (!
|
|
6982
|
+
if (!isObject9(flowValue)) continue;
|
|
7375
6983
|
const flowConfig = flowValue.config;
|
|
7376
|
-
if (!
|
|
6984
|
+
if (!isObject9(flowConfig)) continue;
|
|
7377
6985
|
const bundle2 = flowConfig.bundle;
|
|
7378
|
-
if (!
|
|
6986
|
+
if (!isObject9(bundle2)) continue;
|
|
7379
6987
|
const packages = bundle2.packages;
|
|
7380
|
-
if (!
|
|
6988
|
+
if (!isObject9(packages)) continue;
|
|
7381
6989
|
for (const [pkgName, pkgConfigValue] of Object.entries(packages)) {
|
|
7382
|
-
if (!
|
|
6990
|
+
if (!isObject9(pkgConfigValue)) continue;
|
|
7383
6991
|
if (!pkgConfigValue.version && !pkgConfigValue.path) {
|
|
7384
6992
|
warnings.push({
|
|
7385
6993
|
path: `flows.${flowName}.config.bundle.packages.${pkgName}`,
|
|
@@ -7425,7 +7033,7 @@ function runFlowChecks(input, options) {
|
|
|
7425
7033
|
}
|
|
7426
7034
|
};
|
|
7427
7035
|
perFlow(["flow:structure"], (name, flow, file) => {
|
|
7428
|
-
const structure =
|
|
7036
|
+
const structure = validateFlowStructure2({
|
|
7429
7037
|
...file,
|
|
7430
7038
|
flows: { [name]: flow }
|
|
7431
7039
|
});
|
|
@@ -7467,13 +7075,13 @@ function runFlowChecks(input, options) {
|
|
|
7467
7075
|
warnings,
|
|
7468
7076
|
options.strict === true,
|
|
7469
7077
|
skipped,
|
|
7470
|
-
|
|
7078
|
+
isObject9(resolvedConfig) && isObject9(resolvedConfig.settings) ? resolvedConfig.settings : void 0
|
|
7471
7079
|
);
|
|
7472
7080
|
}
|
|
7473
7081
|
for (const [destName, dest] of Object.entries(flow.destinations || {})) {
|
|
7474
|
-
if (!
|
|
7082
|
+
if (!isObject9(dest.config)) continue;
|
|
7475
7083
|
const mapping = dest.config.mapping;
|
|
7476
|
-
if (!
|
|
7084
|
+
if (!isObject9(mapping)) continue;
|
|
7477
7085
|
for (const key of Object.keys(mapping)) {
|
|
7478
7086
|
if (key.includes(".") && !key.includes(" ")) {
|
|
7479
7087
|
const parts = key.split(".");
|
|
@@ -7533,16 +7141,31 @@ function checkResolvedWindowCollector(name, raw, flow, errors, deferred) {
|
|
|
7533
7141
|
code: "SCHEMA_VALIDATION"
|
|
7534
7142
|
});
|
|
7535
7143
|
}
|
|
7536
|
-
function
|
|
7537
|
-
|
|
7538
|
-
const
|
|
7539
|
-
|
|
7540
|
-
|
|
7541
|
-
|
|
7542
|
-
|
|
7543
|
-
|
|
7144
|
+
function checkWebLoggerFormat(flowName, flow, errors) {
|
|
7145
|
+
if (!isObject9(flow.config) || flow.config.platform !== "web") return;
|
|
7146
|
+
const at = `flows.${flowName}`;
|
|
7147
|
+
const loggers = [];
|
|
7148
|
+
if (isObject9(flow.collector))
|
|
7149
|
+
loggers.push([`${at}.collector.logger`, flow.collector.logger]);
|
|
7150
|
+
for (const [section] of STEP_KINDS2) {
|
|
7151
|
+
const steps = flow[section];
|
|
7152
|
+
if (!isObject9(steps)) continue;
|
|
7153
|
+
for (const [name, step] of Object.entries(steps)) {
|
|
7154
|
+
if (isObject9(step) && isObject9(step.config))
|
|
7155
|
+
loggers.push([
|
|
7156
|
+
`${at}.${section}.${name}.config.logger`,
|
|
7157
|
+
step.config.logger
|
|
7158
|
+
]);
|
|
7159
|
+
}
|
|
7160
|
+
}
|
|
7161
|
+
for (const [path23, logger] of loggers) {
|
|
7162
|
+
if (!isObject9(logger) || logger.format === void 0) continue;
|
|
7163
|
+
errors.push({
|
|
7164
|
+
path: `${path23}.format`,
|
|
7165
|
+
message: "logger.format applies to server flows only: a web flow logs to the browser console, which has no output format. Remove it.",
|
|
7166
|
+
code: "WEB_LOGGER_FORMAT"
|
|
7167
|
+
});
|
|
7544
7168
|
}
|
|
7545
|
-
return unknown;
|
|
7546
7169
|
}
|
|
7547
7170
|
function routeTargets(spec) {
|
|
7548
7171
|
if (spec === void 0) return [];
|
|
@@ -7641,21 +7264,21 @@ function isStepOut(value) {
|
|
|
7641
7264
|
return Array.isArray(value) && value.every((entry) => Array.isArray(entry) && typeof entry[0] === "string");
|
|
7642
7265
|
}
|
|
7643
7266
|
function returnedEvents(value) {
|
|
7644
|
-
if (
|
|
7267
|
+
if (isObject9(value)) return [isObject9(value.event) ? value.event : value];
|
|
7645
7268
|
if (Array.isArray(value)) return value.flatMap(returnedEvents);
|
|
7646
7269
|
return [];
|
|
7647
7270
|
}
|
|
7648
7271
|
function outEvents(out) {
|
|
7649
7272
|
if (isStepOut(out)) {
|
|
7650
7273
|
return out.flatMap(([head, first]) => {
|
|
7651
|
-
if (head === "elb") return
|
|
7274
|
+
if (head === "elb") return isObject9(first) ? [first] : [];
|
|
7652
7275
|
if (head === "return") return returnedEvents(first);
|
|
7653
7276
|
return [];
|
|
7654
7277
|
});
|
|
7655
7278
|
}
|
|
7656
7279
|
if (Array.isArray(out) || typeof out === "string")
|
|
7657
7280
|
return out.length > 0 ? [out] : [];
|
|
7658
|
-
return
|
|
7281
|
+
return isObject9(out) && Object.keys(out).length > 0 ? [out] : [];
|
|
7659
7282
|
}
|
|
7660
7283
|
function hasComparableOut(out) {
|
|
7661
7284
|
return outEvents(out).length > 0;
|
|
@@ -7697,7 +7320,7 @@ function routeAt(spec, path23) {
|
|
|
7697
7320
|
for (const key of path23) {
|
|
7698
7321
|
if (typeof key === "number")
|
|
7699
7322
|
current = Array.isArray(current) ? current[key] : void 0;
|
|
7700
|
-
else current =
|
|
7323
|
+
else current = isObject9(current) ? current[key] : void 0;
|
|
7701
7324
|
}
|
|
7702
7325
|
return current;
|
|
7703
7326
|
}
|
|
@@ -7722,7 +7345,7 @@ function lintRoute(spec, position, known, errors, warnings) {
|
|
|
7722
7345
|
if (node.stop && !node.match && node.kind !== "many") {
|
|
7723
7346
|
const self = routeAt(spec, node.path);
|
|
7724
7347
|
const list = routeAt(spec, node.path.slice(0, -1));
|
|
7725
|
-
if (
|
|
7348
|
+
if (isObject9(self) && self.stop === true && typeof last === "number" && Array.isArray(list) && last < list.length - 1 && once2(`stop:${where(node.path)}`)) {
|
|
7726
7349
|
const at = where(node.path);
|
|
7727
7350
|
warnings.push({
|
|
7728
7351
|
path: at,
|
|
@@ -7770,6 +7393,12 @@ function lintRoute(spec, position, known, errors, warnings) {
|
|
|
7770
7393
|
}
|
|
7771
7394
|
}
|
|
7772
7395
|
}
|
|
7396
|
+
function hasRuntimeValue(value) {
|
|
7397
|
+
if (typeof value === "string")
|
|
7398
|
+
return value.includes(ENV_MARKER_PREFIX3) || value.startsWith(SECRET_MARKER_PREFIX4) || /\$(?:env|secret)\./.test(value);
|
|
7399
|
+
if (Array.isArray(value)) return value.some(hasRuntimeValue);
|
|
7400
|
+
return isObject9(value) && Object.values(value).some(hasRuntimeValue);
|
|
7401
|
+
}
|
|
7773
7402
|
var VALIDATE_PACKAGE = "@walkeros/transformer-validate";
|
|
7774
7403
|
function isValidateStep(step) {
|
|
7775
7404
|
return step.package === VALIDATE_PACKAGE;
|
|
@@ -7788,7 +7417,7 @@ function resolveStepContracts(entries, contract) {
|
|
|
7788
7417
|
}
|
|
7789
7418
|
const sources = [];
|
|
7790
7419
|
for (const [index, entry] of entries.entries()) {
|
|
7791
|
-
if (
|
|
7420
|
+
if (isObject9(entry)) {
|
|
7792
7421
|
sources.push(entry);
|
|
7793
7422
|
continue;
|
|
7794
7423
|
}
|
|
@@ -7806,7 +7435,7 @@ function resolveStepContracts(entries, contract) {
|
|
|
7806
7435
|
message: `contract "${match[1]}" is not defined in the root contract (defined: ${Object.keys(resolved).join(", ") || "none"})`
|
|
7807
7436
|
};
|
|
7808
7437
|
const rule = match[2] ? getByPath(resolved[match[1]], match[2]) : resolved[match[1]];
|
|
7809
|
-
if (!
|
|
7438
|
+
if (!isObject9(rule))
|
|
7810
7439
|
return {
|
|
7811
7440
|
ok: false,
|
|
7812
7441
|
index,
|
|
@@ -7817,7 +7446,7 @@ function resolveStepContracts(entries, contract) {
|
|
|
7817
7446
|
return { ok: true, sources };
|
|
7818
7447
|
}
|
|
7819
7448
|
function checkValidateStepExamples(stepPath, step, contract, errors, warnings, strict, skipped, resolvedSettings) {
|
|
7820
|
-
const settings = resolvedSettings ?? (
|
|
7449
|
+
const settings = resolvedSettings ?? (isObject9(step.config) && isObject9(step.config.settings) ? step.config.settings : {});
|
|
7821
7450
|
const contractPath = `${stepPath}.config.settings.contract`;
|
|
7822
7451
|
if (settings.contract !== void 0 && !Array.isArray(settings.contract)) {
|
|
7823
7452
|
if (step.examples)
|
|
@@ -7840,12 +7469,21 @@ function checkValidateStepExamples(stepPath, step, contract, errors, warnings, s
|
|
|
7840
7469
|
}
|
|
7841
7470
|
if (!step.examples) return;
|
|
7842
7471
|
const contracts = resolution.sources;
|
|
7472
|
+
if (contracts.some(hasRuntimeValue)) {
|
|
7473
|
+
skipped?.push({
|
|
7474
|
+
path: stepPath,
|
|
7475
|
+
check: "flow:contract-examples",
|
|
7476
|
+
reason: "the contract uses a $env or $secret value, known only when the bundle builds or runs, so the examples cannot be judged statically",
|
|
7477
|
+
code: "CONTRACT_NOT_STATIC"
|
|
7478
|
+
});
|
|
7479
|
+
return;
|
|
7480
|
+
}
|
|
7843
7481
|
const mode = settings.mode === "strict" ? "strict" : "pass";
|
|
7844
7482
|
const format = settings.format === true;
|
|
7845
|
-
const output =
|
|
7483
|
+
const output = isObject9(settings.output) ? settings.output : {};
|
|
7846
7484
|
const isValidPath = typeof output.isValid === "string" ? output.isValid : "source.valid";
|
|
7847
7485
|
for (const [exName, example] of Object.entries(step.examples)) {
|
|
7848
|
-
if (example.command || !
|
|
7486
|
+
if (example.command || !isObject9(example.in)) continue;
|
|
7849
7487
|
if (example.out === void 0) continue;
|
|
7850
7488
|
const event = example.in;
|
|
7851
7489
|
const verdict = validateEventAgainstContract(event, void 0, {
|
|
@@ -7883,14 +7521,14 @@ function checkValidateStepExamples(stepPath, step, contract, errors, warnings, s
|
|
|
7883
7521
|
}
|
|
7884
7522
|
|
|
7885
7523
|
// src/commands/validate/validators/mapping.ts
|
|
7886
|
-
import { isObject as
|
|
7524
|
+
import { isObject as isObject10 } from "@walkeros/core";
|
|
7887
7525
|
import { schemas as schemas5 } from "@walkeros/core/dev";
|
|
7888
7526
|
var { RuleSchema } = schemas5.MappingSchemas;
|
|
7889
7527
|
function isRule(value) {
|
|
7890
|
-
return
|
|
7528
|
+
return isObject10(value) && RuleSchema.safeParse(value).success;
|
|
7891
7529
|
}
|
|
7892
7530
|
function isNestedActions(key, value) {
|
|
7893
|
-
if (key.includes(" ") || !
|
|
7531
|
+
if (key.includes(" ") || !isObject10(value)) return false;
|
|
7894
7532
|
const rules = Object.values(value);
|
|
7895
7533
|
return rules.length > 0 && rules.every(
|
|
7896
7534
|
(rule) => Array.isArray(rule) ? rule.length > 0 && rule.every(isRule) : isRule(rule)
|
|
@@ -7900,7 +7538,7 @@ function validateMapping(input) {
|
|
|
7900
7538
|
const errors = [];
|
|
7901
7539
|
const warnings = [];
|
|
7902
7540
|
const details = {};
|
|
7903
|
-
if (!
|
|
7541
|
+
if (!isObject10(input)) {
|
|
7904
7542
|
errors.push({
|
|
7905
7543
|
path: "root",
|
|
7906
7544
|
message: "Mapping must be an object with event patterns as keys",
|
|
@@ -7989,7 +7627,6 @@ async function validateEntry(path23, flowConfig, options = {}) {
|
|
|
7989
7627
|
const outcome = await checkStepSettings(
|
|
7990
7628
|
target,
|
|
7991
7629
|
resolution.flow,
|
|
7992
|
-
file?.flows[target.flow],
|
|
7993
7630
|
"entry:settings",
|
|
7994
7631
|
context2
|
|
7995
7632
|
);
|
|
@@ -8046,6 +7683,7 @@ var VALIDATE_CODES = [
|
|
|
8046
7683
|
"CONTRACT_VIOLATION",
|
|
8047
7684
|
"MAPPING_DOT_KEY",
|
|
8048
7685
|
"FLOW_REF_WARNING",
|
|
7686
|
+
"WEB_LOGGER_FORMAT",
|
|
8049
7687
|
"FLOW_CYCLE",
|
|
8050
7688
|
"VAR_CYCLE",
|
|
8051
7689
|
// Structure (the bundler's own preflight, validateFlowStructure)
|
|
@@ -8054,7 +7692,11 @@ var VALIDATE_CODES = [
|
|
|
8054
7692
|
"STORE_REFERENCE_NOT_FOUND",
|
|
8055
7693
|
"STATE_STORE_UNKNOWN",
|
|
8056
7694
|
"STATE_STORE_FILE",
|
|
8057
|
-
"
|
|
7695
|
+
"MAPPING_NO_OP",
|
|
7696
|
+
"MAPPING_VALUE_NO_OPERATOR",
|
|
7697
|
+
"MAPPING_VALUE_PRODUCERS",
|
|
7698
|
+
"BATCH_WITHOUT_PUSH_BATCH",
|
|
7699
|
+
"MALFORMED_REFERENCE",
|
|
8058
7700
|
// Resolution (getFlowSettings, as the bundler resolves the flow)
|
|
8059
7701
|
"UNRESOLVED_REFERENCE",
|
|
8060
7702
|
"MISSING_ENV",
|
|
@@ -8071,7 +7713,6 @@ var VALIDATE_CODES = [
|
|
|
8071
7713
|
"INVALID_TAGGING",
|
|
8072
7714
|
"INVALID_SCHEMA",
|
|
8073
7715
|
"INVALID_EXTENDS",
|
|
8074
|
-
"INVALID_SECTION",
|
|
8075
7716
|
"INVALID_EVENTS",
|
|
8076
7717
|
"CIRCULAR_EXTENDS",
|
|
8077
7718
|
"INVALID_ENTITY_KEY",
|
|
@@ -8126,7 +7767,7 @@ function inapplicableOptions(type, options) {
|
|
|
8126
7767
|
}
|
|
8127
7768
|
function validateContractInput(input) {
|
|
8128
7769
|
if (!isFlowJson2(input)) return validateContract(input);
|
|
8129
|
-
const contract =
|
|
7770
|
+
const contract = isObject11(input) ? input.contract : void 0;
|
|
8130
7771
|
if (contract === void 0) {
|
|
8131
7772
|
return {
|
|
8132
7773
|
valid: false,
|
|
@@ -8346,191 +7987,8 @@ function exitCodeOf(result, strict) {
|
|
|
8346
7987
|
return result.valid ? 0 : 1;
|
|
8347
7988
|
}
|
|
8348
7989
|
|
|
8349
|
-
// src/commands/login/index.ts
|
|
8350
|
-
import { z as z3 } from "zod";
|
|
8351
|
-
var POLL_TIMEOUT_BUFFER_MS = 5e3;
|
|
8352
|
-
var DEFAULT_POLL_INTERVAL_MS = 5e3;
|
|
8353
|
-
var MIN_SERVER_POLL_INTERVAL_MS = 1e3;
|
|
8354
|
-
var DEFAULT_POLL_TIMEOUT_MS = 9e5;
|
|
8355
|
-
var SLOW_DOWN_STEP_MS = 5e3;
|
|
8356
|
-
var WHOAMI_TIMEOUT_MS = 1e4;
|
|
8357
|
-
var TIMED_OUT = "Authorization timed out. Please try again.";
|
|
8358
|
-
var WhoamiSchema = z3.object({ email: z3.string().min(1) });
|
|
8359
|
-
async function openInBrowser(url) {
|
|
8360
|
-
const { default: open } = await import("open");
|
|
8361
|
-
await open(url);
|
|
8362
|
-
}
|
|
8363
|
-
function delay3(ms) {
|
|
8364
|
-
return new Promise((resolve5) => setTimeout(resolve5, ms));
|
|
8365
|
-
}
|
|
8366
|
-
async function loginCommand(options) {
|
|
8367
|
-
const logger = createCLILogger(options);
|
|
8368
|
-
try {
|
|
8369
|
-
const result = await login({ url: options.url });
|
|
8370
|
-
if (options.json) {
|
|
8371
|
-
logger.json(result);
|
|
8372
|
-
} else if (result.success) {
|
|
8373
|
-
if (result.email) logger.info(`Logged in as ${result.email}`);
|
|
8374
|
-
else logger.info("Logged in.");
|
|
8375
|
-
logger.info(`Session stored in ${result.configPath}`);
|
|
8376
|
-
} else if (result.error) {
|
|
8377
|
-
logger.error(result.error);
|
|
8378
|
-
}
|
|
8379
|
-
process.exit(result.success ? 0 : 1);
|
|
8380
|
-
} catch (error) {
|
|
8381
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
8382
|
-
if (options.json) {
|
|
8383
|
-
logger.json({ success: false, error: message });
|
|
8384
|
-
} else {
|
|
8385
|
-
logger.error(message);
|
|
8386
|
-
}
|
|
8387
|
-
process.exit(1);
|
|
8388
|
-
}
|
|
8389
|
-
}
|
|
8390
|
-
async function fetchEmail(appUrl, accessToken, fetchFn) {
|
|
8391
|
-
try {
|
|
8392
|
-
const response = await appFetch(APP_PATHS.whoami, {
|
|
8393
|
-
baseUrl: appUrl,
|
|
8394
|
-
token: accessToken,
|
|
8395
|
-
fetch: fetchFn,
|
|
8396
|
-
signal: AbortSignal.timeout(WHOAMI_TIMEOUT_MS)
|
|
8397
|
-
});
|
|
8398
|
-
if (!response.ok) return void 0;
|
|
8399
|
-
const parsed = WhoamiSchema.safeParse(await response.json());
|
|
8400
|
-
return parsed.success ? parsed.data.email : void 0;
|
|
8401
|
-
} catch {
|
|
8402
|
-
return void 0;
|
|
8403
|
-
}
|
|
8404
|
-
}
|
|
8405
|
-
async function persistSession(appUrl, tokens, fetchFn) {
|
|
8406
|
-
writeConfig({
|
|
8407
|
-
accessToken: tokens.accessToken,
|
|
8408
|
-
accessTokenExpiresAt: tokens.accessTokenExpiresAt,
|
|
8409
|
-
refreshToken: tokens.refreshToken ?? void 0,
|
|
8410
|
-
appUrl,
|
|
8411
|
-
// Drop the static token this session replaces, so the deprecated path
|
|
8412
|
-
// cannot outlive the login that retired it.
|
|
8413
|
-
token: void 0
|
|
8414
|
-
});
|
|
8415
|
-
const email = await fetchEmail(appUrl, tokens.accessToken, fetchFn);
|
|
8416
|
-
writeConfig({ email });
|
|
8417
|
-
}
|
|
8418
|
-
async function completeDeviceLogin(deviceCode, options = {}) {
|
|
8419
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
8420
|
-
const appUrl = requireSecureUrl(options.url || resolveAppUrl());
|
|
8421
|
-
const deadline = Date.now() + (options.timeoutMs ?? DEFAULT_POLL_TIMEOUT_MS);
|
|
8422
|
-
let intervalMs = options.intervalMs ?? DEFAULT_POLL_INTERVAL_MS;
|
|
8423
|
-
let attempts = 0;
|
|
8424
|
-
let waiting = "pending";
|
|
8425
|
-
while (Date.now() + intervalMs <= deadline) {
|
|
8426
|
-
if (options.maxPollAttempts !== void 0 && attempts >= options.maxPollAttempts)
|
|
8427
|
-
break;
|
|
8428
|
-
attempts += 1;
|
|
8429
|
-
await delay3(intervalMs);
|
|
8430
|
-
const signal = AbortSignal.timeout(Math.max(1, deadline - Date.now()));
|
|
8431
|
-
const poll = await pollDeviceToken(appUrl, deviceCode, fetchFn, signal);
|
|
8432
|
-
if (poll.status === "pending") {
|
|
8433
|
-
waiting = "pending";
|
|
8434
|
-
if (signal.aborted) break;
|
|
8435
|
-
continue;
|
|
8436
|
-
}
|
|
8437
|
-
if (poll.status === "slow_down") {
|
|
8438
|
-
waiting = "slow_down";
|
|
8439
|
-
intervalMs += SLOW_DOWN_STEP_MS;
|
|
8440
|
-
continue;
|
|
8441
|
-
}
|
|
8442
|
-
if (poll.status !== "ok") return poll;
|
|
8443
|
-
await persistSession(appUrl, poll.tokens, fetchFn);
|
|
8444
|
-
return { status: "ok" };
|
|
8445
|
-
}
|
|
8446
|
-
return { status: waiting };
|
|
8447
|
-
}
|
|
8448
|
-
async function login(options = {}) {
|
|
8449
|
-
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
8450
|
-
const appUrl = requireSecureUrl(options.url || resolveAppUrl());
|
|
8451
|
-
let authorization;
|
|
8452
|
-
try {
|
|
8453
|
-
authorization = await startDeviceAuthorization(appUrl, fetchFn);
|
|
8454
|
-
} catch {
|
|
8455
|
-
return { success: false, error: "Failed to request device code" };
|
|
8456
|
-
}
|
|
8457
|
-
const target = authorization.verificationUriComplete;
|
|
8458
|
-
const prompt = (message) => process.stderr.write(message + "\n");
|
|
8459
|
-
prompt(`
|
|
8460
|
-
! Your one-time code: ${authorization.userCode}`);
|
|
8461
|
-
prompt(` Authorize here: ${target}
|
|
8462
|
-
`);
|
|
8463
|
-
const opener = options.openUrl ?? openInBrowser;
|
|
8464
|
-
try {
|
|
8465
|
-
await opener(target);
|
|
8466
|
-
prompt(" Opening browser...");
|
|
8467
|
-
} catch {
|
|
8468
|
-
prompt(" Could not open browser. Visit the URL manually.");
|
|
8469
|
-
}
|
|
8470
|
-
prompt(" Waiting for authorization... (press Ctrl+C to cancel)\n");
|
|
8471
|
-
const outcome = await completeDeviceLogin(authorization.deviceCode, {
|
|
8472
|
-
url: appUrl,
|
|
8473
|
-
fetch: fetchFn,
|
|
8474
|
-
timeoutMs: authorization.expiresIn * 1e3 + POLL_TIMEOUT_BUFFER_MS,
|
|
8475
|
-
// Clamped here, at the one place a server's number enters the loop. The
|
|
8476
|
-
// helper takes its caller's interval as stated, which is what keeps a
|
|
8477
|
-
// stated 0 from becoming a poll flood without making the helper's own
|
|
8478
|
-
// option untestably slow.
|
|
8479
|
-
intervalMs: options.pollIntervalMs ?? Math.max(MIN_SERVER_POLL_INTERVAL_MS, authorization.interval * 1e3),
|
|
8480
|
-
...options.maxPollAttempts !== void 0 ? { maxPollAttempts: options.maxPollAttempts } : {}
|
|
8481
|
-
});
|
|
8482
|
-
switch (outcome.status) {
|
|
8483
|
-
case "ok": {
|
|
8484
|
-
const email = readConfig()?.email;
|
|
8485
|
-
return {
|
|
8486
|
-
success: true,
|
|
8487
|
-
...email ? { email } : {},
|
|
8488
|
-
configPath: getConfigPath()
|
|
8489
|
-
};
|
|
8490
|
-
}
|
|
8491
|
-
case "denied":
|
|
8492
|
-
return { success: false, error: "Authorization was denied." };
|
|
8493
|
-
case "error":
|
|
8494
|
-
return { success: false, error: outcome.error };
|
|
8495
|
-
default:
|
|
8496
|
-
return { success: false, error: TIMED_OUT };
|
|
8497
|
-
}
|
|
8498
|
-
}
|
|
8499
|
-
|
|
8500
|
-
// src/commands/logout/index.ts
|
|
8501
|
-
async function logoutCommand(options) {
|
|
8502
|
-
const logger = createCLILogger(options);
|
|
8503
|
-
const { deleted, superseded } = await logout();
|
|
8504
|
-
const configPath = getConfigPath();
|
|
8505
|
-
if (options.json) {
|
|
8506
|
-
logger.json({ success: true, deleted, superseded });
|
|
8507
|
-
} else if (superseded) {
|
|
8508
|
-
logger.info(
|
|
8509
|
-
"A newer session was stored while logging out, and was kept. Run `walkeros auth logout` again to remove it."
|
|
8510
|
-
);
|
|
8511
|
-
} else if (deleted) {
|
|
8512
|
-
logger.info(`Logged out. Session removed from ${configPath}`);
|
|
8513
|
-
} else {
|
|
8514
|
-
logger.info("No stored credentials found.");
|
|
8515
|
-
}
|
|
8516
|
-
process.exit(0);
|
|
8517
|
-
}
|
|
8518
|
-
function sameSession(before, after) {
|
|
8519
|
-
return before?.accessToken === after.accessToken && before?.refreshToken === after.refreshToken && before?.token === after.token;
|
|
8520
|
-
}
|
|
8521
|
-
async function logout() {
|
|
8522
|
-
const before = readConfig();
|
|
8523
|
-
if (before?.refreshToken) {
|
|
8524
|
-
await revokeRefreshToken(resolveAppUrl(), before.refreshToken);
|
|
8525
|
-
}
|
|
8526
|
-
const after = readConfig();
|
|
8527
|
-
if (after && !sameSession(before, after))
|
|
8528
|
-
return { deleted: false, superseded: true };
|
|
8529
|
-
return { deleted: deleteConfig(), superseded: false };
|
|
8530
|
-
}
|
|
8531
|
-
|
|
8532
7990
|
// src/commands/auth/index.ts
|
|
8533
|
-
import { z as
|
|
7991
|
+
import { z as z3 } from "zod";
|
|
8534
7992
|
|
|
8535
7993
|
// src/core/api-error.ts
|
|
8536
7994
|
var EXIT_RETRYABLE = 75;
|
|
@@ -8588,31 +8046,166 @@ ${err.message}
|
|
|
8588
8046
|
process.exit(1);
|
|
8589
8047
|
}
|
|
8590
8048
|
|
|
8049
|
+
// src/core/app-fetch.ts
|
|
8050
|
+
import { z } from "zod";
|
|
8051
|
+
|
|
8052
|
+
// src/lib/config-file.ts
|
|
8053
|
+
import {
|
|
8054
|
+
readFileSync as readFileSync3,
|
|
8055
|
+
writeFileSync,
|
|
8056
|
+
mkdirSync,
|
|
8057
|
+
unlinkSync,
|
|
8058
|
+
chmodSync,
|
|
8059
|
+
renameSync
|
|
8060
|
+
} from "fs";
|
|
8061
|
+
import { randomBytes } from "crypto";
|
|
8062
|
+
import { join as join5 } from "path";
|
|
8063
|
+
import { homedir } from "os";
|
|
8064
|
+
function getConfigDir() {
|
|
8065
|
+
const xdgConfig = process.env.XDG_CONFIG_HOME;
|
|
8066
|
+
const base = xdgConfig || join5(homedir(), ".config");
|
|
8067
|
+
return join5(base, "walkeros");
|
|
8068
|
+
}
|
|
8069
|
+
function getConfigPath() {
|
|
8070
|
+
return join5(getConfigDir(), "config.json");
|
|
8071
|
+
}
|
|
8072
|
+
function readConfig() {
|
|
8073
|
+
const configPath = getConfigPath();
|
|
8074
|
+
try {
|
|
8075
|
+
const content = readFileSync3(configPath, "utf-8");
|
|
8076
|
+
return JSON.parse(content);
|
|
8077
|
+
} catch {
|
|
8078
|
+
return null;
|
|
8079
|
+
}
|
|
8080
|
+
}
|
|
8081
|
+
function replaceConfigFile(config) {
|
|
8082
|
+
const dir = getConfigDir();
|
|
8083
|
+
mkdirSync(dir, { recursive: true, mode: 448 });
|
|
8084
|
+
const configPath = getConfigPath();
|
|
8085
|
+
const tempPath = `${configPath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
8086
|
+
try {
|
|
8087
|
+
writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 384 });
|
|
8088
|
+
chmodSync(tempPath, 384);
|
|
8089
|
+
renameSync(tempPath, configPath);
|
|
8090
|
+
} catch (error) {
|
|
8091
|
+
try {
|
|
8092
|
+
unlinkSync(tempPath);
|
|
8093
|
+
} catch {
|
|
8094
|
+
}
|
|
8095
|
+
throw error;
|
|
8096
|
+
}
|
|
8097
|
+
}
|
|
8098
|
+
function writeConfig(config) {
|
|
8099
|
+
replaceConfigFile({ ...readConfig() ?? {}, ...config });
|
|
8100
|
+
}
|
|
8101
|
+
function writeTelemetryOnlyConfig(partial) {
|
|
8102
|
+
writeConfig(partial);
|
|
8103
|
+
}
|
|
8104
|
+
function resolveAppUrl() {
|
|
8105
|
+
const envUrl = process.env.WALKEROS_APP_URL;
|
|
8106
|
+
if (envUrl) return envUrl;
|
|
8107
|
+
const config = readConfig();
|
|
8108
|
+
if (config?.appUrl) return config.appUrl;
|
|
8109
|
+
return "https://app.walkeros.io";
|
|
8110
|
+
}
|
|
8111
|
+
|
|
8112
|
+
// src/lib/secure-url.ts
|
|
8113
|
+
function isLoopback(hostname) {
|
|
8114
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
8115
|
+
}
|
|
8116
|
+
function requireSecureUrl(url) {
|
|
8117
|
+
let parsed;
|
|
8118
|
+
try {
|
|
8119
|
+
parsed = new URL(url);
|
|
8120
|
+
} catch {
|
|
8121
|
+
return url;
|
|
8122
|
+
}
|
|
8123
|
+
if (parsed.protocol !== "http:" || isLoopback(parsed.hostname)) return url;
|
|
8124
|
+
throw new Error(
|
|
8125
|
+
`Refusing to send walkerOS credentials over plain http to ${url}. Use https, or localhost / 127.0.0.1 / [::1] for local development.`
|
|
8126
|
+
);
|
|
8127
|
+
}
|
|
8128
|
+
|
|
8129
|
+
// src/core/client-context.ts
|
|
8130
|
+
var context;
|
|
8131
|
+
function setClientContext(input) {
|
|
8132
|
+
const envType = process.env.WALKEROS_CLIENT_TYPE;
|
|
8133
|
+
const type = envType ?? input.type ?? "cli";
|
|
8134
|
+
context = { type, version: input.version };
|
|
8135
|
+
}
|
|
8136
|
+
function getClientContext() {
|
|
8137
|
+
return context;
|
|
8138
|
+
}
|
|
8139
|
+
function resetClientContext() {
|
|
8140
|
+
context = void 0;
|
|
8141
|
+
}
|
|
8142
|
+
function clientContextHeaders() {
|
|
8143
|
+
if (!context) return {};
|
|
8144
|
+
return {
|
|
8145
|
+
"User-Agent": `walkeros-${context.type}/${context.version}`,
|
|
8146
|
+
"X-WalkerOS-Client": context.type,
|
|
8147
|
+
"X-WalkerOS-Client-Version": context.version
|
|
8148
|
+
};
|
|
8149
|
+
}
|
|
8150
|
+
|
|
8151
|
+
// src/core/app-fetch.ts
|
|
8152
|
+
var AppErrorSchema = z.object({
|
|
8153
|
+
error: z.object({ message: z.string().min(1) })
|
|
8154
|
+
});
|
|
8155
|
+
function appErrorMessage(body) {
|
|
8156
|
+
const parsed = AppErrorSchema.safeParse(body);
|
|
8157
|
+
return parsed.success ? parsed.data.error.message : void 0;
|
|
8158
|
+
}
|
|
8159
|
+
async function appFetch(path23, init = {}) {
|
|
8160
|
+
const url = `${(init.baseUrl ?? resolveAppUrl()).replace(/\/+$/, "")}${path23}`;
|
|
8161
|
+
const headers = new Headers(clientContextHeaders());
|
|
8162
|
+
for (const [name, value] of Object.entries(init.headers ?? {}))
|
|
8163
|
+
headers.set(name, value);
|
|
8164
|
+
if (init.token && !headers.has("Authorization"))
|
|
8165
|
+
headers.set("Authorization", `Bearer ${init.token}`);
|
|
8166
|
+
if (headers.has("Authorization")) requireSecureUrl(url);
|
|
8167
|
+
const request = { headers };
|
|
8168
|
+
if (init.method && init.method !== "GET") request.method = init.method;
|
|
8169
|
+
if (init.body !== void 0) request.body = init.body;
|
|
8170
|
+
if (init.signal) request.signal = init.signal;
|
|
8171
|
+
if (init.redirect) request.redirect = init.redirect;
|
|
8172
|
+
return (init.fetch ?? fetch)(url, request);
|
|
8173
|
+
}
|
|
8174
|
+
|
|
8175
|
+
// src/core/app-paths.ts
|
|
8176
|
+
var APP_PATHS = {
|
|
8177
|
+
whoami: "/api/auth/whoami",
|
|
8178
|
+
health: "/api/health",
|
|
8179
|
+
telemetry: "/api/telemetry",
|
|
8180
|
+
openapi: "/api/openapi.json"
|
|
8181
|
+
};
|
|
8182
|
+
|
|
8591
8183
|
// src/commands/api/index.ts
|
|
8592
8184
|
import { once } from "events";
|
|
8593
8185
|
import { readFile as readFile2 } from "fs/promises";
|
|
8594
|
-
import { z as
|
|
8186
|
+
import { z as z2 } from "zod";
|
|
8187
|
+
var NOT_SIGNED_IN = "no token: set WALKEROS_TOKEN to a token from Account > Automation tokens in the walkerOS app";
|
|
8595
8188
|
var ERROR_BODY_LIMIT = 64 * 1024;
|
|
8596
|
-
var DocumentSchema =
|
|
8597
|
-
paths:
|
|
8598
|
-
components:
|
|
8189
|
+
var DocumentSchema = z2.object({
|
|
8190
|
+
paths: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())),
|
|
8191
|
+
components: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())).optional()
|
|
8599
8192
|
});
|
|
8600
|
-
var OperationSchema =
|
|
8601
|
-
summary:
|
|
8602
|
-
description:
|
|
8603
|
-
parameters:
|
|
8604
|
-
requestBody:
|
|
8605
|
-
responses:
|
|
8193
|
+
var OperationSchema = z2.object({
|
|
8194
|
+
summary: z2.string().optional(),
|
|
8195
|
+
description: z2.string().optional(),
|
|
8196
|
+
parameters: z2.array(z2.unknown()).optional(),
|
|
8197
|
+
requestBody: z2.unknown().optional(),
|
|
8198
|
+
responses: z2.record(z2.string(), z2.unknown()).optional()
|
|
8606
8199
|
});
|
|
8607
|
-
var OptionsSchema =
|
|
8608
|
-
data:
|
|
8609
|
-
header:
|
|
8610
|
-
project:
|
|
8611
|
-
yes:
|
|
8200
|
+
var OptionsSchema = z2.object({
|
|
8201
|
+
data: z2.string().optional(),
|
|
8202
|
+
header: z2.array(z2.string()).default([]),
|
|
8203
|
+
project: z2.string().optional(),
|
|
8204
|
+
yes: z2.boolean().optional()
|
|
8612
8205
|
});
|
|
8613
8206
|
|
|
8614
8207
|
// src/commands/auth/index.ts
|
|
8615
|
-
async function
|
|
8208
|
+
async function readJson2(response) {
|
|
8616
8209
|
try {
|
|
8617
8210
|
return await response.json();
|
|
8618
8211
|
} catch {
|
|
@@ -8620,19 +8213,17 @@ async function readJson3(response) {
|
|
|
8620
8213
|
}
|
|
8621
8214
|
}
|
|
8622
8215
|
async function whoami() {
|
|
8623
|
-
const token =
|
|
8624
|
-
if (!token)
|
|
8625
|
-
throw new Error("Not authenticated. Run `walkeros auth login` first.");
|
|
8216
|
+
const token = resolveAccessToken();
|
|
8217
|
+
if (!token) throw new Error(NOT_SIGNED_IN);
|
|
8626
8218
|
const response = await appFetch(APP_PATHS.whoami, { token });
|
|
8627
|
-
const body = await
|
|
8219
|
+
const body = await readJson2(response);
|
|
8628
8220
|
if (!response.ok)
|
|
8629
8221
|
throw new Error(appErrorMessage(body) ?? `HTTP ${response.status}`);
|
|
8630
8222
|
return body;
|
|
8631
8223
|
}
|
|
8632
|
-
var IdentitySchema =
|
|
8633
|
-
email:
|
|
8634
|
-
userId:
|
|
8635
|
-
projectId: z5.string().nullish()
|
|
8224
|
+
var IdentitySchema = z3.object({
|
|
8225
|
+
email: z3.string().optional(),
|
|
8226
|
+
userId: z3.string().optional()
|
|
8636
8227
|
});
|
|
8637
8228
|
async function whoamiCommand(options) {
|
|
8638
8229
|
const logger = createCLILogger(options);
|
|
@@ -8649,7 +8240,6 @@ async function whoamiCommand(options) {
|
|
|
8649
8240
|
const data = identity.data;
|
|
8650
8241
|
if (data.email) logger.info(data.email);
|
|
8651
8242
|
if (data.userId) logger.info(`User: ${data.userId}`);
|
|
8652
|
-
if (data.projectId) logger.info(`Project: ${data.projectId}`);
|
|
8653
8243
|
}
|
|
8654
8244
|
} catch (error) {
|
|
8655
8245
|
handleCliError(error);
|
|
@@ -8724,7 +8314,7 @@ function telemetryDisableCommand() {
|
|
|
8724
8314
|
}
|
|
8725
8315
|
|
|
8726
8316
|
// src/index.ts
|
|
8727
|
-
import { validateFlowStructure as
|
|
8317
|
+
import { validateFlowStructure as validateFlowStructure3 } from "@walkeros/core/dev";
|
|
8728
8318
|
|
|
8729
8319
|
// src/commands/bundle/wrap.ts
|
|
8730
8320
|
import * as path21 from "path";
|
|
@@ -8800,11 +8390,12 @@ async function wrapSkeleton(options) {
|
|
|
8800
8390
|
format: "esm",
|
|
8801
8391
|
platform,
|
|
8802
8392
|
outfile: outputPath,
|
|
8803
|
-
// Resolve `@walkeros/core` (
|
|
8804
|
-
// package's own dependency tree and the
|
|
8805
|
-
// esbuild looks under the temp entryDir
|
|
8806
|
-
// The wrap step always runs from inside the
|
|
8807
|
-
// CLI's local node_modules and the workspace root
|
|
8393
|
+
// Resolve `@walkeros/web-core` (the Tag Mode loader and the preview
|
|
8394
|
+
// activator) from the CLI package's own dependency tree and the
|
|
8395
|
+
// workspace root. Without this, esbuild looks under the temp entryDir
|
|
8396
|
+
// which has no node_modules. The wrap step always runs from inside the
|
|
8397
|
+
// CLI process; both the CLI's local node_modules and the workspace root
|
|
8398
|
+
// are safe anchors.
|
|
8808
8399
|
nodePaths: getNodeResolutionPaths(),
|
|
8809
8400
|
treeShaking: true,
|
|
8810
8401
|
logLevel: "error",
|
|
@@ -8819,7 +8410,7 @@ async function wrapSkeleton(options) {
|
|
|
8819
8410
|
};
|
|
8820
8411
|
if (platform === "browser") {
|
|
8821
8412
|
esbuildOptions.format = "iife";
|
|
8822
|
-
esbuildOptions.plugins = [
|
|
8413
|
+
esbuildOptions.plugins = [cliPackagesPlugin()];
|
|
8823
8414
|
const needs = readNeedsMarker(skeletonText);
|
|
8824
8415
|
esbuildOptions.define = {
|
|
8825
8416
|
"process.env.NODE_ENV": '"production"',
|
|
@@ -8854,10 +8445,10 @@ import fs22 from "fs-extra";
|
|
|
8854
8445
|
import { FlowReferenceError as FlowReferenceError2 } from "@walkeros/core";
|
|
8855
8446
|
|
|
8856
8447
|
// src/schemas/build-manifest.ts
|
|
8857
|
-
import { z as
|
|
8448
|
+
import { z as z4 } from "@walkeros/core/dev";
|
|
8858
8449
|
var BUILD_MANIFEST_VERSION = 1;
|
|
8859
|
-
var HttpUrlSchema =
|
|
8860
|
-
var OutputNameSchema =
|
|
8450
|
+
var HttpUrlSchema = z4.url({ protocol: /^https?$/ });
|
|
8451
|
+
var OutputNameSchema = z4.string().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*$/, "Must be a bare file name").describe("Output file name; its extension picks the format (.tar.gz packs)");
|
|
8861
8452
|
var BUNDLE_TARGET_NAMES = [
|
|
8862
8453
|
"cdn",
|
|
8863
8454
|
"cdn-skeleton",
|
|
@@ -8873,8 +8464,8 @@ var RESERVED_HEADERS = /* @__PURE__ */ new Set([
|
|
|
8873
8464
|
var OutputFields = {
|
|
8874
8465
|
outputName: OutputNameSchema,
|
|
8875
8466
|
putUrl: HttpUrlSchema.describe("Presigned PUT for exactly this output"),
|
|
8876
|
-
contentType:
|
|
8877
|
-
headers:
|
|
8467
|
+
contentType: z4.string().min(1).optional().describe("Content-Type sent with the PUT (must match a signed header)"),
|
|
8468
|
+
headers: z4.record(z4.string().min(1), z4.string()).refine(
|
|
8878
8469
|
(headers) => Object.keys(headers).every(
|
|
8879
8470
|
(name) => !RESERVED_HEADERS.has(name.toLowerCase())
|
|
8880
8471
|
),
|
|
@@ -8883,68 +8474,68 @@ var OutputFields = {
|
|
|
8883
8474
|
"Extra headers sent with the PUT (for headers a presign signs); never logged"
|
|
8884
8475
|
)
|
|
8885
8476
|
};
|
|
8886
|
-
var BuildBundleArtifactSchema =
|
|
8887
|
-
target:
|
|
8477
|
+
var BuildBundleArtifactSchema = z4.object({
|
|
8478
|
+
target: z4.enum(BUNDLE_TARGET_NAMES).describe("Named bundle target"),
|
|
8888
8479
|
...OutputFields
|
|
8889
8480
|
}).strict();
|
|
8890
|
-
var BuildWrapOptionsSchema =
|
|
8891
|
-
windowCollector:
|
|
8892
|
-
windowElb:
|
|
8893
|
-
preview:
|
|
8894
|
-
enabled:
|
|
8895
|
-
keyring:
|
|
8896
|
-
|
|
8481
|
+
var BuildWrapOptionsSchema = z4.object({
|
|
8482
|
+
windowCollector: z4.string().min(1).optional(),
|
|
8483
|
+
windowElb: z4.string().min(1).optional(),
|
|
8484
|
+
preview: z4.object({
|
|
8485
|
+
enabled: z4.boolean(),
|
|
8486
|
+
keyring: z4.array(
|
|
8487
|
+
z4.object({ kid: z4.string(), spki: z4.string() }).strict()
|
|
8897
8488
|
),
|
|
8898
|
-
iss:
|
|
8899
|
-
pb:
|
|
8900
|
-
acceptForeign:
|
|
8901
|
-
demoAllowlist:
|
|
8902
|
-
previewOrigin:
|
|
8489
|
+
iss: z4.string(),
|
|
8490
|
+
pb: z4.string().optional(),
|
|
8491
|
+
acceptForeign: z4.boolean().optional(),
|
|
8492
|
+
demoAllowlist: z4.array(z4.string()).optional(),
|
|
8493
|
+
previewOrigin: z4.string()
|
|
8903
8494
|
}).strict().optional(),
|
|
8904
|
-
previewGrantTargets:
|
|
8905
|
-
observe:
|
|
8906
|
-
url:
|
|
8907
|
-
binding:
|
|
8908
|
-
flowId:
|
|
8909
|
-
level:
|
|
8910
|
-
sample:
|
|
8495
|
+
previewGrantTargets: z4.array(z4.string()).optional(),
|
|
8496
|
+
observe: z4.object({
|
|
8497
|
+
url: z4.string(),
|
|
8498
|
+
binding: z4.string(),
|
|
8499
|
+
flowId: z4.string().optional(),
|
|
8500
|
+
level: z4.enum(["off", "standard", "trace"]).optional(),
|
|
8501
|
+
sample: z4.number().min(0).max(1).optional()
|
|
8911
8502
|
}).strict().optional(),
|
|
8912
|
-
moin:
|
|
8913
|
-
minify:
|
|
8914
|
-
minifyOptions:
|
|
8915
|
-
identifiers:
|
|
8916
|
-
syntax:
|
|
8917
|
-
whitespace:
|
|
8918
|
-
keepNames:
|
|
8919
|
-
legalComments:
|
|
8503
|
+
moin: z4.object({ app: z4.string(), base: z4.string() }).strict().optional().describe("Tag Mode loader target; absent, the production app"),
|
|
8504
|
+
minify: z4.boolean().optional(),
|
|
8505
|
+
minifyOptions: z4.object({
|
|
8506
|
+
identifiers: z4.boolean().optional(),
|
|
8507
|
+
syntax: z4.boolean().optional(),
|
|
8508
|
+
whitespace: z4.boolean().optional(),
|
|
8509
|
+
keepNames: z4.boolean().optional(),
|
|
8510
|
+
legalComments: z4.enum(["none", "inline", "eof", "linked", "external"]).optional()
|
|
8920
8511
|
}).strict().optional(),
|
|
8921
|
-
target:
|
|
8512
|
+
target: z4.string().min(1).optional().describe("esbuild target")
|
|
8922
8513
|
}).strict().describe("Options forwarded to wrapSkeleton");
|
|
8923
|
-
var BuildWrapArtifactSchema =
|
|
8924
|
-
target:
|
|
8925
|
-
platform:
|
|
8926
|
-
skeleton:
|
|
8927
|
-
|
|
8928
|
-
|
|
8514
|
+
var BuildWrapArtifactSchema = z4.object({
|
|
8515
|
+
target: z4.literal("wrap"),
|
|
8516
|
+
platform: z4.enum(["browser", "node"]),
|
|
8517
|
+
skeleton: z4.union([
|
|
8518
|
+
z4.object({ url: HttpUrlSchema }).strict(),
|
|
8519
|
+
z4.object({ artifact: OutputNameSchema }).strict()
|
|
8929
8520
|
]).describe(
|
|
8930
8521
|
"The skeleton to wrap: a GET URL, or the outputName of an earlier bundle artifact in this manifest"
|
|
8931
8522
|
),
|
|
8932
8523
|
options: BuildWrapOptionsSchema.optional(),
|
|
8933
8524
|
...OutputFields
|
|
8934
8525
|
}).strict();
|
|
8935
|
-
var BuildArtifactSchema =
|
|
8526
|
+
var BuildArtifactSchema = z4.union([
|
|
8936
8527
|
BuildBundleArtifactSchema,
|
|
8937
8528
|
BuildWrapArtifactSchema
|
|
8938
8529
|
]);
|
|
8939
|
-
var BuildManifestSchema =
|
|
8940
|
-
version:
|
|
8941
|
-
toolchain:
|
|
8942
|
-
flowConfig:
|
|
8943
|
-
flowName:
|
|
8944
|
-
buildEnv:
|
|
8530
|
+
var BuildManifestSchema = z4.object({
|
|
8531
|
+
version: z4.literal(BUILD_MANIFEST_VERSION),
|
|
8532
|
+
toolchain: z4.string().min(1).describe("Exact @walkeros/cli version; any other version refuses"),
|
|
8533
|
+
flowConfig: z4.record(z4.string(), z4.unknown()).optional().describe("Flow.Json to bundle; required when any bundle artifact is"),
|
|
8534
|
+
flowName: z4.string().min(1).optional(),
|
|
8535
|
+
buildEnv: z4.record(z4.string(), z4.string()).optional().describe(
|
|
8945
8536
|
"Base env for web $env, beneath config.bundle.env. Never the CLI process's own env"
|
|
8946
8537
|
),
|
|
8947
|
-
artifacts:
|
|
8538
|
+
artifacts: z4.array(BuildArtifactSchema).min(1),
|
|
8948
8539
|
resultPutUrl: HttpUrlSchema.describe("Presigned PUT for the result JSON")
|
|
8949
8540
|
}).loose().superRefine((manifest, ctx) => {
|
|
8950
8541
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -8987,21 +8578,21 @@ var BUILD_ERROR_CODES = [
|
|
|
8987
8578
|
"BUILD_FAILED",
|
|
8988
8579
|
"UPLOAD_FAILED"
|
|
8989
8580
|
];
|
|
8990
|
-
var BuildResultSchema =
|
|
8991
|
-
ok:
|
|
8992
|
-
toolchain:
|
|
8993
|
-
artifacts:
|
|
8994
|
-
|
|
8995
|
-
target:
|
|
8996
|
-
outputName:
|
|
8997
|
-
bytes:
|
|
8998
|
-
sha256:
|
|
8581
|
+
var BuildResultSchema = z4.object({
|
|
8582
|
+
ok: z4.boolean(),
|
|
8583
|
+
toolchain: z4.string().describe("The CLI version that ran the build"),
|
|
8584
|
+
artifacts: z4.array(
|
|
8585
|
+
z4.object({
|
|
8586
|
+
target: z4.string(),
|
|
8587
|
+
outputName: z4.string(),
|
|
8588
|
+
bytes: z4.number().int().nonnegative(),
|
|
8589
|
+
sha256: z4.string()
|
|
8999
8590
|
})
|
|
9000
8591
|
).describe("Outputs PUT successfully, in manifest order"),
|
|
9001
|
-
error:
|
|
9002
|
-
code:
|
|
9003
|
-
message:
|
|
9004
|
-
outputName:
|
|
8592
|
+
error: z4.object({
|
|
8593
|
+
code: z4.enum(BUILD_ERROR_CODES),
|
|
8594
|
+
message: z4.string(),
|
|
8595
|
+
outputName: z4.string().optional().describe("The artifact being built when the error occurred")
|
|
9005
8596
|
}).optional()
|
|
9006
8597
|
}).meta({ id: "BuildResult", title: "walkeros bundle --manifest result" });
|
|
9007
8598
|
|
|
@@ -9052,16 +8643,16 @@ async function fetchWithRetry(url, init, options) {
|
|
|
9052
8643
|
if (failure instanceof Response && !isTransientStatus(failure.status)) {
|
|
9053
8644
|
throw new Error(`${label} failed: ${reason}`);
|
|
9054
8645
|
}
|
|
9055
|
-
const
|
|
9056
|
-
if (
|
|
8646
|
+
const delay2 = BACKOFF_MS[attempt - 1];
|
|
8647
|
+
if (delay2 === void 0) {
|
|
9057
8648
|
throw new Error(
|
|
9058
8649
|
`${label} failed after ${maxAttempts} attempts: ${reason}`
|
|
9059
8650
|
);
|
|
9060
8651
|
}
|
|
9061
8652
|
warn?.(
|
|
9062
|
-
`${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${
|
|
8653
|
+
`${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${delay2 / 1e3}s`
|
|
9063
8654
|
);
|
|
9064
|
-
await sleep(
|
|
8655
|
+
await sleep(delay2);
|
|
9065
8656
|
}
|
|
9066
8657
|
}
|
|
9067
8658
|
|
|
@@ -9549,22 +9140,13 @@ export {
|
|
|
9549
9140
|
bundle,
|
|
9550
9141
|
bundleCommand,
|
|
9551
9142
|
classifyStepProperties,
|
|
9552
|
-
clearAuthFields,
|
|
9553
9143
|
clientContextHeaders,
|
|
9554
9144
|
collectKnownSecrets,
|
|
9555
|
-
completeDeviceLogin,
|
|
9556
9145
|
containsCodeMarkers,
|
|
9557
|
-
credentialSource,
|
|
9558
|
-
deleteConfig,
|
|
9559
9146
|
formatPushResult,
|
|
9560
|
-
getAuthHeaders,
|
|
9561
9147
|
getClientContext,
|
|
9562
9148
|
loadConfig,
|
|
9563
9149
|
loadJsonConfig,
|
|
9564
|
-
login,
|
|
9565
|
-
loginCommand,
|
|
9566
|
-
logout,
|
|
9567
|
-
logoutCommand,
|
|
9568
9150
|
push,
|
|
9569
9151
|
pushCommand,
|
|
9570
9152
|
readConfig,
|
|
@@ -9573,7 +9155,6 @@ export {
|
|
|
9573
9155
|
resolveAppUrl,
|
|
9574
9156
|
resolveExportName,
|
|
9575
9157
|
resolveManifestSource,
|
|
9576
|
-
resolveToken,
|
|
9577
9158
|
runBuildManifest,
|
|
9578
9159
|
selectDevExamples,
|
|
9579
9160
|
setClientContext,
|
|
@@ -9581,14 +9162,13 @@ export {
|
|
|
9581
9162
|
simulateDestination,
|
|
9582
9163
|
simulateSource,
|
|
9583
9164
|
simulateTransformer,
|
|
9584
|
-
startDeviceAuthorization,
|
|
9585
9165
|
telemetry_exports as telemetry,
|
|
9586
9166
|
telemetryDisableCommand,
|
|
9587
9167
|
telemetryEnableCommand,
|
|
9588
9168
|
telemetryStatusCommand,
|
|
9589
9169
|
validate,
|
|
9590
9170
|
validateCommand,
|
|
9591
|
-
|
|
9171
|
+
validateFlowStructure3 as validateFlowStructure,
|
|
9592
9172
|
whoami,
|
|
9593
9173
|
whoamiCommand,
|
|
9594
9174
|
wrapSkeleton,
|