@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.
- package/README.md +96 -4
- package/dist/commands/branch/list/index.js +5 -1
- package/dist/commands/ephemeral/impersonate/index.d.ts +1 -0
- package/dist/commands/ephemeral/impersonate/index.js +11 -3
- package/dist/commands/ephemeral/list/index.js +2 -1
- package/dist/commands/ephemeral/pull/index.d.ts +0 -6
- package/dist/commands/ephemeral/pull/index.js +10 -95
- package/dist/commands/ephemeral/push/index.d.ts +10 -0
- package/dist/commands/ephemeral/push/index.js +77 -0
- package/dist/commands/ephemeral/static_host/build/list/index.d.ts +2 -3
- package/dist/commands/ephemeral/static_host/build/list/index.js +19 -40
- package/dist/commands/ephemeral/static_host/list/index.d.ts +2 -3
- package/dist/commands/ephemeral/static_host/list/index.js +20 -40
- package/dist/commands/flatten/index.d.ts +34 -0
- package/dist/commands/flatten/index.js +140 -0
- package/dist/commands/function/list/index.d.ts +4 -4
- package/dist/commands/function/list/index.js +30 -38
- package/dist/commands/knowledge/list/index.js +2 -1
- package/dist/commands/platform/list/index.js +13 -14
- package/dist/commands/release/list/index.js +13 -14
- package/dist/commands/release/pull/index.d.ts +0 -6
- package/dist/commands/release/pull/index.js +10 -95
- package/dist/commands/sandbox/env/list/index.js +4 -0
- package/dist/commands/sandbox/pull/index.d.ts +0 -1
- package/dist/commands/sandbox/pull/index.js +10 -77
- package/dist/commands/sandbox/unit_test/list/index.d.ts +2 -0
- package/dist/commands/sandbox/unit_test/list/index.js +9 -14
- package/dist/commands/sandbox/unit_test/run_all/index.d.ts +1 -0
- package/dist/commands/sandbox/unit_test/run_all/index.js +67 -37
- package/dist/commands/sandbox/workflow_test/list/index.d.ts +2 -0
- package/dist/commands/sandbox/workflow_test/list/index.js +9 -14
- package/dist/commands/sandbox/workflow_test/run_all/index.d.ts +1 -0
- package/dist/commands/sandbox/workflow_test/run_all/index.js +65 -35
- package/dist/commands/static_host/build/list/index.d.ts +2 -3
- package/dist/commands/static_host/build/list/index.js +19 -40
- package/dist/commands/static_host/build/pull/index.js +12 -9
- package/dist/commands/static_host/list/index.d.ts +2 -3
- package/dist/commands/static_host/list/index.js +20 -40
- package/dist/commands/static_host/migrate/index.js +14 -10
- package/dist/commands/tenant/backup/list/index.js +13 -14
- package/dist/commands/tenant/cluster/list/index.js +9 -10
- package/dist/commands/tenant/env/list/index.js +4 -0
- package/dist/commands/tenant/list/index.js +19 -20
- package/dist/commands/tenant/pull/index.d.ts +0 -6
- package/dist/commands/tenant/pull/index.js +10 -95
- package/dist/commands/tenant/snapshot/list/index.js +5 -1
- package/dist/commands/tenant/unit_test/list/index.d.ts +4 -2
- package/dist/commands/tenant/unit_test/list/index.js +9 -14
- package/dist/commands/tenant/unit_test/run_all/index.d.ts +1 -0
- package/dist/commands/tenant/unit_test/run_all/index.js +67 -37
- package/dist/commands/tenant/workflow_test/list/index.d.ts +4 -2
- package/dist/commands/tenant/workflow_test/list/index.js +9 -14
- package/dist/commands/tenant/workflow_test/run_all/index.d.ts +1 -0
- package/dist/commands/tenant/workflow_test/run_all/index.js +65 -35
- package/dist/commands/unit_test/list/index.d.ts +3 -1
- package/dist/commands/unit_test/list/index.js +9 -14
- package/dist/commands/unit_test/run_all/index.d.ts +1 -0
- package/dist/commands/unit_test/run_all/index.js +68 -40
- package/dist/commands/workflow_test/list/index.d.ts +3 -1
- package/dist/commands/workflow_test/list/index.js +10 -13
- package/dist/commands/workflow_test/run_all/index.d.ts +1 -0
- package/dist/commands/workflow_test/run_all/index.js +67 -36
- package/dist/commands/workspace/git/pull/index.js +53 -3
- package/dist/commands/workspace/list/index.js +7 -13
- package/dist/commands/workspace/pull/index.d.ts +0 -6
- package/dist/commands/workspace/pull/index.js +10 -95
- package/dist/utils/concurrency.d.ts +29 -0
- package/dist/utils/concurrency.js +54 -0
- package/dist/utils/document-parser.d.ts +116 -0
- package/dist/utils/document-parser.js +274 -1
- package/dist/utils/flatten.d.ts +36 -0
- package/dist/utils/flatten.js +68 -0
- package/dist/utils/knowledge-sync.d.ts +1 -0
- package/dist/utils/knowledge-sync.js +11 -5
- package/dist/utils/microservice-wait.d.ts +53 -0
- package/dist/utils/microservice-wait.js +83 -0
- package/dist/utils/multidoc-push.d.ts +12 -0
- package/dist/utils/multidoc-push.js +84 -0
- package/dist/utils/paging.d.ts +145 -0
- package/dist/utils/paging.js +199 -0
- package/dist/utils/reference-checker.js +13 -0
- package/oclif.manifest.json +2762 -2550
- 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;
|