@xano/cli 1.3.1-beta.1 → 1.3.1

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 (96) hide show
  1. package/README.md +1 -269
  2. package/dist/base-command.d.ts +1 -12
  3. package/dist/base-command.js +22 -36
  4. package/dist/commands/branch/set_live/index.d.ts +0 -22
  5. package/dist/commands/branch/set_live/index.js +1 -60
  6. package/dist/commands/ephemeral/push/index.js +1 -6
  7. package/dist/commands/function/create/index.d.ts +0 -15
  8. package/dist/commands/function/create/index.js +0 -40
  9. package/dist/commands/function/edit/index.d.ts +0 -15
  10. package/dist/commands/function/edit/index.js +0 -40
  11. package/dist/commands/release/create/index.js +0 -7
  12. package/dist/commands/release/deploy/index.d.ts +0 -28
  13. package/dist/commands/release/deploy/index.js +6 -90
  14. package/dist/commands/release/import/index.js +1 -5
  15. package/dist/commands/release/list/index.d.ts +0 -7
  16. package/dist/commands/release/list/index.js +10 -54
  17. package/dist/commands/release/push/index.js +1 -19
  18. package/dist/commands/sandbox/push/index.js +1 -6
  19. package/dist/commands/tenant/create/index.d.ts +0 -3
  20. package/dist/commands/tenant/create/index.js +0 -21
  21. package/dist/commands/tenant/deploy_release/index.d.ts +0 -40
  22. package/dist/commands/tenant/deploy_release/index.js +4 -186
  23. package/dist/commands/tenant/edit/index.d.ts +0 -2
  24. package/dist/commands/tenant/edit/index.js +4 -39
  25. package/dist/commands/workspace/pull/index.d.ts +0 -10
  26. package/dist/commands/workspace/pull/index.js +7 -70
  27. package/dist/commands/workspace/push/index.d.ts +0 -19
  28. package/dist/commands/workspace/push/index.js +5 -124
  29. package/dist/utils/document-parser.d.ts +0 -10
  30. package/dist/utils/document-parser.js +0 -21
  31. package/dist/utils/multidoc-push.d.ts +2 -55
  32. package/dist/utils/multidoc-push.js +27 -103
  33. package/oclif.manifest.json +3142 -6141
  34. package/package.json +1 -7
  35. package/dist/commands/policy/catalogue/index.d.ts +0 -15
  36. package/dist/commands/policy/catalogue/index.js +0 -29
  37. package/dist/commands/policy/create/index.d.ts +0 -18
  38. package/dist/commands/policy/create/index.js +0 -39
  39. package/dist/commands/policy/delete/index.d.ts +0 -19
  40. package/dist/commands/policy/delete/index.js +0 -61
  41. package/dist/commands/policy/evaluate/index.d.ts +0 -32
  42. package/dist/commands/policy/evaluate/index.js +0 -71
  43. package/dist/commands/policy/list/index.d.ts +0 -14
  44. package/dist/commands/policy/list/index.js +0 -21
  45. package/dist/commands/policy/parse/index.d.ts +0 -19
  46. package/dist/commands/policy/parse/index.js +0 -18
  47. package/dist/commands/policy/publish/index.d.ts +0 -20
  48. package/dist/commands/policy/publish/index.js +0 -38
  49. package/dist/commands/policy/runs/index.d.ts +0 -54
  50. package/dist/commands/policy/runs/index.js +0 -273
  51. package/dist/commands/policy/status/index.d.ts +0 -21
  52. package/dist/commands/policy/status/index.js +0 -54
  53. package/dist/commands/skills/pull/index.d.ts +0 -30
  54. package/dist/commands/skills/pull/index.js +0 -118
  55. package/dist/commands/tenant_deploy_request/bypass/index.d.ts +0 -31
  56. package/dist/commands/tenant_deploy_request/bypass/index.js +0 -109
  57. package/dist/commands/tenant_deploy_request/create/index.d.ts +0 -21
  58. package/dist/commands/tenant_deploy_request/create/index.js +0 -108
  59. package/dist/commands/tenant_deploy_request/edit/index.d.ts +0 -22
  60. package/dist/commands/tenant_deploy_request/edit/index.js +0 -103
  61. package/dist/commands/tenant_deploy_request/get/index.d.ts +0 -25
  62. package/dist/commands/tenant_deploy_request/get/index.js +0 -116
  63. package/dist/commands/tenant_deploy_request/list/index.d.ts +0 -20
  64. package/dist/commands/tenant_deploy_request/list/index.js +0 -122
  65. package/dist/commands/tenant_deploy_request/revision/index.d.ts +0 -21
  66. package/dist/commands/tenant_deploy_request/revision/index.js +0 -83
  67. package/dist/commands/tenant_deploy_request/set_status/index.d.ts +0 -38
  68. package/dist/commands/tenant_deploy_request/set_status/index.js +0 -159
  69. package/dist/policy-command.d.ts +0 -90
  70. package/dist/policy-command.js +0 -94
  71. package/dist/utils/policy/catalogue.d.ts +0 -7
  72. package/dist/utils/policy/catalogue.js +0 -72
  73. package/dist/utils/policy/errors.d.ts +0 -12
  74. package/dist/utils/policy/errors.js +0 -61
  75. package/dist/utils/policy/feedback.d.ts +0 -68
  76. package/dist/utils/policy/feedback.js +0 -165
  77. package/dist/utils/policy/findings.d.ts +0 -23
  78. package/dist/utils/policy/findings.js +0 -65
  79. package/dist/utils/policy/gate.d.ts +0 -161
  80. package/dist/utils/policy/gate.js +0 -201
  81. package/dist/utils/policy/goal.d.ts +0 -46
  82. package/dist/utils/policy/goal.js +0 -95
  83. package/dist/utils/policy/permission.d.ts +0 -23
  84. package/dist/utils/policy/permission.js +0 -84
  85. package/dist/utils/policy/push-gate.d.ts +0 -5
  86. package/dist/utils/policy/push-gate.js +0 -29
  87. package/dist/utils/policy/release.d.ts +0 -85
  88. package/dist/utils/policy/release.js +0 -115
  89. package/dist/utils/policy/request.d.ts +0 -55
  90. package/dist/utils/policy/request.js +0 -115
  91. package/dist/utils/policy/runs.d.ts +0 -30
  92. package/dist/utils/policy/runs.js +0 -101
  93. package/dist/utils/policy/status.d.ts +0 -47
  94. package/dist/utils/policy/status.js +0 -117
  95. package/dist/utils/policy/types.d.ts +0 -185
  96. package/dist/utils/policy/types.js +0 -1
