@xano/cli 1.0.2-beta.6 → 1.0.2-beta.8
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 +2 -0
- package/dist/commands/sandbox/review/index.d.ts +1 -0
- package/dist/commands/sandbox/review/index.js +11 -0
- package/dist/utils/multidoc-push.d.ts +25 -0
- package/dist/utils/multidoc-push.js +39 -18
- package/oclif.manifest.json +2404 -2386
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -505,6 +505,8 @@ xano sandbox push --review # Push and open sandbox
|
|
|
505
505
|
|
|
506
506
|
# Review (open in browser)
|
|
507
507
|
xano sandbox review
|
|
508
|
+
xano sandbox review --url-only # Print the URL without opening the browser
|
|
509
|
+
xano sandbox review --insecure # Skip TLS verification (self-signed certs)
|
|
508
510
|
|
|
509
511
|
# Impersonate (open in browser)
|
|
510
512
|
xano sandbox impersonate
|
|
@@ -3,6 +3,7 @@ export default class SandboxReview extends BaseCommand {
|
|
|
3
3
|
static description: string;
|
|
4
4
|
static examples: string[];
|
|
5
5
|
static flags: {
|
|
6
|
+
insecure: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
6
7
|
output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
7
8
|
'url-only': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
8
9
|
config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
@@ -10,9 +10,16 @@ Review session started!
|
|
|
10
10
|
`,
|
|
11
11
|
`$ xano sandbox review -u`,
|
|
12
12
|
`$ xano sandbox review -o json`,
|
|
13
|
+
`$ xano sandbox review --insecure`,
|
|
13
14
|
];
|
|
14
15
|
static flags = {
|
|
15
16
|
...BaseCommand.baseFlags,
|
|
17
|
+
insecure: Flags.boolean({
|
|
18
|
+
char: 'k',
|
|
19
|
+
default: false,
|
|
20
|
+
description: 'Skip TLS certificate verification (for self-signed certificates)',
|
|
21
|
+
required: false,
|
|
22
|
+
}),
|
|
16
23
|
output: Flags.string({
|
|
17
24
|
char: 'o',
|
|
18
25
|
default: 'summary',
|
|
@@ -29,6 +36,10 @@ Review session started!
|
|
|
29
36
|
};
|
|
30
37
|
async run() {
|
|
31
38
|
const { flags } = await this.parse(SandboxReview);
|
|
39
|
+
if (flags.insecure) {
|
|
40
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';
|
|
41
|
+
this.warn('TLS certificate verification is disabled (insecure mode)');
|
|
42
|
+
}
|
|
32
43
|
const { profile } = this.resolveProfile(flags);
|
|
33
44
|
const apiUrl = `${profile.instance_origin}/api:meta/sandbox/impersonate`;
|
|
34
45
|
try {
|
|
@@ -54,6 +54,31 @@ export declare function countSummaryChanges(summary: Record<string, {
|
|
|
54
54
|
truncated: number;
|
|
55
55
|
updated: number;
|
|
56
56
|
}>, shouldDelete: boolean): number;
|
|
57
|
+
/**
|
|
58
|
+
* Filter document entries down to the ones the dry-run preview reports as changed,
|
|
59
|
+
* used to send only the changed documents during a partial (non-`--sync`) push.
|
|
60
|
+
*
|
|
61
|
+
* The preview keys each operation as `${type}:${name}` (with the verb appended for
|
|
62
|
+
* API endpoints). Local documents are matched against that set.
|
|
63
|
+
*
|
|
64
|
+
* Triggers need special handling: they are authored with specific subtypes
|
|
65
|
+
* (workspace_trigger, error_trigger, table_trigger, agent_trigger,
|
|
66
|
+
* mcp_server_trigger, realtime_trigger) but the server buckets every one under the
|
|
67
|
+
* generic `trigger` type in the preview. We therefore match a local trigger against
|
|
68
|
+
* both its specific type and the generic `trigger` type — otherwise partial pushes
|
|
69
|
+
* silently drop triggers, requiring `--sync --force` to include them (DEV-7084).
|
|
70
|
+
*/
|
|
71
|
+
export declare function filterChangedEntries(entries: Array<{
|
|
72
|
+
content: string;
|
|
73
|
+
filePath: string;
|
|
74
|
+
}>, operations: Array<{
|
|
75
|
+
action: string;
|
|
76
|
+
name: string;
|
|
77
|
+
type: string;
|
|
78
|
+
}>, includeRecords: boolean): Array<{
|
|
79
|
+
content: string;
|
|
80
|
+
filePath: string;
|
|
81
|
+
}>;
|
|
57
82
|
/**
|
|
58
83
|
* Recursively collect all .xs files from a directory, sorted for deterministic ordering.
|
|
59
84
|
*/
|
|
@@ -14,6 +14,44 @@ export const WORKSPACE_MISMATCH_THRESHOLD = 10;
|
|
|
14
14
|
export function countSummaryChanges(summary, shouldDelete) {
|
|
15
15
|
return Object.values(summary).reduce((sum, c) => sum + c.created + c.updated + (shouldDelete ? c.deleted : 0) + c.truncated, 0);
|
|
16
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* Filter document entries down to the ones the dry-run preview reports as changed,
|
|
19
|
+
* used to send only the changed documents during a partial (non-`--sync`) push.
|
|
20
|
+
*
|
|
21
|
+
* The preview keys each operation as `${type}:${name}` (with the verb appended for
|
|
22
|
+
* API endpoints). Local documents are matched against that set.
|
|
23
|
+
*
|
|
24
|
+
* Triggers need special handling: they are authored with specific subtypes
|
|
25
|
+
* (workspace_trigger, error_trigger, table_trigger, agent_trigger,
|
|
26
|
+
* mcp_server_trigger, realtime_trigger) but the server buckets every one under the
|
|
27
|
+
* generic `trigger` type in the preview. We therefore match a local trigger against
|
|
28
|
+
* both its specific type and the generic `trigger` type — otherwise partial pushes
|
|
29
|
+
* silently drop triggers, requiring `--sync --force` to include them (DEV-7084).
|
|
30
|
+
*/
|
|
31
|
+
export function filterChangedEntries(entries, operations, includeRecords) {
|
|
32
|
+
const changedKeys = new Set(operations
|
|
33
|
+
.filter((op) => op.action !== 'unchanged' && op.action !== 'delete' && op.action !== 'cascade_delete')
|
|
34
|
+
.map((op) => `${op.type}:${op.name}`));
|
|
35
|
+
return entries.filter((entry) => {
|
|
36
|
+
const parsed = parseDocument(entry.content);
|
|
37
|
+
if (!parsed)
|
|
38
|
+
return true;
|
|
39
|
+
// Workspace settings always use a fixed key in dry-run regardless of the actual name
|
|
40
|
+
if (parsed.type === 'workspace' && changedKeys.has('workspace:workspace'))
|
|
41
|
+
return true;
|
|
42
|
+
const opName = parsed.verb ? `${parsed.name} ${parsed.verb}` : parsed.name;
|
|
43
|
+
if (changedKeys.has(`${parsed.type}:${opName}`))
|
|
44
|
+
return true;
|
|
45
|
+
// The dry-run preview reports all trigger subtypes under the generic `trigger`
|
|
46
|
+
// type, so match triggers against that bucket too (DEV-7084).
|
|
47
|
+
if (parsed.type.endsWith('_trigger') && changedKeys.has(`trigger:${opName}`))
|
|
48
|
+
return true;
|
|
49
|
+
// Keep table documents that contain records when --records is active
|
|
50
|
+
if (includeRecords && parsed.type === 'table' && /\bitems\s*=\s*\[/m.test(entry.content))
|
|
51
|
+
return true;
|
|
52
|
+
return false;
|
|
53
|
+
});
|
|
54
|
+
}
|
|
17
55
|
// ── File Collection ─────────────────────────────────────────────────────────
|
|
18
56
|
/**
|
|
19
57
|
* Recursively collect all .xs files from a directory, sorted for deterministic ordering.
|
|
@@ -520,24 +558,7 @@ export async function executePush(ctx, target, flags) {
|
|
|
520
558
|
}
|
|
521
559
|
// ── Partial push: filter to changed documents only ────────────────────
|
|
522
560
|
if (isPartial && dryRunPreview) {
|
|
523
|
-
const
|
|
524
|
-
.filter((op) => op.action !== 'unchanged' && op.action !== 'delete' && op.action !== 'cascade_delete')
|
|
525
|
-
.map((op) => `${op.type}:${op.name}`));
|
|
526
|
-
const filteredEntries = documentEntries.filter((entry) => {
|
|
527
|
-
const parsed = parseDocument(entry.content);
|
|
528
|
-
if (!parsed)
|
|
529
|
-
return true;
|
|
530
|
-
// Workspace settings always use a fixed key in dry-run regardless of the actual name
|
|
531
|
-
if (parsed.type === 'workspace' && changedKeys.has('workspace:workspace'))
|
|
532
|
-
return true;
|
|
533
|
-
const opName = parsed.verb ? `${parsed.name} ${parsed.verb}` : parsed.name;
|
|
534
|
-
if (changedKeys.has(`${parsed.type}:${opName}`))
|
|
535
|
-
return true;
|
|
536
|
-
// Keep table documents that contain records when --records is active
|
|
537
|
-
if (flags.records && parsed.type === 'table' && /\bitems\s*=\s*\[/m.test(entry.content))
|
|
538
|
-
return true;
|
|
539
|
-
return false;
|
|
540
|
-
});
|
|
561
|
+
const filteredEntries = filterChangedEntries(documentEntries, dryRunPreview.operations, flags.records);
|
|
541
562
|
if (filteredEntries.length === 0) {
|
|
542
563
|
log('No changes to push.');
|
|
543
564
|
return;
|