@xano/cli 1.0.6-beta.1 → 1.0.6-beta.10

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 (83) hide show
  1. package/README.md +96 -4
  2. package/dist/commands/branch/list/index.js +5 -1
  3. package/dist/commands/ephemeral/impersonate/index.d.ts +1 -0
  4. package/dist/commands/ephemeral/impersonate/index.js +11 -3
  5. package/dist/commands/ephemeral/list/index.js +2 -1
  6. package/dist/commands/ephemeral/pull/index.d.ts +0 -6
  7. package/dist/commands/ephemeral/pull/index.js +10 -95
  8. package/dist/commands/ephemeral/push/index.d.ts +10 -0
  9. package/dist/commands/ephemeral/push/index.js +77 -0
  10. package/dist/commands/ephemeral/static_host/build/list/index.d.ts +2 -3
  11. package/dist/commands/ephemeral/static_host/build/list/index.js +19 -40
  12. package/dist/commands/ephemeral/static_host/list/index.d.ts +2 -3
  13. package/dist/commands/ephemeral/static_host/list/index.js +20 -40
  14. package/dist/commands/flatten/index.d.ts +34 -0
  15. package/dist/commands/flatten/index.js +140 -0
  16. package/dist/commands/function/list/index.d.ts +4 -4
  17. package/dist/commands/function/list/index.js +30 -38
  18. package/dist/commands/knowledge/list/index.js +2 -1
  19. package/dist/commands/platform/list/index.js +13 -14
  20. package/dist/commands/release/list/index.js +13 -14
  21. package/dist/commands/release/pull/index.d.ts +0 -6
  22. package/dist/commands/release/pull/index.js +10 -95
  23. package/dist/commands/sandbox/env/list/index.js +4 -0
  24. package/dist/commands/sandbox/pull/index.d.ts +0 -1
  25. package/dist/commands/sandbox/pull/index.js +10 -77
  26. package/dist/commands/sandbox/unit_test/list/index.d.ts +2 -0
  27. package/dist/commands/sandbox/unit_test/list/index.js +9 -14
  28. package/dist/commands/sandbox/unit_test/run_all/index.d.ts +1 -0
  29. package/dist/commands/sandbox/unit_test/run_all/index.js +67 -37
  30. package/dist/commands/sandbox/workflow_test/list/index.d.ts +2 -0
  31. package/dist/commands/sandbox/workflow_test/list/index.js +9 -14
  32. package/dist/commands/sandbox/workflow_test/run_all/index.d.ts +1 -0
  33. package/dist/commands/sandbox/workflow_test/run_all/index.js +65 -35
  34. package/dist/commands/static_host/build/list/index.d.ts +2 -3
  35. package/dist/commands/static_host/build/list/index.js +19 -40
  36. package/dist/commands/static_host/build/pull/index.js +12 -9
  37. package/dist/commands/static_host/list/index.d.ts +2 -3
  38. package/dist/commands/static_host/list/index.js +20 -40
  39. package/dist/commands/static_host/migrate/index.js +14 -10
  40. package/dist/commands/tenant/backup/list/index.js +13 -14
  41. package/dist/commands/tenant/cluster/list/index.js +9 -10
  42. package/dist/commands/tenant/env/list/index.js +4 -0
  43. package/dist/commands/tenant/list/index.js +19 -20
  44. package/dist/commands/tenant/pull/index.d.ts +0 -6
  45. package/dist/commands/tenant/pull/index.js +10 -95
  46. package/dist/commands/tenant/snapshot/list/index.js +5 -1
  47. package/dist/commands/tenant/unit_test/list/index.d.ts +4 -2
  48. package/dist/commands/tenant/unit_test/list/index.js +9 -14
  49. package/dist/commands/tenant/unit_test/run_all/index.d.ts +1 -0
  50. package/dist/commands/tenant/unit_test/run_all/index.js +67 -37
  51. package/dist/commands/tenant/workflow_test/list/index.d.ts +4 -2
  52. package/dist/commands/tenant/workflow_test/list/index.js +9 -14
  53. package/dist/commands/tenant/workflow_test/run_all/index.d.ts +1 -0
  54. package/dist/commands/tenant/workflow_test/run_all/index.js +65 -35
  55. package/dist/commands/unit_test/list/index.d.ts +3 -1
  56. package/dist/commands/unit_test/list/index.js +9 -14
  57. package/dist/commands/unit_test/run_all/index.d.ts +1 -0
  58. package/dist/commands/unit_test/run_all/index.js +68 -40
  59. package/dist/commands/workflow_test/list/index.d.ts +3 -1
  60. package/dist/commands/workflow_test/list/index.js +10 -13
  61. package/dist/commands/workflow_test/run_all/index.d.ts +1 -0
  62. package/dist/commands/workflow_test/run_all/index.js +67 -36
  63. package/dist/commands/workspace/git/pull/index.js +53 -3
  64. package/dist/commands/workspace/list/index.js +7 -13
  65. package/dist/commands/workspace/pull/index.d.ts +0 -6
  66. package/dist/commands/workspace/pull/index.js +10 -95
  67. package/dist/utils/concurrency.d.ts +29 -0
  68. package/dist/utils/concurrency.js +54 -0
  69. package/dist/utils/document-parser.d.ts +116 -0
  70. package/dist/utils/document-parser.js +274 -1
  71. package/dist/utils/flatten.d.ts +36 -0
  72. package/dist/utils/flatten.js +68 -0
  73. package/dist/utils/knowledge-sync.d.ts +1 -0
  74. package/dist/utils/knowledge-sync.js +11 -5
  75. package/dist/utils/microservice-wait.d.ts +53 -0
  76. package/dist/utils/microservice-wait.js +83 -0
  77. package/dist/utils/multidoc-push.d.ts +12 -0
  78. package/dist/utils/multidoc-push.js +84 -0
  79. package/dist/utils/paging.d.ts +145 -0
  80. package/dist/utils/paging.js +199 -0
  81. package/dist/utils/reference-checker.js +13 -0
  82. package/oclif.manifest.json +2762 -2550
  83. package/package.json +1 -1
