@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.
Files changed (51) hide show
  1. package/CHANGELOG.md +115 -3
  2. package/README.md +2 -2
  3. package/dist/cli.js +4149 -4149
  4. package/dist/dev.d.ts +51 -3
  5. package/dist/dev.js +186 -0
  6. package/dist/dev.js.map +1 -1
  7. package/dist/examples/README.md +12 -1
  8. package/dist/examples/contracts/app.json +261 -0
  9. package/dist/examples/contracts/base.json +708 -0
  10. package/dist/examples/contracts/ecommerce.json +963 -0
  11. package/dist/examples/contracts/leadgen.json +240 -0
  12. package/dist/examples/contracts/publisher.json +372 -0
  13. package/dist/examples/contracts/saas.json +229 -0
  14. package/dist/examples/contracts/travel.json +234 -0
  15. package/dist/examples/customers/README.md +4 -1
  16. package/dist/examples/event.json +1 -1
  17. package/dist/examples/flow-complete.json +107 -130
  18. package/dist/examples/flow-complete.md +12 -10
  19. package/dist/examples/flow-order-complete.json +1 -1
  20. package/dist/examples/flow.json +1 -1
  21. package/dist/examples/index.d.ts +34 -4
  22. package/dist/examples/index.js +128 -139
  23. package/dist/examples/index.js.map +1 -1
  24. package/dist/examples/shared/README.md +4 -0
  25. package/dist/index.d.ts +63 -223
  26. package/dist/index.js +572 -992
  27. package/dist/index.js.map +1 -1
  28. package/dist/validate.d.ts +1 -1
  29. package/dist/validate.js +337 -204
  30. package/dist/validate.js.map +1 -1
  31. package/examples/README.md +12 -1
  32. package/examples/contracts/app.json +261 -0
  33. package/examples/contracts/base.json +708 -0
  34. package/examples/contracts/ecommerce.json +963 -0
  35. package/examples/contracts/leadgen.json +240 -0
  36. package/examples/contracts/publisher.json +372 -0
  37. package/examples/contracts/saas.json +229 -0
  38. package/examples/contracts/travel.json +234 -0
  39. package/examples/customers/README.md +4 -1
  40. package/examples/event.json +1 -1
  41. package/examples/flow-complete.json +107 -130
  42. package/examples/flow-complete.md +12 -10
  43. package/examples/flow-order-complete.json +1 -1
  44. package/examples/flow.json +1 -1
  45. package/examples/shared/README.md +4 -0
  46. package/package.json +30 -30
  47. package/src/telemetry/flow.json +42 -34
  48. package/dist/examples/test.html +0 -43
  49. package/dist/examples/web-serve.js +0 -25503
  50. package/examples/test.html +0 -43
  51. 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
