@walkeros/cli 4.8.1-next-1792019907609 → 4.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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
- var REFRESH_SKEW_MS = 6e4;
758
- var legacyNoticeShown = false;
759
- function noticeLegacyToken() {
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";
@@ -1473,7 +1018,7 @@ function tempSibling(dest) {
1473
1018
  ).join("");
1474
1019
  return `${dest}${TMP_INFIX}${rand}`;
1475
1020
  }
1476
- function errorCode2(error) {
1021
+ function errorCode(error) {
1477
1022
  if (typeof error === "object" && error !== null && "code" in error) {
1478
1023
  const code = error.code;
1479
1024
  return typeof code === "string" ? code : void 0;
@@ -1481,7 +1026,7 @@ function errorCode2(error) {
1481
1026
  return void 0;
1482
1027
  }
1483
1028
  function isOccupied(error) {
1484
- const code = errorCode2(error);
1029
+ const code = errorCode(error);
1485
1030
  return code === "EEXIST" || code === "ENOTEMPTY";
1486
1031
  }
1487
1032
  function isCacheTempName(name) {
@@ -1520,7 +1065,7 @@ async function replaceIncomplete(tmp, dest) {
1520
1065
  await fs9.rename(dest, aside);
1521
1066
  moved = true;
1522
1067
  } catch (error) {
1523
- if (errorCode2(error) !== "ENOENT") throw error;
1068
+ if (errorCode(error) !== "ENOENT") throw error;
1524
1069
  }
1525
1070
  const restore = moved && await isCacheDirComplete(aside);
1526
1071
  const winner = restore ? aside : tmp;
@@ -1698,7 +1243,7 @@ function backoffForAttempt(index) {
1698
1243
  const spread = base * JITTER;
1699
1244
  return base + (Math.random() * 2 - 1) * spread;
1700
1245
  }
1701
- function delay2(ms) {
1246
+ function delay(ms) {
1702
1247
  return new Promise((resolve5) => {
1703
1248
  setTimeout(resolve5, ms);
1704
1249
  });
@@ -1740,7 +1285,7 @@ async function withPacoteRetry(fn, label, options = {}) {
1740
1285
  maxTotalMs - (Date.now() - start)
1741
1286
  );
1742
1287
  if (sleepMs <= 0) break;
1743
- await delay2(sleepMs);
1288
+ await delay(sleepMs);
1744
1289
  }
1745
1290
  throw new Error(
1746
1291
  `Failed ${label} after ${made} attempts: ${describeError(lastError)}`
@@ -2567,21 +2112,21 @@ async function ensureCodeOnDisk(codeContent, compiledCode, tmpDir, inputs) {
2567
2112
  }
2568
2113
 
2569
2114
  // src/version.ts
2570
- import { readFileSync as readFileSync2 } from "fs";
2115
+ import { readFileSync } from "fs";
2571
2116
  import { fileURLToPath } from "url";
2572
- import { dirname as dirname3, join as join4 } from "path";
2117
+ import { dirname as dirname3, join as join3 } from "path";
2573
2118
  var versionFilename = fileURLToPath(import.meta.url);
2574
2119
  var versionDirname = dirname3(versionFilename);
2575
2120
  function findPackageJson() {
2576
2121
  const paths = [
2577
- join4(versionDirname, "../package.json"),
2122
+ join3(versionDirname, "../package.json"),
2578
2123
  // dist/ or src/
2579
- join4(versionDirname, "../../package.json")
2124
+ join3(versionDirname, "../../package.json")
2580
2125
  // src/core/ (not used, but safe)
2581
2126
  ];
2582
2127
  for (const p of paths) {
2583
2128
  try {
2584
- return readFileSync2(p, "utf-8");
2129
+ return readFileSync(p, "utf-8");
2585
2130
  } catch {
2586
2131
  }
2587
2132
  }
@@ -2597,9 +2142,11 @@ function hasCodeReference(code) {
2597
2142
  return isInlineCode(code) || typeof code === "string";
2598
2143
  }
2599
2144
  function generateInlineCode(inline, runtimeProps, isDestination) {
2600
- const pushFn = inline.push.replace("$code:", "");
2601
- const initFn = inline.init ? inline.init.replace("$code:", "") : void 0;
2602
2145
  const typeLine = inline.type ? `type: '${inline.type}',` : "";
2146
+ const functionLines = STEP_FUNCTION_KEYS.flatMap((key) => {
2147
+ const fn = inline[key];
2148
+ return fn ? [`${key}: ${fn.replace("$code:", "")}`] : [];
2149
+ }).join(",\n ");
2603
2150
  const props = {
2604
2151
  config: {},
2605
2152
  env: {},
@@ -2611,8 +2158,7 @@ function generateInlineCode(inline, runtimeProps, isDestination) {
2611
2158
  code: {
2612
2159
  ${typeLine}
2613
2160
  config: ${processConfigValue(props.config)},
2614
- ${initFn ? `init: ${initFn},` : ""}
2615
- push: ${pushFn}
2161
+ ${functionLines}
2616
2162
  },
2617
2163
  ${propLines}
2618
2164
  }`;
@@ -2621,8 +2167,7 @@ function generateInlineCode(inline, runtimeProps, isDestination) {
2621
2167
  code: async (context) => ({
2622
2168
  ${typeLine}
2623
2169
  config: context.config,
2624
- ${initFn ? `init: ${initFn},` : ""}
2625
- push: ${pushFn}
2170
+ ${functionLines}
2626
2171
  }),
2627
2172
  ${propLines}
2628
2173
  }`;
@@ -2768,6 +2313,7 @@ async function bundleCore(flowSettings, buildOptions, logger, showStats = false,
2768
2313
  packagePaths
2769
2314
  );
2770
2315
  const versionsHash = await getHashServer3(sortedVersions.join("\n"), 12);
2316
+ applyCollectorDefaults(flowSettings);
2771
2317
  if (provenance) {
2772
2318
  applyCollectorProvenance(
2773
2319
  flowSettings,
@@ -2939,7 +2485,7 @@ ${dataDeclaration}${needs}`;
2939
2485
  };
2940
2486
  if (buildOptions.platform === "browser") {
2941
2487
  stage2Options.format = "iife";
2942
- stage2Options.plugins = [cliCorePlugin()];
2488
+ stage2Options.plugins = [cliPackagesPlugin()];
2943
2489
  stage2Options.define = {
2944
2490
  "process.env.NODE_ENV": '"production"',
2945
2491
  global: "globalThis",
@@ -3107,22 +2653,25 @@ function getNodeExternals() {
3107
2653
  }
3108
2654
  return externals;
3109
2655
  }
3110
- var CLI_CORE = "walkeros-cli-core";
3111
- function cliCorePlugin() {
2656
+ var CLI_PACKAGES = "walkeros-cli-packages";
2657
+ function cliPackagesPlugin() {
3112
2658
  const resolveDir = path14.dirname(fileURLToPath2(import.meta.url));
3113
2659
  return {
3114
- name: CLI_CORE,
2660
+ name: CLI_PACKAGES,
3115
2661
  setup(build2) {
3116
- build2.onResolve({ filter: /^@walkeros\/core$/ }, async (args) => {
3117
- if (args.pluginData === CLI_CORE) return void 0;
3118
- const resolved = await build2.resolve(args.path, {
3119
- kind: args.kind,
3120
- resolveDir,
3121
- pluginData: CLI_CORE
3122
- });
3123
- if (resolved.errors.length > 0) return { errors: resolved.errors };
3124
- return { path: resolved.path, sideEffects: resolved.sideEffects };
3125
- });
2662
+ build2.onResolve(
2663
+ { filter: /^@walkeros\/(core|web-core)$/ },
2664
+ async (args) => {
2665
+ if (args.pluginData === CLI_PACKAGES) return void 0;
2666
+ const resolved = await build2.resolve(args.path, {
2667
+ kind: args.kind,
2668
+ resolveDir,
2669
+ pluginData: CLI_PACKAGES
2670
+ });
2671
+ if (resolved.errors.length > 0) return { errors: resolved.errors };
2672
+ return { path: resolved.path, sideEffects: resolved.sideEffects };
2673
+ }
2674
+ );
3126
2675
  }
3127
2676
  };
3128
2677
  }
@@ -3439,6 +2988,12 @@ ${firstError.text}`
3439
2988
  function buildDataPayload(flowSettings) {
3440
2989
  return buildSplitConfigObject(flowSettings, detectNamedImports(flowSettings)).dataPayloadObj;
3441
2990
  }
2991
+ function applyCollectorDefaults(flowSettings) {
2992
+ if (getPlatform2(flowSettings) !== "server") return;
2993
+ const collector = flowSettings.collector ?? {};
2994
+ collector.consentDenied ??= "skip";
2995
+ flowSettings.collector = collector;
2996
+ }
3442
2997
  function applyCollectorProvenance(flowSettings, flowName, release2, fallback) {
3443
2998
  const collector = flowSettings.collector ?? {};
3444
2999
  collector.name ??= flowName;
@@ -3557,6 +3112,34 @@ export function wireConfig(__data) {
3557
3112
 
3558
3113
  export { startFlow };`;
3559
3114
  }
3115
+ var HOST_LOGGER_MERGE = ` // The host's logger (masking, its error ring) joins the flow's own: the
3116
+ // flow's level and format win, unless the host forces a level (--verbose);
3117
+ // the flow's handler runs first, then the host's, once per line, always.
3118
+ // The flow handler's originalHandler does nothing, so no line prints a
3119
+ // second time unmasked. The host learns the flow's settings before the
3120
+ // collector starts, so every line, the first included, has its format.
3121
+ if (context.logger) {
3122
+ const own = config.logger || {};
3123
+ const host = context.logger;
3124
+ if (context.onLogger) context.onLogger({ level: own.level, format: own.format });
3125
+ const level = context.logLevel ?? own.level ?? host.level;
3126
+ const printedByHost = () => {};
3127
+ const handler = own.handler && host.handler
3128
+ ? (lvl, message, ctx, scope) => {
3129
+ try {
3130
+ own.handler(lvl, message, ctx, scope, printedByHost);
3131
+ } finally {
3132
+ host.handler(lvl, message, ctx, scope, printedByHost);
3133
+ }
3134
+ }
3135
+ : host.handler || own.handler;
3136
+ config.logger = {
3137
+ ...host,
3138
+ ...(level !== undefined ? { level } : {}),
3139
+ ...(own.format ? { format: own.format } : {}),
3140
+ ...(handler ? { handler } : {}),
3141
+ };
3142
+ }`;
3560
3143
  function generateServerEntry(stage1Path, dataPayload) {
3561
3144
  const stage1Specifier = toFileImportSpecifier(stage1Path);
3562
3145
  return `import { startFlow, wireConfig } from '${stage1Specifier}';
@@ -3566,7 +3149,7 @@ const __configData = ${dataPayload};
3566
3149
  export default async function(context = {}) {
3567
3150
  const config = wireConfig(__configData);
3568
3151
 
3569
- if (context.logger) config.logger = context.logger;
3152
+ ${HOST_LOGGER_MERGE}
3570
3153
 
3571
3154
  if (context.sourceSettings && config.sources) {
3572
3155
  for (const src of Object.values(config.sources)) {
@@ -3626,6 +3209,7 @@ function readObserveConnect(flowSettings, logger) {
3626
3209
  );
3627
3210
  return void 0;
3628
3211
  }
3212
+ var OBSERVE_SLOT_IMPORT = "import { pageObserveSlot } from '@walkeros/web-core';\n";
3629
3213
  function emitObserveAssignment(observe) {
3630
3214
  const literal = {
3631
3215
  url: observe.url,
@@ -3635,9 +3219,9 @@ function emitObserveAssignment(observe) {
3635
3219
  ...observe.sample !== void 0 ? { sample: observe.sample } : {}
3636
3220
  };
3637
3221
  return `
3638
- config.observe = ${JSON.stringify(literal)};`;
3222
+ config.observe = { ...${JSON.stringify(literal)}, slot: pageObserveSlot() };`;
3639
3223
  }
3640
- var MOIN_IMPORT = "import { moin } from '@walkeros/core';\n";
3224
+ var MOIN_IMPORT = "import { moin } from '@walkeros/web-core';\n";
3641
3225
  function emitMoinCall(target) {
3642
3226
  if (!target)
3643
3227
  return `
@@ -3685,10 +3269,11 @@ function generateWebEntry(stage1Path, dataPayload, options = {}) {
3685
3269
  }
3686
3270
  }` : "";
3687
3271
  const stage1Specifier = toFileImportSpecifier(stage1Path);
3272
+ const observeImport = options.observe ? OBSERVE_SLOT_IMPORT : "";
3688
3273
  const observeBlock = options.observe ? emitObserveAssignment(options.observe) : "";
3689
3274
  const loaderImport = platform === "browser" ? MOIN_IMPORT : "";
3690
3275
  const loaderCall = platform === "browser" ? emitMoinCall() : "";
3691
- return `${loaderImport}import { startFlow, wireConfig } from '${stage1Specifier}';
3276
+ return `${loaderImport}${observeImport}import { startFlow, wireConfig } from '${stage1Specifier}';
3692
3277
 
3693
3278
  const __configData = ${dataPayload};
3694
3279
 
@@ -3712,7 +3297,7 @@ function generateWrapEntry(stage1Path, options = {}) {
3712
3297
  }
3713
3298
  const preview = options.preview;
3714
3299
  const previewEnabled = !!preview?.enabled;
3715
- const previewImport = previewEnabled ? `import { browserSwapActivator } from '@walkeros/core';
3300
+ const previewImport = previewEnabled ? `import { browserSwapActivator } from '@walkeros/web-core';
3716
3301
  ` : "";
3717
3302
  const grantTargets = options.previewGrantTargets ?? [];
3718
3303
  const previewGrantBlock = grantTargets.length > 0 ? `
@@ -3762,10 +3347,11 @@ ${grantTargets.map((key) => {
3762
3347
  }
3763
3348
  }` : "";
3764
3349
  const stage1Specifier = toFileImportSpecifier(stage1Path);
3350
+ const observeImport = options.observe ? OBSERVE_SLOT_IMPORT : "";
3765
3351
  const observeBlock = options.observe ? emitObserveAssignment(options.observe) : "";
3766
3352
  const loaderImport = platform === "browser" ? MOIN_IMPORT : "";
3767
3353
  const loaderCall = platform === "browser" ? emitMoinCall(options.moin) : "";
3768
- return `${loaderImport}${previewImport}import { startFlow, wireConfig, __configData } from '${stage1Specifier}';
3354
+ return `${loaderImport}${previewImport}${observeImport}import { startFlow, wireConfig, __configData } from '${stage1Specifier}';
3769
3355
 
3770
3356
  (async () => {${loaderCall}${previewBlock}
3771
3357
  const config = wireConfig(__configData);${envBlock}${previewGrantBlock}${observeBlock}
@@ -3782,7 +3368,7 @@ function generateWrapEntryServer(stage1Path) {
3782
3368
  export default async function(context = {}) {
3783
3369
  const config = wireConfig(__configData);
3784
3370
 
3785
- if (context.logger) config.logger = context.logger;
3371
+ ${HOST_LOGGER_MERGE}
3786
3372
 
3787
3373
  if (context.sourceSettings && config.sources) {
3788
3374
  for (const src of Object.values(config.sources)) {
@@ -4268,7 +3854,7 @@ async function bundle(configOrPath, options = {}) {
4268
3854
  // src/commands/push/index.ts
4269
3855
  import path18 from "path";
4270
3856
  import fs18 from "fs-extra";
4271
- import { createIngest, getPlatform as getPlatform3, stepId } from "@walkeros/core";
3857
+ import { createIngest, getPlatform as getPlatform4, stepId } from "@walkeros/core";
4272
3858
  import {
4273
3859
  enrichEvent,
4274
3860
  transformerInit,
@@ -4497,13 +4083,13 @@ function installTimerInterception(options = {}) {
4497
4083
  setInterval: Reflect.get(target, "setInterval"),
4498
4084
  clearInterval: Reflect.get(target, "clearInterval")
4499
4085
  });
4500
- const trackedSetTimeout = (callback, delay4, ...args) => {
4086
+ const trackedSetTimeout = (callback, delay2, ...args) => {
4501
4087
  if (typeof callback !== "function") return 0;
4502
4088
  const id = nextId++;
4503
4089
  pending.set(id, {
4504
4090
  id,
4505
4091
  callback,
4506
- delay: delay4 ?? 0,
4092
+ delay: delay2 ?? 0,
4507
4093
  type: "timeout",
4508
4094
  args,
4509
4095
  cleared: false
@@ -4516,13 +4102,13 @@ function installTimerInterception(options = {}) {
4516
4102
  const entry = pending.get(numId);
4517
4103
  if (entry) entry.cleared = true;
4518
4104
  };
4519
- const trackedSetInterval = (callback, delay4, ...args) => {
4105
+ const trackedSetInterval = (callback, delay2, ...args) => {
4520
4106
  if (typeof callback !== "function") return 0;
4521
4107
  const id = nextId++;
4522
4108
  pending.set(id, {
4523
4109
  id,
4524
4110
  callback,
4525
- delay: delay4 ?? 0,
4111
+ delay: delay2 ?? 0,
4526
4112
  type: "interval",
4527
4113
  args,
4528
4114
  cleared: false
@@ -4962,7 +4548,7 @@ function buildSimulationResult(args) {
4962
4548
  // src/commands/push/prepare.ts
4963
4549
  import path17 from "path";
4964
4550
  import fs17 from "fs-extra";
4965
- import { getPlatform as getPlatform2 } from "@walkeros/core";
4551
+ import { getPlatform as getPlatform3 } from "@walkeros/core";
4966
4552
 
4967
4553
  // src/core/known-secrets.ts
4968
4554
  import { REF_SECRET } from "@walkeros/core";
@@ -5004,7 +4590,7 @@ async function prepareFlow(input) {
5004
4590
  configPath: process.cwd(),
5005
4591
  flowName: input.flow
5006
4592
  });
5007
- const platform = getPlatform2(flowSettings);
4593
+ const platform = getPlatform3(flowSettings);
5008
4594
  const overrides = buildOverrides(
5009
4595
  { simulate: input.simulate, mock: input.mock },
5010
4596
  flowSettings
@@ -5580,7 +5166,7 @@ async function executeConfigPush(options, validatedEvent, logger, setTempDir, lo
5580
5166
  logger,
5581
5167
  raw: loaded.raw
5582
5168
  });
5583
- const platform = getPlatform3(flowSettings);
5169
+ const platform = getPlatform4(flowSettings);
5584
5170
  const overrides = buildOverrides({ mock: options.mock }, flowSettings);
5585
5171
  logger.debug("Bundling flow configuration");
5586
5172
  const tempDir = await tmpRunDir("push");
@@ -6451,16 +6037,9 @@ import chalk2 from "chalk";
6451
6037
  import { isObject as isObject10 } from "@walkeros/core";
6452
6038
 
6453
6039
  // src/commands/validate/validators/contract.ts
6454
- import { isObject as isObject5 } from "@walkeros/core";
6040
+ import { CONTRACT_RULE_KEYS, isObject as isObject5 } from "@walkeros/core";
6041
+ var KNOWN_KEYS = new Set(CONTRACT_RULE_KEYS);
6455
6042
  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
6043
  function validateContract(input) {
6465
6044
  const errors = [];
6466
6045
  const warnings = [];
@@ -6501,7 +6080,9 @@ function validateContract(input) {
6501
6080
  const keys = Object.keys(obj);
6502
6081
  const unknownKeys = keys.filter((k) => !KNOWN_KEYS.has(k));
6503
6082
  const hasKnownKey = keys.some((k) => KNOWN_KEYS.has(k));
6504
- const objectValuedUnknown = unknownKeys.filter((k) => isObject5(obj[k]));
6083
+ const objectValuedUnknown = unknownKeys.filter(
6084
+ (k) => isObject5(obj[k]) && !SECTION_KEYS.includes(k)
6085
+ );
6505
6086
  if (!hasKnownKey && objectValuedUnknown.length > 0) {
6506
6087
  errors.push({
6507
6088
  path: name,
@@ -6511,9 +6092,9 @@ function validateContract(input) {
6511
6092
  continue;
6512
6093
  }
6513
6094
  for (const key of unknownKeys) {
6514
- warnings.push({
6095
+ errors.push({
6515
6096
  path: `${name}.${key}`,
6516
- message: `Unknown contract key "${key}" is ignored`,
6097
+ 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
6098
  code: "UNKNOWN_CONTRACT_KEY"
6518
6099
  });
6519
6100
  }
@@ -6547,18 +6128,6 @@ function validateContract(input) {
6547
6128
  });
6548
6129
  }
6549
6130
  }
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
- }
6560
- }
6561
- }
6562
6131
  if (obj.events !== void 0) {
6563
6132
  if (typeof obj.events !== "object" || obj.events === null) {
6564
6133
  errors.push({
@@ -6670,9 +6239,14 @@ import {
6670
6239
  isObject as isObject8,
6671
6240
  REF_CONTRACT,
6672
6241
  resolveContracts,
6242
+ SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX4,
6673
6243
  validateStepEntry
6674
6244
  } from "@walkeros/core";
6675
- import { schemas as schemas4, validateFlowStructure } from "@walkeros/core/dev";
6245
+ import {
6246
+ checkStepKeys,
6247
+ schemas as schemas4,
6248
+ validateFlowStructure as validateFlowStructure2
6249
+ } from "@walkeros/core/dev";
6676
6250
  import {
6677
6251
  validateEventAgainstContract
6678
6252
  } from "@walkeros/transformer-validate";
@@ -6873,7 +6447,7 @@ import {
6873
6447
  REF_STORE,
6874
6448
  SECRET_MARKER_PREFIX as SECRET_MARKER_PREFIX3
6875
6449
  } from "@walkeros/core";
6876
- var CLIENT_HEADER = "walkeros-cli/4.8.1-next-1792019907609";
6450
+ var CLIENT_HEADER = "walkeros-cli/4.8.2";
6877
6451
  function createSettingsContext(configDir) {
6878
6452
  return { configDir, cache: /* @__PURE__ */ new Map(), compiled: /* @__PURE__ */ new Map() };
6879
6453
  }
@@ -6991,7 +6565,7 @@ function packageSource(spec, rawFlow) {
6991
6565
  const pinned = pin.version ?? version;
6992
6566
  return pinned ? { name, version: pinned } : { name };
6993
6567
  }
6994
- function readJson2(file) {
6568
+ function readJson(file) {
6995
6569
  return JSON.parse(fs19.readFileSync(file, "utf-8"));
6996
6570
  }
6997
6571
  function readLocalSchema(source, configDir) {
@@ -7002,9 +6576,9 @@ function readLocalSchema(source, configDir) {
7002
6576
  path19.join(root, "walkerOS.json")
7003
6577
  ].find((candidate) => fs19.existsSync(candidate));
7004
6578
  if (!file) throw new Error(`no walkerOS.json under ${root}`);
7005
- const meta = readJson2(file);
6579
+ const meta = readJson(file);
7006
6580
  const pkgFile = path19.join(root, "package.json");
7007
- const pkg = fs19.existsSync(pkgFile) ? readJson2(pkgFile) : void 0;
6581
+ const pkg = fs19.existsSync(pkgFile) ? readJson(pkgFile) : void 0;
7008
6582
  const schemas6 = isObject7(meta) ? meta.schemas : void 0;
7009
6583
  const exportSchemas = isObject7(meta) ? meta.exportSchemas : void 0;
7010
6584
  const declared = isObject7(meta) && isObject7(meta.$meta) ? meta.$meta.exports : void 0;
@@ -7188,7 +6762,9 @@ var { validateFlowConfig: validateFlowConfig2 } = schemas4;
7188
6762
  var DEPRECATED_PACKAGES = {
7189
6763
  "@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
6764
  };
7191
- var OPEN_STEP_KINDS = [
6765
+ var STEP_KINDS2 = [
6766
+ ["sources", "Source"],
6767
+ ["transformers", "Transformer"],
7192
6768
  ["destinations", "Destination"],
7193
6769
  ["stores", "Store"]
7194
6770
  ];
@@ -7237,7 +6813,11 @@ async function validateFlowWithPackages(input, options = {}) {
7237
6813
  }
7238
6814
  }
7239
6815
  for (const outcome of await Promise.all(pending)) {
7240
- result.warnings.push(...outcome.findings);
6816
+ for (const finding of outcome.findings) {
6817
+ if (finding.keyword === "additionalProperties")
6818
+ result.errors.push(finding);
6819
+ else result.warnings.push(finding);
6820
+ }
7241
6821
  run.skipped.push(...outcome.skipped);
7242
6822
  deferred.push(...outcome.deferred);
7243
6823
  if (outcome.checked) packages.push(outcome.checked);
@@ -7245,6 +6825,7 @@ async function validateFlowWithPackages(input, options = {}) {
7245
6825
  result.details.scope = describeScope(scope, run.checks);
7246
6826
  result.details.deferred = [...result.details.deferred ?? [], ...deferred];
7247
6827
  if (packages.length > 0) result.details.packages = packages;
6828
+ result.valid = result.errors.length === 0;
7248
6829
  return result;
7249
6830
  }
7250
6831
  function runFlowChecks(input, options) {
@@ -7303,8 +6884,13 @@ function runFlowChecks(input, options) {
7303
6884
  for (const issue of coreResult.errors) {
7304
6885
  const path23 = issue.path || "root";
7305
6886
  if (!inScope(path23)) continue;
7306
- if (path23 === "contract" && contractErrors > 0) continue;
7307
- errors.push({ path: path23, message: issue.message, code: "SCHEMA_VALIDATION" });
6887
+ if ((path23 === "contract" || path23.startsWith("contract.")) && contractErrors > 0)
6888
+ continue;
6889
+ errors.push({
6890
+ path: path23,
6891
+ message: issue.message,
6892
+ code: issue.code ?? "SCHEMA_VALIDATION"
6893
+ });
7308
6894
  }
7309
6895
  for (const issue of coreResult.warnings) {
7310
6896
  const path23 = issue.path || "root";
@@ -7338,20 +6924,13 @@ function runFlowChecks(input, options) {
7338
6924
  }
7339
6925
  }
7340
6926
  }
7341
- for (const [section, kind] of OPEN_STEP_KINDS) {
6927
+ for (const [section, kind] of STEP_KINDS2) {
7342
6928
  const steps = flowValue[section];
7343
6929
  if (!isObject8(steps)) continue;
7344
6930
  for (const [name, step] of Object.entries(steps)) {
7345
6931
  if (!isObject8(step)) continue;
7346
6932
  const at = `flows.${flowName}.${section}.${name}`;
7347
- for (const key of unknownStepKeys(step, kind)) {
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
- }
6933
+ errors.push(...checkStepKeys(step, kind, at));
7355
6934
  const pkg = step.package;
7356
6935
  if (typeof pkg === "string" && pkg in DEPRECATED_PACKAGES) {
7357
6936
  warnings.push({
@@ -7362,6 +6941,7 @@ function runFlowChecks(input, options) {
7362
6941
  }
7363
6942
  }
7364
6943
  }
6944
+ checkWebLoggerFormat(flowName, flowValue, errors);
7365
6945
  }
7366
6946
  if (flows) {
7367
6947
  details.flowNames = allFlows;
@@ -7425,7 +7005,7 @@ function runFlowChecks(input, options) {
7425
7005
  }
7426
7006
  };
7427
7007
  perFlow(["flow:structure"], (name, flow, file) => {
7428
- const structure = validateFlowStructure({
7008
+ const structure = validateFlowStructure2({
7429
7009
  ...file,
7430
7010
  flows: { [name]: flow }
7431
7011
  });
@@ -7533,16 +7113,31 @@ function checkResolvedWindowCollector(name, raw, flow, errors, deferred) {
7533
7113
  code: "SCHEMA_VALIDATION"
7534
7114
  });
7535
7115
  }
7536
- function unknownStepKeys(step, kind) {
7537
- const unknown = [];
7538
- const rest = { ...step };
7539
- for (; ; ) {
7540
- const verdict = validateStepEntry(rest, kind);
7541
- if (verdict.code !== "UNKNOWN_KEY" || verdict.key === void 0) break;
7542
- unknown.push(verdict.key);
7543
- Reflect.deleteProperty(rest, verdict.key);
7116
+ function checkWebLoggerFormat(flowName, flow, errors) {
7117
+ if (!isObject8(flow.config) || flow.config.platform !== "web") return;
7118
+ const at = `flows.${flowName}`;
7119
+ const loggers = [];
7120
+ if (isObject8(flow.collector))
7121
+ loggers.push([`${at}.collector.logger`, flow.collector.logger]);
7122
+ for (const [section] of STEP_KINDS2) {
7123
+ const steps = flow[section];
7124
+ if (!isObject8(steps)) continue;
7125
+ for (const [name, step] of Object.entries(steps)) {
7126
+ if (isObject8(step) && isObject8(step.config))
7127
+ loggers.push([
7128
+ `${at}.${section}.${name}.config.logger`,
7129
+ step.config.logger
7130
+ ]);
7131
+ }
7132
+ }
7133
+ for (const [path23, logger] of loggers) {
7134
+ if (!isObject8(logger) || logger.format === void 0) continue;
7135
+ errors.push({
7136
+ path: `${path23}.format`,
7137
+ message: "logger.format applies to server flows only: a web flow logs to the browser console, which has no output format. Remove it.",
7138
+ code: "WEB_LOGGER_FORMAT"
7139
+ });
7544
7140
  }
7545
- return unknown;
7546
7141
  }
7547
7142
  function routeTargets(spec) {
7548
7143
  if (spec === void 0) return [];
@@ -7770,6 +7365,12 @@ function lintRoute(spec, position, known, errors, warnings) {
7770
7365
  }
7771
7366
  }
7772
7367
  }
7368
+ function hasRuntimeValue(value) {
7369
+ if (typeof value === "string")
7370
+ return value.includes(ENV_MARKER_PREFIX3) || value.startsWith(SECRET_MARKER_PREFIX4) || /\$(?:env|secret)\./.test(value);
7371
+ if (Array.isArray(value)) return value.some(hasRuntimeValue);
7372
+ return isObject8(value) && Object.values(value).some(hasRuntimeValue);
7373
+ }
7773
7374
  var VALIDATE_PACKAGE = "@walkeros/transformer-validate";
7774
7375
  function isValidateStep(step) {
7775
7376
  return step.package === VALIDATE_PACKAGE;
@@ -7840,6 +7441,15 @@ function checkValidateStepExamples(stepPath, step, contract, errors, warnings, s
7840
7441
  }
7841
7442
  if (!step.examples) return;
7842
7443
  const contracts = resolution.sources;
7444
+ if (contracts.some(hasRuntimeValue)) {
7445
+ skipped?.push({
7446
+ path: stepPath,
7447
+ check: "flow:contract-examples",
7448
+ reason: "the contract uses a $env or $secret value, known only when the bundle builds or runs, so the examples cannot be judged statically",
7449
+ code: "CONTRACT_NOT_STATIC"
7450
+ });
7451
+ return;
7452
+ }
7843
7453
  const mode = settings.mode === "strict" ? "strict" : "pass";
7844
7454
  const format = settings.format === true;
7845
7455
  const output = isObject8(settings.output) ? settings.output : {};
@@ -8046,6 +7656,7 @@ var VALIDATE_CODES = [
8046
7656
  "CONTRACT_VIOLATION",
8047
7657
  "MAPPING_DOT_KEY",
8048
7658
  "FLOW_REF_WARNING",
7659
+ "WEB_LOGGER_FORMAT",
8049
7660
  "FLOW_CYCLE",
8050
7661
  "VAR_CYCLE",
8051
7662
  // Structure (the bundler's own preflight, validateFlowStructure)
@@ -8054,7 +7665,11 @@ var VALIDATE_CODES = [
8054
7665
  "STORE_REFERENCE_NOT_FOUND",
8055
7666
  "STATE_STORE_UNKNOWN",
8056
7667
  "STATE_STORE_FILE",
8057
- "TRANSFORMER_MAPPING_NO_OP",
7668
+ "MAPPING_NO_OP",
7669
+ "MAPPING_VALUE_NO_OPERATOR",
7670
+ "MAPPING_VALUE_PRODUCERS",
7671
+ "BATCH_WITHOUT_PUSH_BATCH",
7672
+ "MALFORMED_REFERENCE",
8058
7673
  // Resolution (getFlowSettings, as the bundler resolves the flow)
8059
7674
  "UNRESOLVED_REFERENCE",
8060
7675
  "MISSING_ENV",
@@ -8071,7 +7686,6 @@ var VALIDATE_CODES = [
8071
7686
  "INVALID_TAGGING",
8072
7687
  "INVALID_SCHEMA",
8073
7688
  "INVALID_EXTENDS",
8074
- "INVALID_SECTION",
8075
7689
  "INVALID_EVENTS",
8076
7690
  "CIRCULAR_EXTENDS",
8077
7691
  "INVALID_ENTITY_KEY",
@@ -8346,191 +7960,8 @@ function exitCodeOf(result, strict) {
8346
7960
  return result.valid ? 0 : 1;
8347
7961
  }
8348
7962
 
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
7963
  // src/commands/auth/index.ts
8533
- import { z as z5 } from "zod";
7964
+ import { z as z3 } from "zod";
8534
7965
 
8535
7966
  // src/core/api-error.ts
8536
7967
  var EXIT_RETRYABLE = 75;
@@ -8588,31 +8019,166 @@ ${err.message}
8588
8019
  process.exit(1);
8589
8020
  }
8590
8021
 
8022
+ // src/core/app-fetch.ts
8023
+ import { z } from "zod";
8024
+
8025
+ // src/lib/config-file.ts
8026
+ import {
8027
+ readFileSync as readFileSync3,
8028
+ writeFileSync,
8029
+ mkdirSync,
8030
+ unlinkSync,
8031
+ chmodSync,
8032
+ renameSync
8033
+ } from "fs";
8034
+ import { randomBytes } from "crypto";
8035
+ import { join as join5 } from "path";
8036
+ import { homedir } from "os";
8037
+ function getConfigDir() {
8038
+ const xdgConfig = process.env.XDG_CONFIG_HOME;
8039
+ const base = xdgConfig || join5(homedir(), ".config");
8040
+ return join5(base, "walkeros");
8041
+ }
8042
+ function getConfigPath() {
8043
+ return join5(getConfigDir(), "config.json");
8044
+ }
8045
+ function readConfig() {
8046
+ const configPath = getConfigPath();
8047
+ try {
8048
+ const content = readFileSync3(configPath, "utf-8");
8049
+ return JSON.parse(content);
8050
+ } catch {
8051
+ return null;
8052
+ }
8053
+ }
8054
+ function replaceConfigFile(config) {
8055
+ const dir = getConfigDir();
8056
+ mkdirSync(dir, { recursive: true, mode: 448 });
8057
+ const configPath = getConfigPath();
8058
+ const tempPath = `${configPath}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
8059
+ try {
8060
+ writeFileSync(tempPath, JSON.stringify(config, null, 2), { mode: 384 });
8061
+ chmodSync(tempPath, 384);
8062
+ renameSync(tempPath, configPath);
8063
+ } catch (error) {
8064
+ try {
8065
+ unlinkSync(tempPath);
8066
+ } catch {
8067
+ }
8068
+ throw error;
8069
+ }
8070
+ }
8071
+ function writeConfig(config) {
8072
+ replaceConfigFile({ ...readConfig() ?? {}, ...config });
8073
+ }
8074
+ function writeTelemetryOnlyConfig(partial) {
8075
+ writeConfig(partial);
8076
+ }
8077
+ function resolveAppUrl() {
8078
+ const envUrl = process.env.WALKEROS_APP_URL;
8079
+ if (envUrl) return envUrl;
8080
+ const config = readConfig();
8081
+ if (config?.appUrl) return config.appUrl;
8082
+ return "https://app.walkeros.io";
8083
+ }
8084
+
8085
+ // src/lib/secure-url.ts
8086
+ function isLoopback(hostname) {
8087
+ return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
8088
+ }
8089
+ function requireSecureUrl(url) {
8090
+ let parsed;
8091
+ try {
8092
+ parsed = new URL(url);
8093
+ } catch {
8094
+ return url;
8095
+ }
8096
+ if (parsed.protocol !== "http:" || isLoopback(parsed.hostname)) return url;
8097
+ throw new Error(
8098
+ `Refusing to send walkerOS credentials over plain http to ${url}. Use https, or localhost / 127.0.0.1 / [::1] for local development.`
8099
+ );
8100
+ }
8101
+
8102
+ // src/core/client-context.ts
8103
+ var context;
8104
+ function setClientContext(input) {
8105
+ const envType = process.env.WALKEROS_CLIENT_TYPE;
8106
+ const type = envType ?? input.type ?? "cli";
8107
+ context = { type, version: input.version };
8108
+ }
8109
+ function getClientContext() {
8110
+ return context;
8111
+ }
8112
+ function resetClientContext() {
8113
+ context = void 0;
8114
+ }
8115
+ function clientContextHeaders() {
8116
+ if (!context) return {};
8117
+ return {
8118
+ "User-Agent": `walkeros-${context.type}/${context.version}`,
8119
+ "X-WalkerOS-Client": context.type,
8120
+ "X-WalkerOS-Client-Version": context.version
8121
+ };
8122
+ }
8123
+
8124
+ // src/core/app-fetch.ts
8125
+ var AppErrorSchema = z.object({
8126
+ error: z.object({ message: z.string().min(1) })
8127
+ });
8128
+ function appErrorMessage(body) {
8129
+ const parsed = AppErrorSchema.safeParse(body);
8130
+ return parsed.success ? parsed.data.error.message : void 0;
8131
+ }
8132
+ async function appFetch(path23, init = {}) {
8133
+ const url = `${(init.baseUrl ?? resolveAppUrl()).replace(/\/+$/, "")}${path23}`;
8134
+ const headers = new Headers(clientContextHeaders());
8135
+ for (const [name, value] of Object.entries(init.headers ?? {}))
8136
+ headers.set(name, value);
8137
+ if (init.token && !headers.has("Authorization"))
8138
+ headers.set("Authorization", `Bearer ${init.token}`);
8139
+ if (headers.has("Authorization")) requireSecureUrl(url);
8140
+ const request = { headers };
8141
+ if (init.method && init.method !== "GET") request.method = init.method;
8142
+ if (init.body !== void 0) request.body = init.body;
8143
+ if (init.signal) request.signal = init.signal;
8144
+ if (init.redirect) request.redirect = init.redirect;
8145
+ return (init.fetch ?? fetch)(url, request);
8146
+ }
8147
+
8148
+ // src/core/app-paths.ts
8149
+ var APP_PATHS = {
8150
+ whoami: "/api/auth/whoami",
8151
+ health: "/api/health",
8152
+ telemetry: "/api/telemetry",
8153
+ openapi: "/api/openapi.json"
8154
+ };
8155
+
8591
8156
  // src/commands/api/index.ts
8592
8157
  import { once } from "events";
8593
8158
  import { readFile as readFile2 } from "fs/promises";
8594
- import { z as z4 } from "zod";
8159
+ import { z as z2 } from "zod";
8160
+ var NOT_SIGNED_IN = "no token: set WALKEROS_TOKEN to a token from Account > Automation tokens in the walkerOS app";
8595
8161
  var ERROR_BODY_LIMIT = 64 * 1024;
8596
- var DocumentSchema = z4.object({
8597
- paths: z4.record(z4.string(), z4.record(z4.string(), z4.unknown())),
8598
- components: z4.record(z4.string(), z4.record(z4.string(), z4.unknown())).optional()
8162
+ var DocumentSchema = z2.object({
8163
+ paths: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())),
8164
+ components: z2.record(z2.string(), z2.record(z2.string(), z2.unknown())).optional()
8599
8165
  });
8600
- var OperationSchema = z4.object({
8601
- summary: z4.string().optional(),
8602
- description: z4.string().optional(),
8603
- parameters: z4.array(z4.unknown()).optional(),
8604
- requestBody: z4.unknown().optional(),
8605
- responses: z4.record(z4.string(), z4.unknown()).optional()
8166
+ var OperationSchema = z2.object({
8167
+ summary: z2.string().optional(),
8168
+ description: z2.string().optional(),
8169
+ parameters: z2.array(z2.unknown()).optional(),
8170
+ requestBody: z2.unknown().optional(),
8171
+ responses: z2.record(z2.string(), z2.unknown()).optional()
8606
8172
  });
8607
- var OptionsSchema = z4.object({
8608
- data: z4.string().optional(),
8609
- header: z4.array(z4.string()).default([]),
8610
- project: z4.string().optional(),
8611
- yes: z4.boolean().optional()
8173
+ var OptionsSchema = z2.object({
8174
+ data: z2.string().optional(),
8175
+ header: z2.array(z2.string()).default([]),
8176
+ project: z2.string().optional(),
8177
+ yes: z2.boolean().optional()
8612
8178
  });
8613
8179
 
8614
8180
  // src/commands/auth/index.ts
8615
- async function readJson3(response) {
8181
+ async function readJson2(response) {
8616
8182
  try {
8617
8183
  return await response.json();
8618
8184
  } catch {
@@ -8620,19 +8186,17 @@ async function readJson3(response) {
8620
8186
  }
8621
8187
  }
8622
8188
  async function whoami() {
8623
- const token = await resolveAccessToken();
8624
- if (!token)
8625
- throw new Error("Not authenticated. Run `walkeros auth login` first.");
8189
+ const token = resolveAccessToken();
8190
+ if (!token) throw new Error(NOT_SIGNED_IN);
8626
8191
  const response = await appFetch(APP_PATHS.whoami, { token });
8627
- const body = await readJson3(response);
8192
+ const body = await readJson2(response);
8628
8193
  if (!response.ok)
8629
8194
  throw new Error(appErrorMessage(body) ?? `HTTP ${response.status}`);
8630
8195
  return body;
8631
8196
  }
8632
- var IdentitySchema = z5.object({
8633
- email: z5.string().optional(),
8634
- userId: z5.string().optional(),
8635
- projectId: z5.string().nullish()
8197
+ var IdentitySchema = z3.object({
8198
+ email: z3.string().optional(),
8199
+ userId: z3.string().optional()
8636
8200
  });
8637
8201
  async function whoamiCommand(options) {
8638
8202
  const logger = createCLILogger(options);
@@ -8649,7 +8213,6 @@ async function whoamiCommand(options) {
8649
8213
  const data = identity.data;
8650
8214
  if (data.email) logger.info(data.email);
8651
8215
  if (data.userId) logger.info(`User: ${data.userId}`);
8652
- if (data.projectId) logger.info(`Project: ${data.projectId}`);
8653
8216
  }
8654
8217
  } catch (error) {
8655
8218
  handleCliError(error);
@@ -8724,7 +8287,7 @@ function telemetryDisableCommand() {
8724
8287
  }
8725
8288
 
8726
8289
  // src/index.ts
8727
- import { validateFlowStructure as validateFlowStructure2 } from "@walkeros/core/dev";
8290
+ import { validateFlowStructure as validateFlowStructure3 } from "@walkeros/core/dev";
8728
8291
 
8729
8292
  // src/commands/bundle/wrap.ts
8730
8293
  import * as path21 from "path";
@@ -8800,11 +8363,12 @@ async function wrapSkeleton(options) {
8800
8363
  format: "esm",
8801
8364
  platform,
8802
8365
  outfile: outputPath,
8803
- // Resolve `@walkeros/core` (used by the preview activator) from the CLI
8804
- // package's own dependency tree and the workspace root. Without this,
8805
- // esbuild looks under the temp entryDir which has no node_modules.
8806
- // The wrap step always runs from inside the CLI process; both the
8807
- // CLI's local node_modules and the workspace root are safe anchors.
8366
+ // Resolve `@walkeros/web-core` (the Tag Mode loader and the preview
8367
+ // activator) from the CLI package's own dependency tree and the
8368
+ // workspace root. Without this, esbuild looks under the temp entryDir
8369
+ // which has no node_modules. The wrap step always runs from inside the
8370
+ // CLI process; both the CLI's local node_modules and the workspace root
8371
+ // are safe anchors.
8808
8372
  nodePaths: getNodeResolutionPaths(),
8809
8373
  treeShaking: true,
8810
8374
  logLevel: "error",
@@ -8819,7 +8383,7 @@ async function wrapSkeleton(options) {
8819
8383
  };
8820
8384
  if (platform === "browser") {
8821
8385
  esbuildOptions.format = "iife";
8822
- esbuildOptions.plugins = [cliCorePlugin()];
8386
+ esbuildOptions.plugins = [cliPackagesPlugin()];
8823
8387
  const needs = readNeedsMarker(skeletonText);
8824
8388
  esbuildOptions.define = {
8825
8389
  "process.env.NODE_ENV": '"production"',
@@ -8854,10 +8418,10 @@ import fs22 from "fs-extra";
8854
8418
  import { FlowReferenceError as FlowReferenceError2 } from "@walkeros/core";
8855
8419
 
8856
8420
  // src/schemas/build-manifest.ts
8857
- import { z as z6 } from "@walkeros/core/dev";
8421
+ import { z as z4 } from "@walkeros/core/dev";
8858
8422
  var BUILD_MANIFEST_VERSION = 1;
8859
- var HttpUrlSchema = z6.url({ protocol: /^https?$/ });
8860
- var OutputNameSchema = z6.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)");
8423
+ var HttpUrlSchema = z4.url({ protocol: /^https?$/ });
8424
+ 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
8425
  var BUNDLE_TARGET_NAMES = [
8862
8426
  "cdn",
8863
8427
  "cdn-skeleton",
@@ -8873,8 +8437,8 @@ var RESERVED_HEADERS = /* @__PURE__ */ new Set([
8873
8437
  var OutputFields = {
8874
8438
  outputName: OutputNameSchema,
8875
8439
  putUrl: HttpUrlSchema.describe("Presigned PUT for exactly this output"),
8876
- contentType: z6.string().min(1).optional().describe("Content-Type sent with the PUT (must match a signed header)"),
8877
- headers: z6.record(z6.string().min(1), z6.string()).refine(
8440
+ contentType: z4.string().min(1).optional().describe("Content-Type sent with the PUT (must match a signed header)"),
8441
+ headers: z4.record(z4.string().min(1), z4.string()).refine(
8878
8442
  (headers) => Object.keys(headers).every(
8879
8443
  (name) => !RESERVED_HEADERS.has(name.toLowerCase())
8880
8444
  ),
@@ -8883,68 +8447,68 @@ var OutputFields = {
8883
8447
  "Extra headers sent with the PUT (for headers a presign signs); never logged"
8884
8448
  )
8885
8449
  };
8886
- var BuildBundleArtifactSchema = z6.object({
8887
- target: z6.enum(BUNDLE_TARGET_NAMES).describe("Named bundle target"),
8450
+ var BuildBundleArtifactSchema = z4.object({
8451
+ target: z4.enum(BUNDLE_TARGET_NAMES).describe("Named bundle target"),
8888
8452
  ...OutputFields
8889
8453
  }).strict();
8890
- var BuildWrapOptionsSchema = z6.object({
8891
- windowCollector: z6.string().min(1).optional(),
8892
- windowElb: z6.string().min(1).optional(),
8893
- preview: z6.object({
8894
- enabled: z6.boolean(),
8895
- keyring: z6.array(
8896
- z6.object({ kid: z6.string(), spki: z6.string() }).strict()
8454
+ var BuildWrapOptionsSchema = z4.object({
8455
+ windowCollector: z4.string().min(1).optional(),
8456
+ windowElb: z4.string().min(1).optional(),
8457
+ preview: z4.object({
8458
+ enabled: z4.boolean(),
8459
+ keyring: z4.array(
8460
+ z4.object({ kid: z4.string(), spki: z4.string() }).strict()
8897
8461
  ),
8898
- iss: z6.string(),
8899
- pb: z6.string().optional(),
8900
- acceptForeign: z6.boolean().optional(),
8901
- demoAllowlist: z6.array(z6.string()).optional(),
8902
- previewOrigin: z6.string()
8462
+ iss: z4.string(),
8463
+ pb: z4.string().optional(),
8464
+ acceptForeign: z4.boolean().optional(),
8465
+ demoAllowlist: z4.array(z4.string()).optional(),
8466
+ previewOrigin: z4.string()
8903
8467
  }).strict().optional(),
8904
- previewGrantTargets: z6.array(z6.string()).optional(),
8905
- observe: z6.object({
8906
- url: z6.string(),
8907
- binding: z6.string(),
8908
- flowId: z6.string().optional(),
8909
- level: z6.enum(["off", "standard", "trace"]).optional(),
8910
- sample: z6.number().min(0).max(1).optional()
8468
+ previewGrantTargets: z4.array(z4.string()).optional(),
8469
+ observe: z4.object({
8470
+ url: z4.string(),
8471
+ binding: z4.string(),
8472
+ flowId: z4.string().optional(),
8473
+ level: z4.enum(["off", "standard", "trace"]).optional(),
8474
+ sample: z4.number().min(0).max(1).optional()
8911
8475
  }).strict().optional(),
8912
- moin: z6.object({ app: z6.string(), base: z6.string() }).strict().optional().describe("Tag Mode loader target; absent, the production app"),
8913
- minify: z6.boolean().optional(),
8914
- minifyOptions: z6.object({
8915
- identifiers: z6.boolean().optional(),
8916
- syntax: z6.boolean().optional(),
8917
- whitespace: z6.boolean().optional(),
8918
- keepNames: z6.boolean().optional(),
8919
- legalComments: z6.enum(["none", "inline", "eof", "linked", "external"]).optional()
8476
+ moin: z4.object({ app: z4.string(), base: z4.string() }).strict().optional().describe("Tag Mode loader target; absent, the production app"),
8477
+ minify: z4.boolean().optional(),
8478
+ minifyOptions: z4.object({
8479
+ identifiers: z4.boolean().optional(),
8480
+ syntax: z4.boolean().optional(),
8481
+ whitespace: z4.boolean().optional(),
8482
+ keepNames: z4.boolean().optional(),
8483
+ legalComments: z4.enum(["none", "inline", "eof", "linked", "external"]).optional()
8920
8484
  }).strict().optional(),
8921
- target: z6.string().min(1).optional().describe("esbuild target")
8485
+ target: z4.string().min(1).optional().describe("esbuild target")
8922
8486
  }).strict().describe("Options forwarded to wrapSkeleton");
8923
- var BuildWrapArtifactSchema = z6.object({
8924
- target: z6.literal("wrap"),
8925
- platform: z6.enum(["browser", "node"]),
8926
- skeleton: z6.union([
8927
- z6.object({ url: HttpUrlSchema }).strict(),
8928
- z6.object({ artifact: OutputNameSchema }).strict()
8487
+ var BuildWrapArtifactSchema = z4.object({
8488
+ target: z4.literal("wrap"),
8489
+ platform: z4.enum(["browser", "node"]),
8490
+ skeleton: z4.union([
8491
+ z4.object({ url: HttpUrlSchema }).strict(),
8492
+ z4.object({ artifact: OutputNameSchema }).strict()
8929
8493
  ]).describe(
8930
8494
  "The skeleton to wrap: a GET URL, or the outputName of an earlier bundle artifact in this manifest"
8931
8495
  ),
8932
8496
  options: BuildWrapOptionsSchema.optional(),
8933
8497
  ...OutputFields
8934
8498
  }).strict();
8935
- var BuildArtifactSchema = z6.union([
8499
+ var BuildArtifactSchema = z4.union([
8936
8500
  BuildBundleArtifactSchema,
8937
8501
  BuildWrapArtifactSchema
8938
8502
  ]);
8939
- var BuildManifestSchema = z6.object({
8940
- version: z6.literal(BUILD_MANIFEST_VERSION),
8941
- toolchain: z6.string().min(1).describe("Exact @walkeros/cli version; any other version refuses"),
8942
- flowConfig: z6.record(z6.string(), z6.unknown()).optional().describe("Flow.Json to bundle; required when any bundle artifact is"),
8943
- flowName: z6.string().min(1).optional(),
8944
- buildEnv: z6.record(z6.string(), z6.string()).optional().describe(
8503
+ var BuildManifestSchema = z4.object({
8504
+ version: z4.literal(BUILD_MANIFEST_VERSION),
8505
+ toolchain: z4.string().min(1).describe("Exact @walkeros/cli version; any other version refuses"),
8506
+ flowConfig: z4.record(z4.string(), z4.unknown()).optional().describe("Flow.Json to bundle; required when any bundle artifact is"),
8507
+ flowName: z4.string().min(1).optional(),
8508
+ buildEnv: z4.record(z4.string(), z4.string()).optional().describe(
8945
8509
  "Base env for web $env, beneath config.bundle.env. Never the CLI process's own env"
8946
8510
  ),
8947
- artifacts: z6.array(BuildArtifactSchema).min(1),
8511
+ artifacts: z4.array(BuildArtifactSchema).min(1),
8948
8512
  resultPutUrl: HttpUrlSchema.describe("Presigned PUT for the result JSON")
8949
8513
  }).loose().superRefine((manifest, ctx) => {
8950
8514
  const seen = /* @__PURE__ */ new Set();
@@ -8987,21 +8551,21 @@ var BUILD_ERROR_CODES = [
8987
8551
  "BUILD_FAILED",
8988
8552
  "UPLOAD_FAILED"
8989
8553
  ];
8990
- var BuildResultSchema = z6.object({
8991
- ok: z6.boolean(),
8992
- toolchain: z6.string().describe("The CLI version that ran the build"),
8993
- artifacts: z6.array(
8994
- z6.object({
8995
- target: z6.string(),
8996
- outputName: z6.string(),
8997
- bytes: z6.number().int().nonnegative(),
8998
- sha256: z6.string()
8554
+ var BuildResultSchema = z4.object({
8555
+ ok: z4.boolean(),
8556
+ toolchain: z4.string().describe("The CLI version that ran the build"),
8557
+ artifacts: z4.array(
8558
+ z4.object({
8559
+ target: z4.string(),
8560
+ outputName: z4.string(),
8561
+ bytes: z4.number().int().nonnegative(),
8562
+ sha256: z4.string()
8999
8563
  })
9000
8564
  ).describe("Outputs PUT successfully, in manifest order"),
9001
- error: z6.object({
9002
- code: z6.enum(BUILD_ERROR_CODES),
9003
- message: z6.string(),
9004
- outputName: z6.string().optional().describe("The artifact being built when the error occurred")
8565
+ error: z4.object({
8566
+ code: z4.enum(BUILD_ERROR_CODES),
8567
+ message: z4.string(),
8568
+ outputName: z4.string().optional().describe("The artifact being built when the error occurred")
9005
8569
  }).optional()
9006
8570
  }).meta({ id: "BuildResult", title: "walkeros bundle --manifest result" });
9007
8571
 
@@ -9052,16 +8616,16 @@ async function fetchWithRetry(url, init, options) {
9052
8616
  if (failure instanceof Response && !isTransientStatus(failure.status)) {
9053
8617
  throw new Error(`${label} failed: ${reason}`);
9054
8618
  }
9055
- const delay4 = BACKOFF_MS[attempt - 1];
9056
- if (delay4 === void 0) {
8619
+ const delay2 = BACKOFF_MS[attempt - 1];
8620
+ if (delay2 === void 0) {
9057
8621
  throw new Error(
9058
8622
  `${label} failed after ${maxAttempts} attempts: ${reason}`
9059
8623
  );
9060
8624
  }
9061
8625
  warn?.(
9062
- `${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${delay4 / 1e3}s`
8626
+ `${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${delay2 / 1e3}s`
9063
8627
  );
9064
- await sleep(delay4);
8628
+ await sleep(delay2);
9065
8629
  }
9066
8630
  }
9067
8631
 
@@ -9549,22 +9113,13 @@ export {
9549
9113
  bundle,
9550
9114
  bundleCommand,
9551
9115
  classifyStepProperties,
9552
- clearAuthFields,
9553
9116
  clientContextHeaders,
9554
9117
  collectKnownSecrets,
9555
- completeDeviceLogin,
9556
9118
  containsCodeMarkers,
9557
- credentialSource,
9558
- deleteConfig,
9559
9119
  formatPushResult,
9560
- getAuthHeaders,
9561
9120
  getClientContext,
9562
9121
  loadConfig,
9563
9122
  loadJsonConfig,
9564
- login,
9565
- loginCommand,
9566
- logout,
9567
- logoutCommand,
9568
9123
  push,
9569
9124
  pushCommand,
9570
9125
  readConfig,
@@ -9573,7 +9128,6 @@ export {
9573
9128
  resolveAppUrl,
9574
9129
  resolveExportName,
9575
9130
  resolveManifestSource,
9576
- resolveToken,
9577
9131
  runBuildManifest,
9578
9132
  selectDevExamples,
9579
9133
  setClientContext,
@@ -9581,14 +9135,13 @@ export {
9581
9135
  simulateDestination,
9582
9136
  simulateSource,
9583
9137
  simulateTransformer,
9584
- startDeviceAuthorization,
9585
9138
  telemetry_exports as telemetry,
9586
9139
  telemetryDisableCommand,
9587
9140
  telemetryEnableCommand,
9588
9141
  telemetryStatusCommand,
9589
9142
  validate,
9590
9143
  validateCommand,
9591
- validateFlowStructure2 as validateFlowStructure,
9144
+ validateFlowStructure3 as validateFlowStructure,
9592
9145
  whoami,
9593
9146
  whoamiCommand,
9594
9147
  wrapSkeleton,