@@ -0,0 +1,199 @@
1
+ /* eslint-disable camelcase */
2
+ import { Flags } from '@oclif/core';
3
+ function makePageFlag(description) {
4
+ return Flags.integer({ default: 1, description, required: false });
5
+ }
6
+ function makePerPageFlag(defaultValue, description) {
7
+ return Flags.integer({ default: defaultValue, description, required: false });
8
+ }
9
+ export function pagingFlags(tier, options = {}) {
10
+ if (tier === 'none') {
11
+ return {};
12
+ }
13
+ if (tier === 'page-only-envelope') {
14
+ const fixed = options.fixedPerPage;
15
+ return {
16
+ page: makePageFlag(fixed
17
+ ? `Page number for pagination (page size is fixed at ${fixed} by the API)`
18
+ : 'Page number for pagination'),
19
+ };
20
+ }
21
+ return {
22
+ page: makePageFlag('Page number for pagination'),
23
+ per_page: makePerPageFlag(50, options.maxPerPage
24
+ ? `Number of results per page (max ${options.maxPerPage})`
25
+ : 'Number of results per page'),
26
+ };
27
+ }
28
+ /**
29
+ * Translate parsed paging flags into query-string entries, emitting only the
30
+ * params the endpoint actually declares.
31
+ */
32
+ export function buildPagingParams(flags, tier) {
33
+ if (tier === 'none') {
34
+ return [];
35
+ }
36
+ const { page, per_page: perPage } = flags;
37
+ const params = [];
38
+ if (page !== undefined) {
39
+ params.push(['page', String(page)]);
40
+ }
41
+ if (tier === 'envelope' && perPage !== undefined) {
42
+ params.push(['per_page', String(perPage)]);
43
+ }
44
+ return params;
45
+ }
46
+ /** Coerce a possibly-null numeric paging field to a number or undefined. */
47
+ function optionalNumber(value) {
48
+ return typeof value === 'number' ? value : undefined;
49
+ }
50
+ /**
51
+ * Absorb the response shapes the Metadata API returns for list endpoints:
52
+ * a bare array, a paging envelope keyed on `items`, or an object keyed on the
53
+ * resource name (e.g. `{workspaces: [...]}`).
54
+ *
55
+ * `resourceKeys` names any resource-keyed fallbacks to check, in order.
56
+ */
57
+ export function normalizeListResponse(data, resourceKeys = []) {
58
+ if (Array.isArray(data)) {
59
+ return { items: data };
60
+ }
61
+ if (data && typeof data === 'object') {
62
+ const record = data;
63
+ if (Array.isArray(record.items)) {
64
+ return {
65
+ curPage: optionalNumber(record.curPage),
66
+ items: record.items,
67
+ itemsTotal: optionalNumber(record.itemsTotal),
68
+ nextPage: optionalNumber(record.nextPage),
69
+ prevPage: optionalNumber(record.prevPage),
70
+ };
71
+ }
72
+ for (const key of resourceKeys) {
73
+ if (Array.isArray(record[key])) {
74
+ return {
75
+ curPage: optionalNumber(record.curPage),
76
+ items: record[key],
77
+ itemsTotal: optionalNumber(record.itemsTotal),
78
+ nextPage: optionalNumber(record.nextPage),
79
+ prevPage: optionalNumber(record.prevPage),
80
+ };
81
+ }
82
+ }
83
+ }
84
+ const accepted = ['an array', 'an object with an items array', ...resourceKeys.map((k) => `an object with a ${k} array`)];
85
+ throw new Error(`Unexpected API response format. Expected ${accepted.join(', ')}.`);
86
+ }
87
+ /** Page size used when the CLI pages an endpoint on the user's behalf. */
88
+ export const INTERNAL_PAGE_SIZE = 100;
89
+ /**
90
+ * Walk an envelope-tier endpoint page by page and collect every item.
91
+ *
92
+ * Termination is the server's own `nextPage`, never "the page came back full" —
93
+ * the same rule the footer follows. An empty page also stops the walk, which
94
+ * covers an endpoint that omits `nextPage` entirely rather than looping forever.
95
+ *
96
+ * `maxPages` is a runaway backstop, not a limit users are expected to hit; when
97
+ * it trips, `onTruncate` fires so the caller can say so out loud instead of
98
+ * silently processing a subset.
99
+ */
100
+ export async function collectAllPages(fetchPage, options = {}) {
101
+ const maxPages = options.maxPages ?? 100;
102
+ const items = [];
103
+ for (let page = 1; page <= maxPages; page++) {
104
+ // eslint-disable-next-line no-await-in-loop
105
+ const list = await fetchPage(page);
106
+ items.push(...list.items);
107
+ if (list.items.length === 0 || list.nextPage === undefined) {
108
+ return items;
109
+ }
110
+ }
111
+ options.onTruncate?.(items.length);
112
+ return items;
113
+ }
114
+ /**
115
+ * Build the `--output json` payload for a list command.
116
+ *
117
+ * Field names mirror the Metadata API envelope exactly — `curPage`, `nextPage`,
118
+ * `prevPage`, `itemsTotal`, `items` — so a script can move between the CLI and
119
+ * the raw API without a translation layer. `perPage` is the one field the CLI
120
+ * injects: the API never echoes it back, and it is otherwise invisible when the
121
+ * user leaves the flag at its default.
122
+ *
123
+ * Emits only fields the response actually proves, mirroring the footer's
124
+ * honesty rule: `itemsTotal` appears only when the server sent it, `nextPage`
125
+ * only when the server computed it.
126
+ *
127
+ * Without this envelope, a script driving `--output json` sees a bare array and
128
+ * its only available stop condition is `length < perPage` — precisely the
129
+ * page-fullness inference this module refuses to make in the footer.
130
+ */
131
+ export function buildPagingJson(list, options) {
132
+ const payload = { items: list.items };
133
+ if (options.tier === 'none') {
134
+ return payload;
135
+ }
136
+ const hasPositionEvidence = list.curPage !== undefined ||
137
+ list.nextPage !== undefined ||
138
+ list.prevPage !== undefined ||
139
+ list.itemsTotal !== undefined;
140
+ // Same rule as the footer: with no metadata we cannot assert a position.
141
+ if (!hasPositionEvidence) {
142
+ return payload;
143
+ }
144
+ const curPage = list.curPage ?? options.page;
145
+ if (curPage !== undefined)
146
+ payload.curPage = curPage;
147
+ if (options.tier === 'envelope' && options.perPage !== undefined)
148
+ payload.perPage = options.perPage;
149
+ if (list.nextPage !== undefined)
150
+ payload.nextPage = list.nextPage;
151
+ if (list.prevPage !== undefined)
152
+ payload.prevPage = list.prevPage;
153
+ if (list.itemsTotal !== undefined)
154
+ payload.itemsTotal = list.itemsTotal;
155
+ return payload;
156
+ }
157
+ const SEPARATOR = ' · ';
158
+ /**
159
+ * Render the paging footer for a list command, reporting only facts the response
160
+ * actually proves. Returns null when there is nothing worth saying — an empty
161
+ * result set already prints its own "No X found" line.
162
+ *
163
+ * Deliberately asymmetric across tiers: `envelope` shows a next-page hint but no
164
+ * total, `page-only-envelope` shows a total but no next-page hint, and `none`
165
+ * shows a bare count. See PagingTier for why.
166
+ */
167
+ export function formatPagingFooter(list, options) {
168
+ const count = list.items.length;
169
+ const plural = options.nounPlural ?? `${options.noun}s`;
170
+ const countPhrase = `${count} ${count === 1 ? options.noun : plural}`;
171
+ // A paged tier whose response carried no metadata at all tells us nothing
172
+ // about position — the endpoint may have ignored `page` entirely. Reporting
173
+ // the requested page here would state the user's wish as a server fact, so
174
+ // fall back to the bare count.
175
+ const hasPositionEvidence = list.curPage !== undefined ||
176
+ list.nextPage !== undefined ||
177
+ list.prevPage !== undefined ||
178
+ list.itemsTotal !== undefined;
179
+ if (options.tier === 'none' || !hasPositionEvidence) {
180
+ return count === 0 ? null : countPhrase;
181
+ }
182
+ // An empty page past the end is worth reporting when we know the true total —
183
+ // otherwise `--page 99` on a populated workspace is indistinguishable from an
184
+ // empty one.
185
+ if (count === 0 && list.itemsTotal === undefined) {
186
+ return null;
187
+ }
188
+ const page = list.curPage ?? options.page ?? 1;
189
+ const parts = [`Page ${page}`, `${count} shown`];
190
+ if (options.tier === 'envelope' && list.nextPage !== undefined) {
191
+ // Server-computed. Null/absent on the last page, so following it can never
192
+ // land on an empty result. Page fullness is never consulted here.
193
+ parts.push(`next: --page ${list.nextPage}`);
194
+ }
195
+ if (options.tier === 'page-only-envelope' && list.itemsTotal !== undefined) {
196
+ parts.push(`${list.itemsTotal} total`);
197
+ }
198
+ return parts.join(SEPARATOR);
199
+ }
@@ -28,6 +28,16 @@ const REFERENCE_PATTERNS = [
28
28
  },