- 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";
@@ -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
- const isLocalPath = pkg.startsWith(".") || pkg.startsWith("/");
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 errorCode2(error) {
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 = errorCode2(error);
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 (errorCode2(error) !== "ENOENT") throw error;
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 delay2(ms) {
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 delay2(sleepMs);
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 as readFileSync2 } from "fs";
2151
+ import { readFileSync } from "fs";
2571
2152
  import { fileURLToPath } from "url";
2572
- import { dirname as dirname3, join as join4 } from "path";
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
- join4(versionDirname, "../package.json"),
2158
+ join3(versionDirname, "../package.json"),
2578
2159
  // dist/ or src/
2579
- join4(versionDirname, "../../package.json")
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 readFileSync2(p, "utf-8");
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
- ${initFn ? `init: ${initFn},` : ""}
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
- ${initFn ? `init: ${initFn},` : ""}
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 = [cliCorePlugin()];
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 CLI_CORE = "walkeros-cli-core";
3111
- function cliCorePlugin() {
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: CLI_CORE,
2696
+ name: CLI_PACKAGES,
3115
2697
  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
- });
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
- if (context.logger) config.logger = context.logger;
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 = ${JSON.stringify(literal)};`;
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
- if (context.logger) config.logger = context.logger;
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 getPlatform3, stepId } from "@walkeros/core";
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, delay4, ...args) => {
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: delay4 ?? 0,
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, delay4, ...args) => {
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: delay4 ?? 0,
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 getPlatform2 } from "@walkeros/core";
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 = getPlatform2(flowSettings);
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 = getPlatform3(flowSettings);
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 isObject10 } from "@walkeros/core";
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((k) => isObject5(obj[k]));
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
- warnings.push({
6131
+ errors.push({
6515
6132
  path: `${name}.${key}`,
6516
- message: `Unknown contract key "${key}" is ignored`,
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 isObject8,
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 { schemas as schemas4, validateFlowStructure } from "@walkeros/core/dev";
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 isObject7,
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
- var CLIENT_HEADER = "walkeros-cli/4.8.1";
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 (!isObject7(entry))
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 (isObject7(current)) current = current[segment];
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 (isObject7(value))
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 bundlePin(rawFlow, name) {
6975
- const config = isObject7(rawFlow) ? rawFlow.config : void 0;
6976
- const bundle2 = isObject7(config) ? config.bundle : void 0;
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 (!isObject7(settings)) return void 0;
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(source) {
7049
- return source.localPath ? `path:${source.localPath}` : `${source.name}@${source.version ?? "latest"}`;
6638
+ function sourceKey({ packageName, spec }) {
6639
+ return spec.path !== void 0 ? `path:${spec.path}` : `${packageName}@${spec.version ?? "latest"}`;
7050
6640
  }
7051
- function cachedSchema(source, context2) {
7052
- const key = sourceKey(source);
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(source, context2);
6645
+ pending = loadSchema(resolved, context2);
7056
6646
  context2.cache.set(key, pending);
7057
6647
  }
7058
6648
  return pending;
7059
6649
  }
7060
- function cachedCompile(source, exportName, settings, context2) {
7061
- const key = `${sourceKey(source)}#${exportName ?? ""}`;
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, rawFlow, check, context2) {
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
- const source = packageSource(spec, rawFlow);
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(source, context2);
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 ${source.name}${source.version ? `@${source.version}` : ""} could not be loaded: ${getErrorMessage3(error)}`,
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: source.name,
6703
+ package: label,
7096
6704
  ...schema.version ? { version: schema.version } : {}
7097
6705
  };
7098
6706
  const { exportName } = resolveExportName(
7099
- resolvedFlow,
6707
+ resolved.normalizedFlow,
7100
6708
  SECTION_KIND[target.section],
7101
6709
  target.key
7102
6710
  );
7103
- const version = schema.version ?? source.version;
6711
+ const version = schema.version ?? pinned;
7104
6712
  const selection = selectSettingsSchema(
7105
6713
  schema,
7106
- version ? `${source.name}@${version}` : source.name,
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
- source,
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 ${source.name} has no settings schema`,
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 ${source.name} cannot be compiled: ${compiled.message}`,
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 = isObject7(step?.config) ? step.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 OPEN_STEP_KINDS = [
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 = isObject8(rawFlow[section]) ? rawFlow[section] : {};
6833
+ const steps = isObject9(rawFlow[section]) ? rawFlow[section] : {};
7224
6834
  for (const [key, entry] of Object.entries(steps)) {
7225
- if (!isObject8(entry) || entry.package === void 0) continue;
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
- result.warnings.push(...outcome.findings);
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 = isObject8(input) ? input : {};
6893
+ const config = isObject9(input) ? input : {};
7285
6894
  const flowsValue = config.flows;
7286
- const flows = isObject8(flowsValue) ? flowsValue : void 0;
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) continue;
7307
- errors.push({ path: path23, message: issue.message, code: "SCHEMA_VALIDATION" });
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 (!isObject8(flowValue)) continue;
6938
+ if (!isObject9(flowValue)) continue;
7325
6939
  const transformersValue = flowValue.transformers;
7326
- if (isObject8(transformersValue)) {
6940
+ if (isObject9(transformersValue)) {
7327
6941
  for (const [name, transformerValue] of Object.entries(
7328
6942
  transformersValue
7329
6943
  )) {
7330
- if (!isObject8(transformerValue)) continue;
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 OPEN_STEP_KINDS) {
6955
+ for (const [section, kind] of STEP_KINDS2) {
7342
6956
  const steps = flowValue[section];
7343
- if (!isObject8(steps)) continue;
6957
+ if (!isObject9(steps)) continue;
7344
6958
  for (const [name, step] of Object.entries(steps)) {
7345
- if (!isObject8(step)) continue;
6959
+ if (!isObject9(step)) continue;
7346
6960
  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
- }
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 (!isObject8(flowValue)) continue;
6982
+ if (!isObject9(flowValue)) continue;
7375
6983
  const flowConfig = flowValue.config;
7376
- if (!isObject8(flowConfig)) continue;
6984
+ if (!isObject9(flowConfig)) continue;
7377
6985
  const bundle2 = flowConfig.bundle;
7378
- if (!isObject8(bundle2)) continue;
6986
+ if (!isObject9(bundle2)) continue;
7379
6987
  const packages = bundle2.packages;
7380
- if (!isObject8(packages)) continue;
6988
+ if (!isObject9(packages)) continue;
7381
6989
  for (const [pkgName, pkgConfigValue] of Object.entries(packages)) {
7382
- if (!isObject8(pkgConfigValue)) continue;
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 = validateFlowStructure({
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
- isObject8(resolvedConfig) && isObject8(resolvedConfig.settings) ? resolvedConfig.settings : void 0
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 (!isObject8(dest.config)) continue;
7082
+ if (!isObject9(dest.config)) continue;
7475
7083
  const mapping = dest.config.mapping;
7476
- if (!isObject8(mapping)) continue;
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 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);
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 (isObject8(value)) return [isObject8(value.event) ? value.event : value];
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 isObject8(first) ? [first] : [];
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 isObject8(out) && Object.keys(out).length > 0 ? [out] : [];
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 = isObject8(current) ? current[key] : void 0;
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 (isObject8(self) && self.stop === true && typeof last === "number" && Array.isArray(list) && last < list.length - 1 && once2(`stop:${where(node.path)}`)) {
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 (isObject8(entry)) {
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 (!isObject8(rule))
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 ?? (isObject8(step.config) && isObject8(step.config.settings) ? step.config.settings : {});
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 = isObject8(settings.output) ? settings.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 || !isObject8(example.in)) continue;
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 isObject9 } from "@walkeros/core";
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 isObject9(value) && RuleSchema.safeParse(value).success;
7528
+ return isObject10(value) && RuleSchema.safeParse(value).success;
7891
7529
  }
7892
7530
  function isNestedActions(key, value) {
7893
- if (key.includes(" ") || !isObject9(value)) return false;
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 (!isObject9(input)) {
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
- "TRANSFORMER_MAPPING_NO_OP",
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 = isObject10(input) ? input.contract : void 0;
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 z5 } from "zod";
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 z4 } from "zod";
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 = 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()
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 = 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()
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 = z4.object({
8608
- data: z4.string().optional(),
8609
- header: z4.array(z4.string()).default([]),
8610
- project: z4.string().optional(),
8611
- yes: z4.boolean().optional()
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 readJson3(response) {
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 = await resolveAccessToken();
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 readJson3(response);
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 = z5.object({
8633
- email: z5.string().optional(),
8634
- userId: z5.string().optional(),
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 validateFlowStructure2 } from "@walkeros/core/dev";
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` (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.
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 = [cliCorePlugin()];
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 z6 } from "@walkeros/core/dev";
8448
+ import { z as z4 } from "@walkeros/core/dev";
8858
8449
  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)");
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: 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(
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 = z6.object({
8887
- target: z6.enum(BUNDLE_TARGET_NAMES).describe("Named bundle 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 = 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()
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: z6.string(),
8899
- pb: z6.string().optional(),
8900
- acceptForeign: z6.boolean().optional(),
8901
- demoAllowlist: z6.array(z6.string()).optional(),
8902
- previewOrigin: z6.string()
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: 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()
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: 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()
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: z6.string().min(1).optional().describe("esbuild target")
8512
+ target: z4.string().min(1).optional().describe("esbuild target")
8922
8513
  }).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()
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 = z6.union([
8526
+ var BuildArtifactSchema = z4.union([
8936
8527
  BuildBundleArtifactSchema,
8937
8528
  BuildWrapArtifactSchema
8938
8529
  ]);
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(
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: z6.array(BuildArtifactSchema).min(1),
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 = 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()
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: 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")
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 delay4 = BACKOFF_MS[attempt - 1];
9056
- if (delay4 === void 0) {
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 ${delay4 / 1e3}s`
8653
+ `${label} attempt ${attempt}/${maxAttempts} failed: ${reason}, retrying in ${delay2 / 1e3}s`
9063
8654
  );
9064
- await sleep(delay4);
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
- validateFlowStructure2 as validateFlowStructure,
9171
+ validateFlowStructure3 as validateFlowStructure,
9592
9172
  whoami,
9593
9173
  whoamiCommand,
9594
9174
  wrapSkeleton,