@@ -1,24 +1,11 @@
1
- import { Errors, ux } from '@oclif/core';
1
+ import { ux } from '@oclif/core';
2
2
  import { minimatch } from 'minimatch';
3
3
  import * as fs from 'node:fs';
4
4
  import { join, relative } from 'node:path';
5
5
  import { buildDocumentKey, findFilesWithGuid, parseDocument } from './document-parser.js';
6
6
  import { flattenBundleFile } from './flatten.js';
7
7
  import { collectKnowledgeObjects, fetchKnowledge, knowledgePreview, pushKnowledge, syncGuidToFrontmatter, toPushItems, } from './knowledge-sync.js';
8
- import { policyWeakeningGuidance, WEAKENING_REFUSAL } from './policy/permission.js';
9
- import { PushPolicyGateError } from './policy/push-gate.js';
10
8
  import { checkReferences, checkTableIndexes } from './reference-checker.js';
11
- /**
12
- * A push that failed after its multidoc import landed. The import is not rolled back, so the error
13
- * carries what it did for the calling command to report beside the failure.
14
- */
15
- export class FailedAfterImportError extends Errors.CLIError {
16
- imported;
17
- constructor(message, imported) {
18
- super(message);
19
- this.imported = imported;
20
- }
21
- }
22
9
  /**
23
10
  * Filter document entries down to the ones the dry-run preview reports as changed,
24
11
  * used to send only the changed documents during a partial (non-`--sync`) push.
@@ -592,9 +579,7 @@ function mergeKnowledgePreview(preview, knowledge) {
592
579
  */