29
29
  // Schema foreign key references: table = "name" inside field definitions
30
30
  { keyword: 'table (FK)', regex: /\btable\s*=\s*"([^"]*)"/gm, targetType: 'table' },
31
+ // Realtime v2: a channel references its owning realtime_server by name via a
32
+ // top-level `realtime_server = "..."` (renamed from a bare `server` to match
33
+ // the api_group/mcp_server convention). The full keyword is unambiguous, so no
34
+ // false-match against another object type's `server` field.
35
+ {
36
+ keyword: 'channel (realtime_server)',
37
+ regex: /^\s*realtime_server\s*=\s*"([^"]*)"/gm,
38
+ sourceType: 'channel',
39
+ targetType: 'realtime_server',
40
+ },
31
41
  ];
32
42
  /**
33
43
  * Strip surrounding quotes from a name if present.
@@ -119,6 +129,9 @@ export function checkReferences(documents, serverOperations) {
119
129
  if (!parsed)
120
130
  continue;
121
131
  for (const pattern of REFERENCE_PATTERNS) {
132
+ // Skip patterns scoped to a different source document type.
133
+ if (pattern.sourceType && pattern.sourceType !== parsed.type)
134
+ continue;
122
135
  // Reset regex state for each document
123
136
  pattern.regex.lastIndex = 0;
124
137
  let match;