@xano/cli 1.0.6-beta.9 → 1.2.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/README.md +46 -62
- package/dist/base-command.d.ts +0 -2
- package/dist/base-command.js +4 -10
- package/dist/commands/release/pull/index.d.ts +6 -0
- package/dist/commands/release/pull/index.js +95 -10
- package/dist/commands/sandbox/pull/index.d.ts +1 -0
- package/dist/commands/sandbox/pull/index.js +77 -10
- package/dist/commands/sandbox/unit_test/run/index.js +17 -11
- package/dist/commands/sandbox/unit_test/run_all/index.js +9 -1
- package/dist/commands/sandbox/workflow_test/run/index.js +12 -9
- package/dist/commands/sandbox/workflow_test/run_all/index.js +9 -1
- package/dist/commands/tenant/pull/index.d.ts +6 -0
- package/dist/commands/tenant/pull/index.js +95 -10
- package/dist/commands/tenant/unit_test/run/index.js +19 -11
- package/dist/commands/tenant/unit_test/run_all/index.js +13 -1
- package/dist/commands/tenant/workflow_test/run/index.js +14 -9
- package/dist/commands/tenant/workflow_test/run_all/index.js +13 -1
- package/dist/commands/unit_test/run/index.js +19 -11
- package/dist/commands/unit_test/run_all/index.js +13 -1
- package/dist/commands/workflow_test/run/index.js +15 -10
- package/dist/commands/workflow_test/run_all/index.js +15 -3
- package/dist/commands/workspace/git/pull/index.js +3 -53
- package/dist/commands/workspace/pull/index.d.ts +6 -0
- package/dist/commands/workspace/pull/index.js +95 -10
- package/dist/utils/document-parser.d.ts +0 -85
- package/dist/utils/document-parser.js +1 -214
- package/dist/utils/knowledge-sync.d.ts +0 -1
- package/dist/utils/knowledge-sync.js +5 -11
- package/dist/utils/paging.d.ts +1 -2
- package/dist/utils/reference-checker.js +0 -13
- package/oclif.manifest.json +2796 -4820
- package/package.json +1 -10
- package/dist/commands/ephemeral/create/index.d.ts +0 -18
- package/dist/commands/ephemeral/create/index.js +0 -103
- package/dist/commands/ephemeral/delete/index.d.ts +0 -18
- package/dist/commands/ephemeral/delete/index.js +0 -99
- package/dist/commands/ephemeral/edit/index.d.ts +0 -18
- package/dist/commands/ephemeral/edit/index.js +0 -109
- package/dist/commands/ephemeral/get/index.d.ts +0 -21
- package/dist/commands/ephemeral/get/index.js +0 -125
- package/dist/commands/ephemeral/impersonate/index.d.ts +0 -20
- package/dist/commands/ephemeral/impersonate/index.js +0 -120
- package/dist/commands/ephemeral/list/index.d.ts +0 -19
- package/dist/commands/ephemeral/list/index.js +0 -123
- package/dist/commands/ephemeral/pull/index.d.ts +0 -19
- package/dist/commands/ephemeral/pull/index.js +0 -164
- package/dist/commands/ephemeral/push/index.d.ts +0 -35
- package/dist/commands/ephemeral/push/index.js +0 -221
- package/dist/commands/ephemeral/static_host/build/delete/index.d.ts +0 -20
- package/dist/commands/ephemeral/static_host/build/delete/index.js +0 -121
- package/dist/commands/ephemeral/static_host/build/get/index.d.ts +0 -18
- package/dist/commands/ephemeral/static_host/build/get/index.js +0 -137
- package/dist/commands/ephemeral/static_host/build/list/index.d.ts +0 -18
- package/dist/commands/ephemeral/static_host/build/list/index.js +0 -137
- package/dist/commands/ephemeral/static_host/build/pull/index.d.ts +0 -53
- package/dist/commands/ephemeral/static_host/build/pull/index.js +0 -308
- package/dist/commands/ephemeral/static_host/build/push/index.d.ts +0 -24
- package/dist/commands/ephemeral/static_host/build/push/index.js +0 -250
- package/dist/commands/ephemeral/static_host/create/index.d.ts +0 -18
- package/dist/commands/ephemeral/static_host/create/index.js +0 -92
- package/dist/commands/ephemeral/static_host/deploy/index.d.ts +0 -19
- package/dist/commands/ephemeral/static_host/deploy/index.js +0 -112
- package/dist/commands/ephemeral/static_host/edit/index.d.ts +0 -24
- package/dist/commands/ephemeral/static_host/edit/index.js +0 -158
- package/dist/commands/ephemeral/static_host/get/index.d.ts +0 -19
- package/dist/commands/ephemeral/static_host/get/index.js +0 -101
- package/dist/commands/ephemeral/static_host/list/index.d.ts +0 -17
- package/dist/commands/ephemeral/static_host/list/index.js +0 -132
- package/dist/utils/microservice-wait.d.ts +0 -53
- package/dist/utils/microservice-wait.js +0 -83
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
import { Args, Flags } from '@oclif/core';
|
|
2
|
-
import BaseCommand from '../../../../base-command.js';
|
|
3
|
-
import { buildPagingJson, buildPagingParams, formatPagingFooter, normalizeListResponse, pagingFlags } from '../../../../utils/paging.js';
|
|
4
|
-
export default class EphemeralStaticHostList extends BaseCommand {
|
|
5
|
-
static args = {
|
|
6
|
-
tenant_name: Args.string({
|
|
7
|
-
description: 'Ephemeral tenant name',
|
|
8
|
-
required: true,
|
|
9
|
-
}),
|
|
10
|
-
};
|
|
11
|
-
static description = 'List all static hosts for an ephemeral tenant from the Xano Metadata API';
|
|
12
|
-
static examples = [
|
|
13
|
-
`$ xano ephemeral static_host list e4f2-9ab1-xyz1 -w 40
|
|
14
|
-
Available static hosts:
|
|
15
|
-
- my-static-host (ID: 1)
|
|
16
|
-
- another-host (ID: 2)
|
|
17
|
-
`,
|
|
18
|
-
`$ xano ephemeral static_host list e4f2-9ab1-xyz1 --profile production
|
|
19
|
-
Available static hosts:
|
|
20
|
-
- my-static-host (ID: 1)
|
|
21
|
-
- another-host (ID: 2)
|
|
22
|
-
`,
|
|
23
|
-
`$ xano ephemeral static_host list e4f2-9ab1-xyz1 -w 40 --output json
|
|
24
|
-
{
|
|
25
|
-
"count": 1,
|
|
26
|
-
"page": 1,
|
|
27
|
-
"total": 3,
|
|
28
|
-
"items": [
|
|
29
|
-
{
|
|
30
|
-
"id": 1,
|
|
31
|
-
"name": "my-static-host"
|
|
32
|
-
}
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
`,
|
|
36
|
-
`$ xano ephemeral static_host list e4f2-9ab1-xyz1 -p staging -o json --page 2
|
|
37
|
-
[
|
|
38
|
-
{
|
|
39
|
-
"id": 3,
|
|
40
|
-
"name": "static-host-3"
|
|
41
|
-
}
|
|
42
|
-
]
|
|
43
|
-
`,
|
|
44
|
-
];
|
|
45
|
-
static flags = {
|
|
46
|
-
...BaseCommand.baseFlags,
|
|
47
|
-
output: Flags.string({
|
|
48
|
-
char: 'o',
|
|
49
|
-
default: 'summary',
|
|
50
|
-
description: 'Output format',
|
|
51
|
-
options: ['summary', 'json'],
|
|
52
|
-
required: false,
|
|
53
|
-
}),
|
|
54
|
-
...pagingFlags('page-only-envelope', { fixedPerPage: 100 }),
|
|
55
|
-
workspace: Flags.string({
|
|
56
|
-
char: 'w',
|
|
57
|
-
description: 'Workspace ID (optional if set in profile)',
|
|
58
|
-
required: false,
|
|
59
|
-
}),
|
|
60
|
-
};
|
|
61
|
-
async run() {
|
|
62
|
-
const { args, flags } = await this.parse(EphemeralStaticHostList);
|
|
63
|
-
const { profile, profileName } = this.resolveProfile(flags);
|
|
64
|
-
const tenantName = args.tenant_name;
|
|
65
|
-
// Determine workspace_id from flag or profile
|
|
66
|
-
let workspaceId;
|
|
67
|
-
if (flags.workspace) {
|
|
68
|
-
workspaceId = flags.workspace;
|
|
69
|
-
}
|
|
70
|
-
else if (profile.workspace) {
|
|
71
|
-
workspaceId = profile.workspace;
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
this.error(`Workspace ID is required. Either:\n` +
|
|
75
|
-
` 1. Provide it as a flag: xano ephemeral static_host list <tenant_name> -w <workspace_id>\n` +
|
|
76
|
-
` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
|
|
77
|
-
}
|
|
78
|
-
// Build query parameters
|
|
79
|
-
const queryParams = new URLSearchParams(buildPagingParams(flags, 'page-only-envelope'));
|
|
80
|
-
// Construct the API URL
|
|
81
|
-
const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/tenant/${tenantName}/static_host?${queryParams.toString()}`;
|
|
82
|
-
// Fetch static hosts from the API
|
|
83
|
-
try {
|
|
84
|
-
const response = await this.verboseFetch(apiUrl, {
|
|
85
|
-
headers: {
|
|
86
|
-
'accept': 'application/json',
|
|
87
|
-
'Authorization': `Bearer ${profile.access_token}`,
|
|
88
|
-
},
|
|
89
|
-
method: 'GET',
|
|
90
|
-
}, flags.verbose, profile.access_token);
|
|
91
|
-
if (!response.ok) {
|
|
92
|
-
const errorText = await response.text();
|
|
93
|
-
this.error(`API request failed with status ${response.status}: ${response.statusText}\n${errorText}`);
|
|
94
|
-
}
|
|
95
|
-
const list = normalizeListResponse(await response.json(), ['static_hosts']);
|
|
96
|
-
const staticHosts = list.items;
|
|
97
|
-
// Output results
|
|
98
|
-
if (flags.output === 'json') {
|
|
99
|
-
this.log(JSON.stringify(buildPagingJson(list, { page: flags.page, tier: 'page-only-envelope' }), null, 2));
|
|
100
|
-
}
|
|
101
|
-
else {
|
|
102
|
-
// summary format
|
|
103
|
-
if (staticHosts.length === 0) {
|
|
104
|
-
this.log('No static hosts found');
|
|
105
|
-
}
|
|
106
|
-
else {
|
|
107
|
-
this.log('Available static hosts:');
|
|
108
|
-
for (const host of staticHosts) {
|
|
109
|
-
if (host.id === undefined) {
|
|
110
|
-
this.log(` - ${host.name}`);
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
const domainInfo = host.domain ? ` - ${host.domain}` : '';
|
|
114
|
-
this.log(` - ${host.name} (ID: ${host.id})${domainInfo}`);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const footer = formatPagingFooter(list, { noun: 'static host', page: flags.page, tier: 'page-only-envelope' });
|
|
119
|
-
if (footer)
|
|
120
|
-
this.log(footer);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
catch (error) {
|
|
124
|
-
if (error instanceof Error) {
|
|
125
|
-
this.error(`Failed to fetch static hosts: ${error.message}`);
|
|
126
|
-
}
|
|
127
|
-
else {
|
|
128
|
-
this.error(`Failed to fetch static hosts: ${String(error)}`);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Poll a tenant's microservice deployment status until every auto-deployed
|
|
3
|
-
* microservice settles (ok/error) or a timeout elapses. Backs `ephemeral push
|
|
4
|
-
* --wait`: after a multidoc push auto-deploys microservices (tenant_deploy=
|
|
5
|
-
* "auto"), the CLI waits here for them to become Ready and reports the outcome.
|
|
6
|
-
*
|
|
7
|
-
* The backend route (GET .../tenant/{name}/microservice, statement
|
|
8
|
-
* mvp:microservice_status_all) returns one entry per microservice with a live
|
|
9
|
-
* k8s readiness read. `manual`/`disabled` microservices are reported but not
|
|
10
|
-
* waited on (they were never deployed by the push).
|
|
11
|
-
*/
|
|
12
|
-
/** One microservice's status as returned by the tenant status route. */
|
|
13
|
-
export interface MicroserviceStatusEntry {
|
|
14
|
-
desired?: number;
|
|
15
|
-
detail?: string;
|
|
16
|
-
microservice_id: number;
|
|
17
|
-
name: string;
|
|
18
|
-
ready?: number;
|
|
19
|
-
status: string;
|
|
20
|
-
tenant_deploy?: string;
|
|
21
|
-
}
|
|
22
|
-
export interface WaitOptions {
|
|
23
|
-
/** Bearer token for the authed status GET. */
|
|
24
|
-
accessToken: string;
|
|
25
|
-
/** Called once per poll with the latest entries, for progress rendering. */
|
|
26
|
-
onPoll?: (entries: MicroserviceStatusEntry[], elapsedMs: number) => void;
|
|
27
|
-
/** Poll cadence in ms (default 2000). */
|
|
28
|
-
pollIntervalMs?: number;
|
|
29
|
-
/** Absolute URL of the tenant microservice status route. */
|
|
30
|
-
statusUrl: string;
|
|
31
|
-
/** Overall wait budget in ms (default 300000 = 300s). */
|
|
32
|
-
timeoutMs?: number;
|
|
33
|
-
/** Authed fetch (command.verboseFetch bound), so TLS/dispatcher settings apply. */
|
|
34
|
-
verboseFetch: (url: string, options: RequestInit, verbose: boolean, authToken?: string) => Promise<Response>;
|
|
35
|
-
/** Verbose request logging passthrough. */
|
|
36
|
-
verbose?: boolean;
|
|
37
|
-
}
|
|
38
|
-
export interface WaitResult {
|
|
39
|
-
/** The final status entries observed. */
|
|
40
|
-
entries: MicroserviceStatusEntry[];
|
|
41
|
-
/** True if any awaited (auto) microservice ended in "error". */
|
|
42
|
-
hadError: boolean;
|
|
43
|
-
/** True if the wait budget elapsed before all awaited microservices settled. */
|
|
44
|
-
timedOut: boolean;
|
|
45
|
-
}
|
|
46
|
-
/** An awaited microservice is one that was auto-deployed and is not skipped/disabled. */
|
|
47
|
-
export declare function isAwaited(entry: MicroserviceStatusEntry): boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Poll until all awaited microservices settle or the timeout elapses. Transient
|
|
50
|
-
* poll failures (network blips, a brief 5xx while a pod restarts) are tolerated —
|
|
51
|
-
* they don't abort the wait; only the overall timeout does.
|
|
52
|
-
*/
|
|
53
|
-
export declare function waitForMicroservices(opts: WaitOptions): Promise<WaitResult>;
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Poll a tenant's microservice deployment status until every auto-deployed
|
|
3
|
-
* microservice settles (ok/error) or a timeout elapses. Backs `ephemeral push
|
|
4
|
-
* --wait`: after a multidoc push auto-deploys microservices (tenant_deploy=
|
|
5
|
-
* "auto"), the CLI waits here for them to become Ready and reports the outcome.
|
|
6
|
-
*
|
|
7
|
-
* The backend route (GET .../tenant/{name}/microservice, statement
|
|
8
|
-
* mvp:microservice_status_all) returns one entry per microservice with a live
|
|
9
|
-
* k8s readiness read. `manual`/`disabled` microservices are reported but not
|
|
10
|
-
* waited on (they were never deployed by the push).
|
|
11
|
-
*/
|
|
12
|
-
/** Statuses that mean an awaited microservice has settled (no longer in flight). */
|
|
13
|
-
const SETTLED = new Set(['ok', 'error']);
|
|
14
|
-
/** Statuses that mean we don't wait on this microservice at all. */
|
|
15
|
-
const NOT_AWAITED = new Set(['skipped', 'disabled']);
|
|
16
|
-
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
17
|
-
/** An awaited microservice is one that was auto-deployed and is not skipped/disabled. */
|
|
18
|
-
export function isAwaited(entry) {
|
|
19
|
-
return !NOT_AWAITED.has(entry.status) && (entry.tenant_deploy ?? 'auto') !== 'manual';
|
|
20
|
-
}
|
|
21
|
-
/** True once every awaited microservice has settled (ok/error). */
|
|
22
|
-
function allSettled(entries) {
|
|
23
|
-
const awaited = entries.filter((e) => isAwaited(e));
|
|
24
|
-
// No auto microservices at all → nothing to wait for.
|
|
25
|
-
if (awaited.length === 0)
|
|
26
|
-
return true;
|
|
27
|
-
return awaited.every((e) => SETTLED.has(e.status));
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Fetch the status route once. Throws on a non-2xx so the caller can decide
|
|
31
|
-
* whether a transient failure is fatal (it isn't — we keep polling).
|
|
32
|
-
*/
|
|
33
|
-
async function fetchStatus(opts) {
|
|
34
|
-
const res = await opts.verboseFetch(opts.statusUrl, { headers: { Authorization: `Bearer ${opts.accessToken}` }, method: 'GET' }, opts.verbose ?? false, opts.accessToken);
|
|
35
|
-
if (!res.ok) {
|
|
36
|
-
throw new Error(`status ${res.status} ${res.statusText}`);
|
|
37
|
-
}
|
|
38
|
-
const body = (await res.json());
|
|
39
|
-
if (!Array.isArray(body)) {
|
|
40
|
-
throw new Error('unexpected status response shape');
|
|
41
|
-
}
|
|
42
|
-
return body;
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* Poll until all awaited microservices settle or the timeout elapses. Transient
|
|
46
|
-
* poll failures (network blips, a brief 5xx while a pod restarts) are tolerated —
|
|
47
|
-
* they don't abort the wait; only the overall timeout does.
|
|
48
|
-
*/
|
|
49
|
-
export async function waitForMicroservices(opts) {
|
|
50
|
-
const pollIntervalMs = opts.pollIntervalMs ?? 2000;
|
|
51
|
-
const timeoutMs = opts.timeoutMs ?? 300000;
|
|
52
|
-
const start = Date.now();
|
|
53
|
-
let entries = [];
|
|
54
|
-
let consecutiveErrors = 0;
|
|
55
|
-
// Poll loop. We always do at least one fetch so `--wait` reports even when the
|
|
56
|
-
// deployment already settled between the push returning and the first poll.
|
|
57
|
-
for (;;) {
|
|
58
|
-
const elapsed = Date.now() - start;
|
|
59
|
-
try {
|
|
60
|
-
entries = await fetchStatus(opts);
|
|
61
|
-
consecutiveErrors = 0;
|
|
62
|
-
opts.onPoll?.(entries, elapsed);
|
|
63
|
-
if (allSettled(entries)) {
|
|
64
|
-
return { entries, hadError: entries.some((e) => isAwaited(e) && e.status === 'error'), timedOut: false };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
// A transient status read failure is non-fatal — keep polling until the
|
|
69
|
-
// overall timeout. (Mirrors the frontend poller's tolerate-with-cap.) We
|
|
70
|
-
// don't surface each blip; the timeout is the real failure signal.
|
|
71
|
-
consecutiveErrors++;
|
|
72
|
-
}
|
|
73
|
-
if (Date.now() - start + pollIntervalMs > timeoutMs) {
|
|
74
|
-
// Out of budget. Report whatever we last saw as timed out.
|
|
75
|
-
return {
|
|
76
|
-
entries,
|
|
77
|
-
hadError: entries.some((e) => isAwaited(e) && e.status === 'error'),
|
|
78
|
-
timedOut: true,
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
await sleep(pollIntervalMs);
|
|
82
|
-
}
|
|
83
|
-
}
|