593
580
  export async function executePush(ctx, target, flags) {
594
581
  const { accessToken, command, inputDir, verboseFetch } = ctx;
595
- const log = ctx.log ?? command.log.bind(command);
596
- let dryRunPreview = null;
597
- const stop = (stopped) => ({ knowledge: { deleted: 0, imported: 0 }, preview: dryRunPreview, sent: [], stopped });
582
+ const log = command.log.bind(command);
598
583
  // ── Collect knowledge entries (before file check so knowledge-only push works) ─
599
584
  let knowledgeObjects = [];
600
585
  if (ctx.knowledge) {
@@ -653,7 +638,7 @@ export async function executePush(ctx, target, flags) {
653
638
  const doFlatten = await confirm('Flatten these file(s) in place and continue the push?');
654
639
  if (!doFlatten) {
655
640
  log('Push cancelled. Run `xano flatten <file>` yourself, or re-run to be prompted again.');
656
- return stop('cancelled');
641
+ return;
657
642
  }
658
643
  }
659
644
  else {
@@ -756,6 +741,7 @@ export async function executePush(ctx, target, flags) {
756
741
  'Content-Type': 'text/x-xanoscript',
757
742
  };
758
743
  // ── Dry-run / Preview ─────────────────────────────────────────────────
744
+ let dryRunPreview = null;
759
745
  const dryRunUrl = knowledgeOnly ? null : target.buildDryRunUrl(queryParams);
760
746
  if (dryRunUrl && (flags['dry-run'] || !flags.force)) {
761
747
  const dryRunParams = new URLSearchParams(queryParams);
@@ -847,7 +833,7 @@ export async function executePush(ctx, target, flags) {
847
833
  log('');
848
834
  log(ux.colorize('red', `Push blocked: ${criticalOps.length} critical error(s) found.`));
849
835
  if (!flags.force) {
850
- return stop('blocked');
836
+ return;
851
837
  }
852
838
  log(ux.colorize('yellow', 'Proceeding anyway due to --force flag.'));
853
839
  }
@@ -877,10 +863,10 @@ export async function executePush(ctx, target, flags) {
877
863
  if (!hasChanges && !hasLocalRecords) {
878
864
  log('');
879
865
  log('No changes to push.');
880
- return stop('no-changes');
866
+ return;
881
867
  }
882
868
  if (flags['dry-run']) {
883
- return stop('dry-run');
869
+ return;
884
870
  }
885
871
  // Warn when the sandbox currently holds a different source workspace than the one being
886
872
  // pushed. The backend compares the source workspace id we sent against the id stored on
@@ -898,7 +884,7 @@ export async function executePush(ctx, target, flags) {
898
884
  const proceed = await confirm('Continue with push anyway?');
899
885
  if (!proceed) {
900
886
  log('Push cancelled. Run `xano sandbox reset` then retry.');
901
- return stop('cancelled');
887
+ return;
902
888
  }
903
889
  mismatchConfirmed = true;
904
890
  }
@@ -919,7 +905,7 @@ export async function executePush(ctx, target, flags) {
919
905
  const confirmed = await confirm(message);
920
906
  if (!confirmed) {
921
907
  log('Push cancelled.');
922
- return stop('cancelled');
908
+ return;
923
909
  }
924
910
  }
925
911
  else {
@@ -936,17 +922,15 @@ export async function executePush(ctx, target, flags) {
936
922
  }
937
923
  }
938
924
  else {
939
- await handleDryRunError(dryRunResponse, command, target, { log, verbose: flags.verbose });
925
+ await handleDryRunError(dryRunResponse, command, flags, target);
940
926
  // If we get here, the user confirmed to proceed without preview
941
927
  }
942
928
  }
943
929
  catch (error) {
944
930
  // Ctrl+C or SIGINT
945
- if (error instanceof PushPolicyGateError)
946
- throw error;
947
931
  if (error.name === 'AbortError' || error.code === 'ERR_USE_AFTER_CLOSE') {
948
932
  log('\nPush cancelled.');
949
- return stop('cancelled');
933
+ return;
950
934
  }
951
935
  // Re-throw oclif errors
952
936
  if (error instanceof Error && 'oclif' in error) {
@@ -977,16 +961,16 @@ export async function executePush(ctx, target, flags) {
977
961
  if (!hasChanges) {
978
962
  log('');
979
963
  log('No changes to push.');
980
- return stop('no-changes');
964
+ return;
981
965
  }
982
966
  if (flags['dry-run']) {
983
- return stop('dry-run');
967
+ return;
984
968
  }
985
969
  if (process.stdin.isTTY) {
986
970
  const confirmed = await confirm('Proceed with push?');
987
971
  if (!confirmed) {
988
972
  log('Push cancelled.');
989
- return stop('cancelled');
973
+ return;
990
974
  }
991
975
  }
992
976
  else {
@@ -1002,19 +986,17 @@ export async function executePush(ctx, target, flags) {
1002
986
  }
1003
987
  }
1004
988
  // ── Partial push: filter to changed documents only ────────────────────
1005
- let sent = documentEntries;
1006
989
  if (!knowledgeOnly && isPartial && dryRunPreview) {
1007
- sent = filterChangedEntries(documentEntries, dryRunPreview.operations, flags.records);
1008
- if (sent.length === 0 && knowledgeObjects.length === 0) {
990
+ const filteredEntries = filterChangedEntries(documentEntries, dryRunPreview.operations, flags.records);
991
+ if (filteredEntries.length === 0 && knowledgeObjects.length === 0) {
1009
992
  log('No changes to push.');
1010
- return stop('no-changes');
993
+ return;
1011
994
  }
1012
- multidoc = sent.map((d) => d.content).join('\n---\n');
995
+ multidoc = filteredEntries.length > 0 ? filteredEntries.map((d) => d.content).join('\n---\n') : '';
1013
996
  }
1014
997
  // ── Execute the actual push ───────────────────────────────────────────
1015
998
  const startTime = Date.now();
1016
999
  let pushedDocCount = 0;
1017
- let pushResponse;
1018
1000
  if (!knowledgeOnly && multidoc) {
1019
1001
  const apiUrl = target.buildPushUrl(queryParams);
1020
1002
  try {
@@ -1024,19 +1006,14 @@ export async function executePush(ctx, target, flags) {
1024
1006
  method: 'POST',
1025
1007
  }, flags.verbose, accessToken);
1026
1008
  if (!response.ok) {
1027
- const errorText = await response.text();
1028
- refuseIfExplained(command, target, response.status, errorText);
1029
- handlePushError(response, errorText, documentEntries, inputDir, command);
1009
+ handlePushError(response, await response.text(), documentEntries, inputDir, command);
1030
1010
  }
1031
1011
  // Parse response for GUID map
1032
1012
  const responseText = await response.text();
1033
1013
  let guidMap = [];
1034
- pushResponse = {};
1035
1014
  if (responseText && responseText !== 'null') {
1036
1015
  try {
1037
1016
  const responseJson = JSON.parse(responseText);
1038
- if (responseJson && typeof responseJson === 'object')
1039
- pushResponse = responseJson;
1040
1017
  if (responseJson?.guid_map && Array.isArray(responseJson.guid_map)) {
1041
1018
  guidMap = responseJson.guid_map;
1042
1019
  }
@@ -1062,7 +1039,7 @@ export async function executePush(ctx, target, flags) {
1062
1039
  let updatedCount = 0;
1063
1040
  let canonicalCount = 0;
1064
1041
  for (const entry of guidMap) {
1065
- if (!entry.guid || entry.type === 'policy')
1042
+ if (!entry.guid)
1066
1043
  continue;
1067
1044
  const key = buildDocumentKey(entry.type, entry.name, entry.verb, entry.api_group);
1068
1045
  let filePath = documentFileMap.get(key);
@@ -1108,8 +1085,6 @@ export async function executePush(ctx, target, flags) {
1108
1085
  pushedDocCount = multidoc.split('\n---\n').length;
1109
1086
  }
1110
1087
  catch (error) {
1111
- if (error instanceof PushPolicyGateError)
1112
- throw error;
1113
1088
  if (error instanceof Error && 'oclif' in error)
1114
1089
  throw error;
1115
1090
  const elapsedMs = Date.now() - startTime;
@@ -1119,12 +1094,6 @@ export async function executePush(ctx, target, flags) {
1119
1094
  // ── Push knowledge ────────────────────────────────────────────────────
1120
1095
  let knowledgeImported = 0;
1121
1096
  let knowledgeDeleted = 0;
1122
- const pushed = () => ({
1123
- knowledge: { deleted: knowledgeDeleted, imported: knowledgeImported },
1124
- preview: dryRunPreview,
1125
- response: pushResponse,
1126
- sent: pushResponse ? sent : [],
1127
- });
1128
1097
  if (ctx.knowledge && (knowledgeObjects.length > 0 || shouldDelete)) {
1129
1098
  const listUrl = ctx.knowledge.listUrl();
1130
1099
  try {
@@ -1162,10 +1131,7 @@ export async function executePush(ctx, target, flags) {
1162
1131
  if (error instanceof Error && 'oclif' in error)
1163
1132
  throw error;
1164
1133
  const elapsedMs = Date.now() - startTime;
1165
- const message = `Failed to push knowledge: ${describeNetworkError(error, listUrl, elapsedMs)}`;
1166
- if (pushResponse)
1167
- throw new FailedAfterImportError(message, pushed());
1168
- command.error(message);
1134
+ command.error(`Failed to push knowledge: ${describeNetworkError(error, listUrl, elapsedMs)}`);
1169
1135
  }
1170
1136
  }
1171
1137
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
@@ -1179,7 +1145,6 @@ export async function executePush(ctx, target, flags) {
1179
1145
  parts.push(kParts.join(', '));
1180
1146
  }
1181
1147
  log(`Pushed ${parts.join(' + ')} to ${target.label} from ${relative(process.cwd(), inputDir) || inputDir} in ${elapsed}s`);
1182
- return pushed();
1183
1148
  }
1184
1149
  // ── Error Handlers ──────────────────────────────────────────────────────────
1185
1150
  /**
@@ -1258,43 +1223,10 @@ function formatFailureDuration(elapsedMs) {
1258
1223
  ? ` (failed after ~${human}, near a common ${boundaries.find((b) => Math.abs(totalSeconds - b) <= b * 0.05)}s timeout — likely a server or proxy cutoff)`
1259
1224
  : ` (failed after ${human})`;
1260
1225
  }
1261
- /** Stop with the target's own guidance when it recognises this refusal. */
1262
- function refuseIfExplained(command, target, status, body) {
1263
- let message = body;
1264
- let payload;
1265
- try {
1266
- const parsed = JSON.parse(body);
1267
- if (typeof parsed?.message === 'string')
1268
- message = parsed.message;
1269
- payload = parsed?.payload;
1270
- }
1271
- catch {
1272
- // Not JSON
1273
- }
1274
- const refusal = payload;
1275
- if (status === 403 && refusal?.code === 'policy_gate')
1276
- throw new PushPolicyGateError(refusal);
1277
- // Policy files that weaken a mandatory policy of the live branch, from a credential without
1278
- // workspace:policy update: a permission refusal (exit 1), not a blocking finding. The platform's
1279
- // sentence already reads "Push refused: … Nothing was imported.", so it is printed as it is.
1280
- if (status === 403 && refusal?.code === WEAKENING_REFUSAL) {
1281
- command.error(`${message}${target.explainRefusal?.(status, payload) ?? policyWeakeningGuidance(payload, [], true)}`);
1282
- }
1283
- // The plan's policy cap: the platform's message names the plan, its cap and the remedy, and the
1284
- // push itself would be refused the same way, so the preview stops here rather than skipping.
1285
- if (status === 403 && refusal?.code === 'policy_plan_limit')
1286
- command.error(`Push refused (${status}): ${message}`);
1287
- if (refusal?.code === 'policy_gate_transaction_required') {
1288
- command.error('Push refused: the live branch policy gate requires a transaction. Remove --no-transaction and retry. Nothing was imported.');
1289
- }
1290
- const guidance = target.explainRefusal?.(status, payload);
1291
- if (guidance)
1292
- command.error(`Push refused (${status}): ${message}${guidance}`);
1293
- }
1294
- async function handleDryRunError(response, command, target, { log, verbose }) {
1295
- const errorText = await response.text();
1296
- refuseIfExplained(command, target, response.status, errorText);
1226
+ async function handleDryRunError(response, command, flags, target) {
1227
+ const log = command.log.bind(command);
1297
1228
  if (response.status === 404) {
1229
+ const errorText = await response.text();
1298
1230
  try {
1299
1231
  const errorJson = JSON.parse(errorText);
1300
1232
  if (errorJson.message) {
@@ -1312,6 +1244,7 @@ async function handleDryRunError(response, command, target, { log, verbose }) {
1312
1244
  log('');
1313
1245
  }
1314
1246
  else {
1247
+ const errorText = await response.text();
1315
1248
  // Check if push is disabled
1316
1249
  try {
1317
1250
  const errorJson = JSON.parse(errorText);
@@ -1334,17 +1267,8 @@ async function handleDryRunError(response, command, target, { log, verbose }) {
1334
1267
  catch {
1335
1268
  // Not JSON, fall through
1336
1269
  }
1337
- let reason = '';
1338
- try {
1339
- const errorJson = JSON.parse(errorText);
1340
- if (typeof errorJson?.message === 'string' && errorJson.message.trim())
1341
- reason = `: ${errorJson.message.trim().replace(/\.$/, '')}`;
1342
- }
1343
- catch {
1344
- // Not JSON
1345
- }
1346
- command.warn(`Push preview failed (${response.status})${reason}. Skipping preview.`);
1347
- if (verbose) {
1270
+ command.warn(`Push preview failed (${response.status}). Skipping preview.`);
1271
+ if (flags.verbose) {
1348
1272
  log(ux.colorize('dim', errorText));
1349
1273
  }
1350
1274
  }