@walkeros/cli 4.3.0-next-1784055686454 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -665,6 +665,7 @@ interface ValidationWarning {
665
665
  path: string;
666
666
  message: string;
667
667
  suggestion?: string;
668
+ code?: string;
668
669
  }
669
670
  interface ValidateResult {
670
671
  valid: boolean;
@@ -912,8 +913,8 @@ interface paths {
912
913
  cookie?: never;
913
914
  };
914
915
  /**
915
- * Verify magic link token
916
- * @description Verify a magic link token and create an authenticated session. Redirects to the specified URL or home page.
916
+ * Legacy magic link entry point
917
+ * @description Side-effect-free redirector to the /auth/verify page for links minted before the page-URL change. Never consumes the token; redemption happens via POST.
917
918
  */
918
919
  get: {
919
920
  parameters: {
@@ -929,8 +930,8 @@ interface paths {
929
930
  };
930
931
  requestBody?: never;
931
932
  responses: {
932
- /** @description Redirect to target URL with session cookie set */
933
- 302: {
933
+ /** @description Redirect to the /auth/verify page with the token forwarded */
934
+ 307: {
934
935
  headers: {
935
936
  [name: string]: unknown;
936
937
  };
@@ -939,7 +940,43 @@ interface paths {
939
940
  };
940
941
  };
941
942
  put?: never;
942
- post?: never;
943
+ /**
944
+ * Redeem magic link token
945
+ * @description Redeem a magic link token and create an authenticated session. Redeems immediately when the browser-nonce cookie from the magic-link request matches; otherwise answers confirm_required and expects a follow-up call with confirm: true.
946
+ */
947
+ post: {
948
+ parameters: {
949
+ query?: never;
950
+ header?: never;
951
+ path?: never;
952
+ cookie?: never;
953
+ };
954
+ requestBody?: {
955
+ content: {
956
+ 'application/json': components['schemas']['VerifyRequest'];
957
+ };
958
+ };
959
+ responses: {
960
+ /** @description Redemption result. status=ok sets the session cookie and carries the redirect target. */
961
+ 200: {
962
+ headers: {
963
+ [name: string]: unknown;
964
+ };
965
+ content: {
966
+ 'application/json': components['schemas']['VerifyResponse'];
967
+ };
968
+ };
969
+ /** @description Validation error */
970
+ 400: {
971
+ headers: {
972
+ [name: string]: unknown;
973
+ };
974
+ content: {
975
+ 'application/json': components['schemas']['ErrorResponse'];
976
+ };
977
+ };
978
+ };
979
+ };
943
980
  delete?: never;
944
981
  options?: never;
945
982
  head?: never;
@@ -9839,6 +9876,7 @@ interface components {
9839
9876
  activationUrl: string;
9840
9877
  /** Format: date-time */
9841
9878
  sessionExpiresAt: string;
9879
+ sessionGrant?: string;
9842
9880
  };
9843
9881
  ObserveSessionResponse: {
9844
9882
  /** @example ses_abc123xyz456 */
@@ -9862,7 +9900,7 @@ interface components {
9862
9900
  ObserveSessionWeb: {
9863
9901
  previewId: string;
9864
9902
  token: string;
9865
- activationUrl: string | null;
9903
+ previewEnabled: boolean;
9866
9904
  /** Format: uri */
9867
9905
  bundleUrl: string;
9868
9906
  } | null;
@@ -10617,6 +10655,29 @@ interface components {
10617
10655
  /** @example /dashboard */
10618
10656
  redirect_to?: string;
10619
10657
  };
10658
+ VerifyResponse:
10659
+ | {
10660
+ /** @enum {string} */
10661
+ status: 'ok';
10662
+ /** @example / */
10663
+ redirectTo: string;
10664
+ }
10665
+ | {
10666
+ /** @enum {string} */
10667
+ status: 'confirm_required';
10668
+ /** @example user@example.com */
10669
+ email: string;
10670
+ }
10671
+ | {
10672
+ /** @enum {string} */
10673
+ status: 'expired' | 'used' | 'invalid' | 'malformed';
10674
+ };
10675
+ VerifyRequest: {
10676
+ token: string;
10677
+ /** @example /dashboard */
10678
+ redirect_to?: string;
10679
+ confirm?: boolean;
10680
+ };
10620
10681
  WhoamiResponse: {
10621
10682
  /** @example user_a1b2c3d4 */
10622
10683
  userId: string;
@@ -11445,7 +11506,7 @@ interface WrapSkeletonOptions {
11445
11506
  /**
11446
11507
  * Browser-only: preview-ARTIFACT grant injection. The preview-artifact wrap
11447
11508
  * sets this to the server-bound destination keys that should receive the
11448
- * `X-Walkeros-Preview` header read from `localStorage['elbPreview']` at boot.
11509
+ * `X-Walkeros-Preview` header read from `localStorage['elbPreviewSession']` at boot.
11449
11510
  * Mutually exclusive with `preview` (a host activates, an artifact injects);
11450
11511
  * passing both throws.
11451
11512
  */
@@ -11654,6 +11715,23 @@ interface CreatePreviewOptions {
11654
11715
  url?: string;
11655
11716
  }
11656
11717
  declare function createPreview(options: CreatePreviewOptions): Promise<components['schemas']['PreviewResponse']>;
11718
+ interface RegrantPreviewOptions {
11719
+ projectId?: string;
11720
+ flowId: string;
11721
+ previewId: string;
11722
+ /** Bare `https://host[:port]` origins the grant may activate on; the
11723
+ * returned `activationUrl` targets the first. */
11724
+ origins: string[];
11725
+ /** Observe session id — binds the minted grant to that session so
11726
+ * forwarded events reach its container. Opaque to the CLI. */
11727
+ sessionId?: string;
11728
+ }
11729
+ /**
11730
+ * Mint a fresh, origin-bound activation grant for an existing preview.
11731
+ * Grants are app-signed and origin-bound, so a client cannot forge a working
11732
+ * activation URL by string-appending a token — only the server can mint one.
11733
+ */
11734
+ declare function regrantPreview(options: RegrantPreviewOptions): Promise<components['schemas']['MintGrantResponse']>;
11657
11735
  interface DeletePreviewOptions {
11658
11736
  projectId?: string;
11659
11737
  flowId: string;
@@ -12022,4 +12100,4 @@ declare module '@walkeros/core' {
12022
12100
  }
12023
12101
  }
12024
12102
 
12025
- export { ApiError, type ApiErrorDetail, type BuildOptions, type BundleStats, type CLIBuildOptions, type ClientContext, type ClientType, type CompareContractInput, type ContractComparison, type ContractVerdict, type CreatePreviewOptions, type CreateSecretOptions, type DeletePreviewOptions, type DeleteSecretOptions, type DeployOptions, DeploymentAmbiguityError, type DeploymentSummaryForFlow, type DeviceCodeOptions, type DeviceCodeResult, type ExampleLookupResult, type FeedbackOptions, type GetPreviewOptions, type GlobalOptions, type HealthResult, type ListDeploymentsOptions, type ListFlowsOptions, type ListJourneysOptions, type ListPreviewsOptions, type ListProjectsOptions, type ListSecretsOptions, type MinifyOptions, type PollOptions, type PollResult, type PrepareInput, type PreparedFlow, type ProjectFlows, type PushResult, type RunCommandOptions, type RunOptions, type RunResult, type SSEEvent, type SSEParseResult, type SimulateCollectorOptions, type SimulateDataOptions, type SimulateDestinationOptions, type SimulateSourceOptions, type SimulateTransformerOptions, type UpdateSecretOptions, VERSION, type ValidateResult, type ValidationError, type ValidationType, type ValidationWarning, type WalkerOSConfig, type WrapSkeletonOptions, annotateErrorWithDrift, apiFetch, bakedContractHash, bakedContractVersion, buildDataPayload, bundle, bundleCommand, canonicalContractHash, classifyStepProperties, clientContextHeaders, compareContract, compareOutput, containsCodeMarkers, createApiClient, createDeployCommand, createDeployment, createDeploymentCommand, createFlow, createFlowCommand, createPreview, createProject, createProjectCommand, createSecret, deleteConfig, deleteDeployment, deleteDeploymentByFlowId, deleteDeploymentCommand, deleteFlow, deleteFlowCommand, deletePreview, deleteProject, deleteProjectCommand, deleteSecret, deploy, deployCommand, deployFetch, duplicateFlow, duplicateFlowCommand, feedback, feedbackCommand, fetchHealth, findExample, getAuthHeaders, getClientContext, getDefaultProject, getDeployment, getDeploymentBySlug, getDeploymentBySlugCommand, getDeploymentCommand, getFeedbackPreference, getFlow, getFlowCommand, getPreview, getProject, getProjectCommand, getToken, listAllFlows, listDeployments, listDeploymentsCommand, listFlows, listFlowsCommand, listJourneys, listPreviews, listProjects, listProjectsCommand, listSecrets, loadConfig, loadJsonConfig, loginCommand, logoutCommand, mergeAuthHeaders, parseSSEEvents, pollForToken, publicFetch, push, pushCommand, readConfig, requestDeviceCode, requireProjectId, resetClientContext, resolveAppUrl, resolveToken, run, runCommand, setClientContext, setDefaultProject, setFeedbackPreference, simulateCollector, simulateDestination, simulateSource, simulateTransformer, index as telemetry, telemetryDisableCommand, telemetryEnableCommand, telemetryStatusCommand, throwApiError, updateFlow, updateFlowCommand, updateProject, updateProjectCommand, updateSecret, validate, validateCommand, validateFlowStructure, whoami, whoamiCommand, wrapSkeleton, writeConfig };
12103
+ export { ApiError, type ApiErrorDetail, type BuildOptions, type BundleStats, type CLIBuildOptions, type ClientContext, type ClientType, type CompareContractInput, type ContractComparison, type ContractVerdict, type CreatePreviewOptions, type CreateSecretOptions, type DeletePreviewOptions, type DeleteSecretOptions, type DeployOptions, DeploymentAmbiguityError, type DeploymentSummaryForFlow, type DeviceCodeOptions, type DeviceCodeResult, type ExampleLookupResult, type FeedbackOptions, type GetPreviewOptions, type GlobalOptions, type HealthResult, type ListDeploymentsOptions, type ListFlowsOptions, type ListJourneysOptions, type ListPreviewsOptions, type ListProjectsOptions, type ListSecretsOptions, type MinifyOptions, type PollOptions, type PollResult, type PrepareInput, type PreparedFlow, type ProjectFlows, type PushResult, type RegrantPreviewOptions, type RunCommandOptions, type RunOptions, type RunResult, type SSEEvent, type SSEParseResult, type SimulateCollectorOptions, type SimulateDataOptions, type SimulateDestinationOptions, type SimulateSourceOptions, type SimulateTransformerOptions, type UpdateSecretOptions, VERSION, type ValidateResult, type ValidationError, type ValidationType, type ValidationWarning, type WalkerOSConfig, type WrapSkeletonOptions, annotateErrorWithDrift, apiFetch, bakedContractHash, bakedContractVersion, buildDataPayload, bundle, bundleCommand, canonicalContractHash, classifyStepProperties, clientContextHeaders, compareContract, compareOutput, containsCodeMarkers, createApiClient, createDeployCommand, createDeployment, createDeploymentCommand, createFlow, createFlowCommand, createPreview, createProject, createProjectCommand, createSecret, deleteConfig, deleteDeployment, deleteDeploymentByFlowId, deleteDeploymentCommand, deleteFlow, deleteFlowCommand, deletePreview, deleteProject, deleteProjectCommand, deleteSecret, deploy, deployCommand, deployFetch, duplicateFlow, duplicateFlowCommand, feedback, feedbackCommand, fetchHealth, findExample, getAuthHeaders, getClientContext, getDefaultProject, getDeployment, getDeploymentBySlug, getDeploymentBySlugCommand, getDeploymentCommand, getFeedbackPreference, getFlow, getFlowCommand, getPreview, getProject, getProjectCommand, getToken, listAllFlows, listDeployments, listDeploymentsCommand, listFlows, listFlowsCommand, listJourneys, listPreviews, listProjects, listProjectsCommand, listSecrets, loadConfig, loadJsonConfig, loginCommand, logoutCommand, mergeAuthHeaders, parseSSEEvents, pollForToken, publicFetch, push, pushCommand, readConfig, regrantPreview, requestDeviceCode, requireProjectId, resetClientContext, resolveAppUrl, resolveToken, run, runCommand, setClientContext, setDefaultProject, setFeedbackPreference, simulateCollector, simulateDestination, simulateSource, simulateTransformer, index as telemetry, telemetryDisableCommand, telemetryEnableCommand, telemetryStatusCommand, throwApiError, updateFlow, updateFlowCommand, updateProject, updateProjectCommand, updateSecret, validate, validateCommand, validateFlowStructure, whoami, whoamiCommand, wrapSkeleton, writeConfig };
package/dist/index.js CHANGED
@@ -3321,7 +3321,7 @@ function generateWrapEntry(stage1Path, options = {}) {
3321
3321
  const assignmentCode = assignments.length > 0 ? "\n" + assignments.join("\n") : "";
3322
3322
  if (options.preview !== void 0 && options.previewGrantTargets !== void 0) {
3323
3323
  throw new Error(
3324
- "generateWrapEntry: `preview` (host activator) and `previewGrantTargets` (preview-artifact injection) are mutually exclusive. A host bundle activates a preview; an artifact injects its grant. Pass exactly one."
3324
+ "generateWrapEntry: `preview` (host activator) and `previewGrantTargets` (preview-artifact injection) are mutually exclusive. A host bundle activates a preview; an artifact injects its grant. Pass at most one."
3325
3325
  );
3326
3326
  }
3327
3327
  const preview = options.preview;
@@ -3334,7 +3334,7 @@ function generateWrapEntry(stage1Path, options = {}) {
3334
3334
  try {
3335
3335
  const __previewGrant =
3336
3336
  typeof localStorage !== 'undefined'
3337
- ? localStorage.getItem('elbPreview')
3337
+ ? localStorage.getItem('elbPreviewSession')
3338
3338
  : null;
3339
3339
  if (__previewGrant && config.destinations) {
3340
3340
  ${grantTargets.map((key) => {
@@ -6409,11 +6409,14 @@ function createPoller(config, logger) {
6409
6409
  import http from "http";
6410
6410
  import { verifyActivation } from "@walkeros/core";
6411
6411
  var PREVIEW_LOG = "[walkerOS:preview]";
6412
- function answerPreviewPreflight(res) {
6412
+ function answerPreviewPreflight(req, res) {
6413
+ const requested = req.headers["access-control-request-headers"];
6414
+ const requestedHeaders = Array.isArray(requested) ? requested.join(", ") : requested;
6413
6415
  res.writeHead(204, {
6414
6416
  "Access-Control-Allow-Origin": "*",
6415
6417
  "Access-Control-Allow-Methods": "GET, POST, OPTIONS",
6416
- "Access-Control-Allow-Headers": "Content-Type, X-Walkeros-Preview"
6418
+ "Access-Control-Allow-Headers": requestedHeaders || "Content-Type, X-Walkeros-Preview",
6419
+ Vary: "Access-Control-Request-Headers"
6417
6420
  });
6418
6421
  res.end();
6419
6422
  }
@@ -6439,21 +6442,36 @@ function guardPreviewIntake(req, res, gate, logger, onPass) {
6439
6442
  source: "storage",
6440
6443
  now: gate.now ? gate.now() : Date.now(),
6441
6444
  crypto: gate.crypto
6442
- }).then((result) => {
6443
- if (result.ok) {
6444
- onPass();
6445
- } else {
6445
+ }).then(
6446
+ (result) => {
6447
+ if (!result.ok) {
6448
+ logger.info(
6449
+ `${PREVIEW_LOG} rejected ${req.method} ${req.url}: ${result.reason}`
6450
+ );
6451
+ rejectPreview(res);
6452
+ return;
6453
+ }
6454
+ try {
6455
+ onPass();
6456
+ } catch (error) {
6457
+ logger.info(
6458
+ `${PREVIEW_LOG} flow handler error on ${req.method} ${req.url}: ${error instanceof Error ? error.message : String(error)}`
6459
+ );
6460
+ if (!res.headersSent) {
6461
+ res.writeHead(500, { "Content-Type": "application/json" });
6462
+ res.end(JSON.stringify({ error: "Internal Server Error" }));
6463
+ } else {
6464
+ res.end();
6465
+ }
6466
+ }
6467
+ },
6468
+ (error) => {
6446
6469
  logger.info(
6447
- `${PREVIEW_LOG} rejected ${req.method} ${req.url}: ${result.reason}`
6470
+ `${PREVIEW_LOG} verification error on ${req.method} ${req.url}: ${error instanceof Error ? error.message : String(error)}`
6448
6471
  );
6449
6472
  rejectPreview(res);
6450
6473
  }
6451
- }).catch((error) => {
6452
- logger.info(
6453
- `${PREVIEW_LOG} verification error on ${req.method} ${req.url}: ${error instanceof Error ? error.message : String(error)}`
6454
- );
6455
- rejectPreview(res);
6456
- });
6474
+ );
6457
6475
  }
6458
6476
  function createHealthServer(port, logger, previewGate) {
6459
6477
  return new Promise((resolve5, reject) => {
@@ -6488,7 +6506,7 @@ function createHealthServer(port, logger, previewGate) {
6488
6506
  };
6489
6507
  if (previewGate) {
6490
6508
  if (req.method === "OPTIONS") {
6491
- answerPreviewPreflight(res);
6509
+ answerPreviewPreflight(req, res);
6492
6510
  return;
6493
6511
  }
6494
6512
  guardPreviewIntake(req, res, previewGate, logger, delegate);
@@ -7559,11 +7577,14 @@ init_config();
7559
7577
  import chalk2 from "chalk";
7560
7578
 
7561
7579
  // src/commands/validate/validators/contract.ts
7580
+ import { isObject as isObject4 } from "@walkeros/core";
7562
7581
  var SECTION_KEYS = ["globals", "context", "custom", "user", "consent"];
7563
7582
  var KNOWN_KEYS = /* @__PURE__ */ new Set([
7564
7583
  "extend",
7584
+ "tagging",
7565
7585
  "description",
7566
7586
  "events",
7587
+ "schema",
7567
7588
  ...SECTION_KEYS
7568
7589
  ]);
7569
7590
  function validateContract(input) {
@@ -7581,7 +7602,19 @@ function validateContract(input) {
7581
7602
  const contracts = input;
7582
7603
  const contractNames = Object.keys(contracts);
7583
7604
  details.contractCount = contractNames.length;
7605
+ for (const name of contractNames) {
7606
+ if (name.startsWith("$")) {
7607
+ errors.push({
7608
+ path: name,
7609
+ message: `"${name}" is not a named contract entry. This looks like the flat shape; use named ContractRule entries, lift $tagging to the rule field "tagging", and nest entity-action schemas under "events".`,
7610
+ code: "FLAT_CONTRACT_SHAPE"
7611
+ });
7612
+ }
7613
+ }
7584
7614
  for (const [name, entry] of Object.entries(contracts)) {
7615
+ if (name.startsWith("$")) {
7616
+ continue;
7617
+ }
7585
7618
  if (typeof entry !== "object" || entry === null) {
7586
7619
  errors.push({
7587
7620
  path: name,
@@ -7591,6 +7624,39 @@ function validateContract(input) {
7591
7624
  continue;
7592
7625
  }
7593
7626
  const obj = entry;
7627
+ const keys = Object.keys(obj);
7628
+ const unknownKeys = keys.filter((k) => !KNOWN_KEYS.has(k));
7629
+ const hasKnownKey = keys.some((k) => KNOWN_KEYS.has(k));
7630
+ const objectValuedUnknown = unknownKeys.filter((k) => isObject4(obj[k]));
7631
+ if (!hasKnownKey && objectValuedUnknown.length > 0) {
7632
+ errors.push({
7633
+ path: name,
7634
+ message: `Contract "${name}" looks like a flat entity-action map. Nest entity-action schemas under an "events" key of a named ContractRule.`,
7635
+ code: "FLAT_CONTRACT_SHAPE"
7636
+ });
7637
+ continue;
7638
+ }
7639
+ for (const key of unknownKeys) {
7640
+ warnings.push({
7641
+ path: `${name}.${key}`,
7642
+ message: `Unknown contract key "${key}" is ignored`,
7643
+ code: "UNKNOWN_CONTRACT_KEY"
7644
+ });
7645
+ }
7646
+ if (obj.tagging !== void 0 && typeof obj.tagging !== "number") {
7647
+ errors.push({
7648
+ path: `${name}.tagging`,
7649
+ message: "tagging must be a number",
7650
+ code: "INVALID_TAGGING"
7651
+ });
7652
+ }
7653
+ if (obj.schema !== void 0 && !isObject4(obj.schema)) {
7654
+ errors.push({
7655
+ path: `${name}.schema`,
7656
+ message: "schema must be a JSON Schema object",
7657
+ code: "INVALID_SCHEMA"
7658
+ });
7659
+ }
7594
7660
  if (obj.extend !== void 0) {
7595
7661
  if (typeof obj.extend !== "string") {
7596
7662
  errors.push({
@@ -7718,7 +7784,7 @@ function validateEvent2(input) {
7718
7784
  // src/commands/validate/validators/flow.ts
7719
7785
  import {
7720
7786
  getFlowSettings as getFlowSettings2,
7721
- isObject as isObject4,
7787
+ isObject as isObject5,
7722
7788
  resolveContracts,
7723
7789
  validateStepEntry as validateStepEntry2
7724
7790
  } from "@walkeros/core";
@@ -7726,9 +7792,9 @@ import { schemas as schemas4 } from "@walkeros/core/dev";
7726
7792
  import { validateEventAgainstContract } from "@walkeros/transformer-validate";
7727
7793
  var { validateFlowConfig: validateFlowConfig2 } = schemas4;
7728
7794
  function isFlowJson(value) {
7729
- if (!isObject4(value)) return false;
7795
+ if (!isObject5(value)) return false;
7730
7796
  if (!("version" in value) || !("flows" in value)) return false;
7731
- return isObject4(value.flows);
7797
+ return isObject5(value.flows);
7732
7798
  }
7733
7799
  function validateFlow(input, options = {}) {
7734
7800
  const errors = [];
@@ -7759,9 +7825,9 @@ function validateFlow(input, options = {}) {
7759
7825
  message: issue.message
7760
7826
  });
7761
7827
  }
7762
- const config = isObject4(input) ? input : {};
7828
+ const config = isObject5(input) ? input : {};
7763
7829
  const flowsValue = config.flows;
7764
- const flows = isObject4(flowsValue) ? flowsValue : void 0;
7830
+ const flows = isObject5(flowsValue) ? flowsValue : void 0;
7765
7831
  if (flows && Object.keys(flows).length === 0) {
7766
7832
  errors.push({
7767
7833
  path: "flows",
@@ -7771,13 +7837,13 @@ function validateFlow(input, options = {}) {
7771
7837
  }
7772
7838
  if (flows) {
7773
7839
  for (const [flowName, flowValue] of Object.entries(flows)) {
7774
- if (!isObject4(flowValue)) continue;
7840
+ if (!isObject5(flowValue)) continue;
7775
7841
  const transformersValue = flowValue.transformers;
7776
- if (!isObject4(transformersValue)) continue;
7842
+ if (!isObject5(transformersValue)) continue;
7777
7843
  for (const [name, transformerValue] of Object.entries(
7778
7844
  transformersValue
7779
7845
  )) {
7780
- if (!isObject4(transformerValue)) continue;
7846
+ if (!isObject5(transformerValue)) continue;
7781
7847
  const result = validateStepEntry2(transformerValue, "Transformer");
7782
7848
  if (!result.ok) {
7783
7849
  errors.push({
@@ -7808,15 +7874,15 @@ function validateFlow(input, options = {}) {
7808
7874
  let totalPackageCount = 0;
7809
7875
  if (flows) {
7810
7876
  for (const [flowName, flowValue] of Object.entries(flows)) {
7811
- if (!isObject4(flowValue)) continue;
7877
+ if (!isObject5(flowValue)) continue;
7812
7878
  const flowConfig = flowValue.config;
7813
- if (!isObject4(flowConfig)) continue;
7879
+ if (!isObject5(flowConfig)) continue;
7814
7880
  const bundle2 = flowConfig.bundle;
7815
- if (!isObject4(bundle2)) continue;
7881
+ if (!isObject5(bundle2)) continue;
7816
7882
  const packages = bundle2.packages;
7817
- if (!isObject4(packages)) continue;
7883
+ if (!isObject5(packages)) continue;
7818
7884
  for (const [pkgName, pkgConfigValue] of Object.entries(packages)) {
7819
- if (!isObject4(pkgConfigValue)) continue;
7885
+ if (!isObject5(pkgConfigValue)) continue;
7820
7886
  if (!pkgConfigValue.version && !pkgConfigValue.path) {
7821
7887
  warnings.push({
7822
7888
  path: `flows.${flowName}.config.bundle.packages.${pkgName}`,
@@ -7865,9 +7931,9 @@ function validateFlow(input, options = {}) {
7865
7931
  for (const [destName, dest] of Object.entries(
7866
7932
  flowSettings.destinations || {}
7867
7933
  )) {
7868
- if (!isObject4(dest.config)) continue;
7934
+ if (!isObject5(dest.config)) continue;
7869
7935
  const mapping = dest.config.mapping;
7870
- if (!isObject4(mapping)) continue;
7936
+ if (!isObject5(mapping)) continue;
7871
7937
  for (const key of Object.keys(mapping)) {
7872
7938
  if (key.includes(".") && !key.includes(" ")) {
7873
7939
  const parts = key.split(".");
@@ -8149,7 +8215,7 @@ function checkContractCompliance(config, contract, errors, warnings, strict) {
8149
8215
  const rules = Object.values(resolved);
8150
8216
  if (rules.length === 0) return;
8151
8217
  const checkExample = (path20, candidate) => {
8152
- if (!isObject4(candidate)) return;
8218
+ if (!isObject5(candidate)) return;
8153
8219
  const entity = typeof candidate.entity === "string" ? candidate.entity : void 0;
8154
8220
  const action = typeof candidate.action === "string" ? candidate.action : void 0;
8155
8221
  if (!entity || !action) return;
@@ -8239,7 +8305,7 @@ function validateMapping(input) {
8239
8305
  // src/commands/validate/validators/entry.ts
8240
8306
  import Ajv from "ajv";
8241
8307
  import { fetchPackageSchema } from "@walkeros/core";
8242
- var CLIENT_HEADER = "walkeros-cli/4.3.0-next-1784055686454";
8308
+ var CLIENT_HEADER = "walkeros-cli/4.3.0";
8243
8309
  var SECTIONS = ["destinations", "sources", "transformers"];
8244
8310
  function resolveEntry(path20, flowConfig) {
8245
8311
  const flows = flowConfig.flows;
@@ -8804,8 +8870,8 @@ import createClient from "openapi-fetch";
8804
8870
  init_config_file();
8805
8871
  import { createHash } from "crypto";
8806
8872
  import semver4 from "semver";
8807
- var bakedContractVersion = true ? "2.4.0" : PLACEHOLDER;
8808
- var bakedContractHash = true ? "0ac882455113d4f5cec40e9d1a32a7771fd139e37a059c7a272ff9982e64c8aa" : "";
8873
+ var bakedContractVersion = true ? "3.1.0" : PLACEHOLDER;
8874
+ var bakedContractHash = true ? "d3753dd02864fc19892f74a6a9afddb2081fc7a3f249991a681ae6c5540be650" : "";
8809
8875
  function isRecord3(value) {
8810
8876
  return value !== null && typeof value === "object" && !Array.isArray(value);
8811
8877
  }
@@ -9959,7 +10025,7 @@ init_config_classifier();
9959
10025
 
9960
10026
  // src/commands/bundle/validate-structure.ts
9961
10027
  init_structural_validators();
9962
- import { isObject as isObject5, validateStepEntry as validateStepEntry3 } from "@walkeros/core";
10028
+ import { isObject as isObject6, validateStepEntry as validateStepEntry3 } from "@walkeros/core";
9963
10029
  var STEP_SECTIONS = [
9964
10030
  "sources",
9965
10031
  "destinations",
@@ -9986,7 +10052,7 @@ function getSection(flow, section) {
9986
10052
  }
9987
10053
  function hasCodeReference3(code) {
9988
10054
  if (typeof code === "string") return true;
9989
- return isObject5(code) && "push" in code;
10055
+ return isObject6(code) && "push" in code;
9990
10056
  }
9991
10057
  function messageOf(error) {
9992
10058
  return error instanceof Error ? error.message : String(error);
@@ -9995,10 +10061,10 @@ function validateFlowStructure(flowConfig) {
9995
10061
  const errors = [];
9996
10062
  const details = {};
9997
10063
  const flows = flowConfig.flows;
9998
- const flowNames = isObject5(flows) ? Object.keys(flows) : [];
10064
+ const flowNames = isObject6(flows) ? Object.keys(flows) : [];
9999
10065
  details.flowNames = flowNames;
10000
10066
  details.flowCount = flowNames.length;
10001
- if (!isObject5(flows) || flowNames.length === 0) {
10067
+ if (!isObject6(flows) || flowNames.length === 0) {
10002
10068
  errors.push({
10003
10069
  path: "flows",
10004
10070
  message: "At least one flow is required",
@@ -10115,10 +10181,10 @@ async function wrapSkeleton(options) {
10115
10181
  } = options;
10116
10182
  if (options.preview && options.previewGrantTargets) {
10117
10183
  throw new Error(
10118
- "wrapSkeleton: `preview` (host activator) and `previewGrantTargets` (preview-artifact injection) are mutually exclusive. Pass exactly one."
10184
+ "wrapSkeleton: `preview` (host activator) and `previewGrantTargets` (preview-artifact injection) are mutually exclusive. Pass at most one."
10119
10185
  );
10120
10186
  }
10121
- if (options.preview && !/^[a-z0-9.-]+$/.test(options.preview.previewOrigin)) {
10187
+ if (options.preview && (typeof options.preview.previewOrigin !== "string" || !/^[a-z0-9.-]+$/.test(options.preview.previewOrigin))) {
10122
10188
  throw new Error(
10123
10189
  `Invalid previewOrigin "${options.preview.previewOrigin}". Must be a bare hostname matching /^[a-z0-9.-]+$/.`
10124
10190
  );
@@ -10279,11 +10345,37 @@ async function createPreview(options) {
10279
10345
  );
10280
10346
  if (!grantResponse.ok) {
10281
10347
  const body = await grantResponse.json().catch(() => ({}));
10282
- throwApiError(body, "Failed to mint preview activation grant");
10348
+ try {
10349
+ throwApiError(body, "Failed to mint preview activation grant");
10350
+ } catch (error) {
10351
+ if (error instanceof Error) {
10352
+ error.message += ` (preview ${created.id} was created but has no working activation URL; delete it or mint a grant with regrantPreview)`;
10353
+ }
10354
+ throw error;
10355
+ }
10283
10356
  }
10284
10357
  const grant = await grantResponse.json();
10285
10358
  return { ...created, activationUrl: grant.activationUrl };
10286
10359
  }
10360
+ async function regrantPreview(options) {
10361
+ const pid = options.projectId ?? requireProjectId();
10362
+ const response = await apiFetch(
10363
+ `/api/projects/${pid}/flows/${options.flowId}/previews/${options.previewId}/grant`,
10364
+ {
10365
+ method: "POST",
10366
+ headers: { "Content-Type": "application/json" },
10367
+ body: JSON.stringify({
10368
+ origins: options.origins,
10369
+ ...options.sessionId ? { sessionId: options.sessionId } : {}
10370
+ })
10371
+ }
10372
+ );
10373
+ if (!response.ok) {
10374
+ const body = await response.json().catch(() => ({}));
10375
+ throwApiError(body, "Failed to mint preview activation grant");
10376
+ }
10377
+ return response.json();
10378
+ }
10287
10379
  async function deletePreview(options) {
10288
10380
  const pid = options.projectId ?? requireProjectId();
10289
10381
  const response = await apiFetch(
@@ -10766,6 +10858,7 @@ export {
10766
10858
  push,
10767
10859
  pushCommand,
10768
10860
  readConfig,
10861
+ regrantPreview,
10769
10862
  requestDeviceCode,
10770
10863
  requireProjectId,
10771
10864
  resetClientContext,