@xano/cli 1.2.0 → 1.3.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.
Files changed (116) hide show
  1. package/README.md +112 -3
  2. package/dist/base-command.d.ts +43 -36
  3. package/dist/base-command.js +223 -160
  4. package/dist/commands/auth/index.d.ts +1 -1
  5. package/dist/commands/auth/index.js +7 -7
  6. package/dist/commands/branch/create/index.d.ts +1 -1
  7. package/dist/commands/branch/create/index.js +1 -1
  8. package/dist/commands/ephemeral/create/index.d.ts +18 -0
  9. package/dist/commands/ephemeral/create/index.js +103 -0
  10. package/dist/commands/ephemeral/delete/index.d.ts +18 -0
  11. package/dist/commands/ephemeral/delete/index.js +99 -0
  12. package/dist/commands/ephemeral/edit/index.d.ts +18 -0
  13. package/dist/commands/ephemeral/edit/index.js +109 -0
  14. package/dist/commands/ephemeral/get/index.d.ts +21 -0
  15. package/dist/commands/ephemeral/get/index.js +125 -0
  16. package/dist/commands/ephemeral/impersonate/index.d.ts +20 -0
  17. package/dist/commands/ephemeral/impersonate/index.js +120 -0
  18. package/dist/commands/ephemeral/list/index.d.ts +19 -0
  19. package/dist/commands/ephemeral/list/index.js +123 -0
  20. package/dist/commands/ephemeral/pull/index.d.ts +19 -0
  21. package/dist/commands/ephemeral/pull/index.js +163 -0
  22. package/dist/commands/ephemeral/push/index.d.ts +35 -0
  23. package/dist/commands/ephemeral/push/index.js +223 -0
  24. package/dist/commands/ephemeral/static_host/build/delete/index.d.ts +20 -0
  25. package/dist/commands/ephemeral/static_host/build/delete/index.js +121 -0
  26. package/dist/commands/ephemeral/static_host/build/get/index.d.ts +18 -0
  27. package/dist/commands/ephemeral/static_host/build/get/index.js +137 -0
  28. package/dist/commands/ephemeral/static_host/build/list/index.d.ts +18 -0
  29. package/dist/commands/ephemeral/static_host/build/list/index.js +137 -0
  30. package/dist/commands/ephemeral/static_host/build/pull/index.d.ts +53 -0
  31. package/dist/commands/ephemeral/static_host/build/pull/index.js +308 -0
  32. package/dist/commands/ephemeral/static_host/build/push/index.d.ts +24 -0
  33. package/dist/commands/ephemeral/static_host/build/push/index.js +250 -0
  34. package/dist/commands/ephemeral/static_host/create/index.d.ts +18 -0
  35. package/dist/commands/ephemeral/static_host/create/index.js +92 -0
  36. package/dist/commands/ephemeral/static_host/deploy/index.d.ts +19 -0
  37. package/dist/commands/ephemeral/static_host/deploy/index.js +112 -0
  38. package/dist/commands/ephemeral/static_host/edit/index.d.ts +24 -0
  39. package/dist/commands/ephemeral/static_host/edit/index.js +158 -0
  40. package/dist/commands/ephemeral/static_host/get/index.d.ts +19 -0
  41. package/dist/commands/ephemeral/static_host/get/index.js +101 -0
  42. package/dist/commands/ephemeral/static_host/list/index.d.ts +17 -0
  43. package/dist/commands/ephemeral/static_host/list/index.js +132 -0
  44. package/dist/commands/flatten/index.d.ts +34 -0
  45. package/dist/commands/flatten/index.js +140 -0
  46. package/dist/commands/function/create/index.js +1 -1
  47. package/dist/commands/function/edit/index.js +26 -32
  48. package/dist/commands/function/get/index.js +2 -3
  49. package/dist/commands/function/run/index.d.ts +1 -0
  50. package/dist/commands/function/run/index.js +19 -6
  51. package/dist/commands/profile/create/index.d.ts +1 -1
  52. package/dist/commands/profile/create/index.js +7 -7
  53. package/dist/commands/profile/me/index.js +1 -1
  54. package/dist/commands/profile/use/index.js +0 -4
  55. package/dist/commands/profile/wizard/index.d.ts +1 -1
  56. package/dist/commands/profile/wizard/index.js +12 -10
  57. package/dist/commands/profile/workspace/set/index.js +1 -1
  58. package/dist/commands/release/edit/index.js +2 -2
  59. package/dist/commands/release/export/index.js +1 -2
  60. package/dist/commands/release/import/index.js +1 -1
  61. package/dist/commands/release/pull/index.d.ts +0 -6
  62. package/dist/commands/release/pull/index.js +13 -99
  63. package/dist/commands/release/push/index.js +2 -2
  64. package/dist/commands/sandbox/env/get_all/index.js +1 -1
  65. package/dist/commands/sandbox/env/set_all/index.js +1 -1
  66. package/dist/commands/sandbox/get/index.js +1 -1
  67. package/dist/commands/sandbox/license/get/index.js +1 -1
  68. package/dist/commands/sandbox/license/set/index.js +1 -1
  69. package/dist/commands/sandbox/pull/index.d.ts +0 -1
  70. package/dist/commands/sandbox/pull/index.js +13 -81
  71. package/dist/commands/sandbox/push/index.d.ts +1 -1
  72. package/dist/commands/sandbox/push/index.js +5 -5
  73. package/dist/commands/static_host/build/create/index.d.ts +1 -1
  74. package/dist/commands/static_host/build/create/index.js +2 -2
  75. package/dist/commands/static_host/build/pull/index.js +1 -1
  76. package/dist/commands/static_host/build/push/index.js +1 -1
  77. package/dist/commands/static_host/edit/index.js +1 -1
  78. package/dist/commands/tenant/backup/export/index.js +1 -2
  79. package/dist/commands/tenant/backup/import/index.js +1 -1
  80. package/dist/commands/tenant/cluster/create/index.js +1 -1
  81. package/dist/commands/tenant/cluster/license/get/index.js +1 -1
  82. package/dist/commands/tenant/cluster/license/set/index.js +1 -1
  83. package/dist/commands/tenant/create/index.d.ts +1 -1
  84. package/dist/commands/tenant/create/index.js +6 -6
  85. package/dist/commands/tenant/deploy_platform/index.js +1 -1
  86. package/dist/commands/tenant/edit/index.js +7 -7
  87. package/dist/commands/tenant/env/get_all/index.js +1 -1
  88. package/dist/commands/tenant/env/set_all/index.js +1 -1
  89. package/dist/commands/tenant/impersonate/index.d.ts +1 -1
  90. package/dist/commands/tenant/impersonate/index.js +14 -14
  91. package/dist/commands/tenant/license/get/index.js +1 -1
  92. package/dist/commands/tenant/license/set/index.js +1 -1
  93. package/dist/commands/tenant/pull/index.d.ts +0 -6
  94. package/dist/commands/tenant/pull/index.js +14 -100
  95. package/dist/commands/workspace/git/pull/index.d.ts +4 -4
  96. package/dist/commands/workspace/git/pull/index.js +158 -97
  97. package/dist/commands/workspace/pull/index.d.ts +1 -7
  98. package/dist/commands/workspace/pull/index.js +17 -103
  99. package/dist/help.js +4 -2
  100. package/dist/update-check.d.ts +1 -1
  101. package/dist/update-check.js +1 -1
  102. package/dist/utils/document-parser.d.ts +116 -0
  103. package/dist/utils/document-parser.js +311 -4
  104. package/dist/utils/flatten.d.ts +36 -0
  105. package/dist/utils/flatten.js +68 -0
  106. package/dist/utils/knowledge-sync.d.ts +1 -0
  107. package/dist/utils/knowledge-sync.js +11 -6
  108. package/dist/utils/microservice-wait.d.ts +53 -0
  109. package/dist/utils/microservice-wait.js +84 -0
  110. package/dist/utils/multidoc-push.d.ts +88 -0
  111. package/dist/utils/multidoc-push.js +378 -15
  112. package/dist/utils/paging.d.ts +2 -1
  113. package/dist/utils/paging.js +0 -1
  114. package/dist/utils/reference-checker.js +14 -3
  115. package/oclif.manifest.json +5264 -3170
  116. package/package.json +10 -1
@@ -61,9 +61,9 @@ Workspace updated to 'Production API' (xyz789) on profile 'production'
61
61
  async fetchWorkspaces(accessToken, origin) {
62
62
  const response = await fetch(`${origin}/api:meta/workspace`, {
63
63
  headers: {
64
- 'User-Agent': buildUserAgent(this.config.version),
65
64
  accept: 'application/json',
66
65
  Authorization: `Bearer ${accessToken}`,
66
+ 'User-Agent': buildUserAgent(this.config.version),
67
67
  },
68
68
  method: 'GET',
69
69
  });
@@ -69,8 +69,8 @@ Updated release: v1.0-final - ID: 10
69
69
  const current = await getResponse.json();
70
70
  // Merge in user-provided values
71
71
  const body = {
72
- description: flags.description !== undefined ? flags.description : (current.description ?? ''),
73
- name: flags.name !== undefined ? flags.name : current.name,
72
+ description: flags.description === undefined ? (current.description ?? '') : flags.description,
73
+ name: flags.name === undefined ? current.name : flags.name,
74
74
  };
75
75
  // Update release
76
76
  const putResponse = await this.verboseFetch(baseUrl, {
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand, { buildUserAgent } from '../../../base-command.js';
5
5
  export default class ReleaseExport extends BaseCommand {
6
6
  static args = {
@@ -79,7 +79,6 @@ Downloaded release 'v1.0' to ./release-v1.0.tar.gz
79
79
  const fileStream = fs.createWriteStream(resolvedPath);
80
80
  const reader = downloadResponse.body.getReader();
81
81
  let totalBytes = 0;
82
- // eslint-disable-next-line no-constant-condition
83
82
  while (true) {
84
83
  // eslint-disable-next-line no-await-in-loop
85
84
  const { done, value } = await reader.read();
@@ -1,6 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../base-command.js';
5
5
  export default class ReleaseImport extends BaseCommand {
6
6
  static args = {};
@@ -14,10 +14,4 @@ export default class ReleasePull extends BaseCommand {
14
14
  };
15
15
  run(): Promise<void>;
16
16
  private resolveReleaseName;
17
- /**
18
- * Sanitize a document name for use as a filename.
19
- * Strips quotes, replaces spaces with underscores, and removes
20
- * characters that are unsafe in filenames.
21
- */
22
- private sanitizeFilename;
23
17
  }
@@ -1,9 +1,9 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as fs from 'node:fs';
3
- import * as path from 'node:path';
4
2
  import snakeCase from 'lodash.snakecase';
3
+ import * as fs from 'node:fs';
4
+ import path from 'node:path';
5
5
  import BaseCommand from '../../../base-command.js';
6
- import { buildApiGroupFolderResolver, parseDocument } from '../../../utils/document-parser.js';
6
+ import { buildApiGroupFolderResolver, buildChannelServerResolver, parseDocument, resolveDocumentPath, } from '../../../utils/document-parser.js';
7
7
  export default class ReleasePull extends BaseCommand {
8
8
  static description = 'Pull a release multidoc from the Xano Metadata API and split into individual files';
9
9
  static examples = [
@@ -123,96 +123,19 @@ Pulled 58 documents from release 'v1.0'
123
123
  fs.mkdirSync(outputDir, { recursive: true });
124
124
  // Resolve api_group names to unique folder names, disambiguating collisions
125
125
  const getApiGroupFolder = buildApiGroupFolderResolver(documents, snakeCase);
126
+ // Resolve a realtime v2 channel path -> owning realtime_server name, so
127
+ // messages can nest under their channel's server (see resolver docs).
128
+ const getChannelServer = buildChannelServerResolver(documents);
126
129
  // Track filenames per type to handle duplicates
127
130
  const filenameCounters = new Map();
128
131
  let writtenCount = 0;
129
132
  for (const doc of documents) {
130
- let typeDir;
131
- let baseName;
132
- if (doc.type === 'workspace') {
133
- // workspace → workspace/{name}.xs
134
- typeDir = path.join(outputDir, 'workspace');
135
- baseName = this.sanitizeFilename(doc.name);
136
- }
137
- else if (doc.type === 'workspace_trigger') {
138
- // workspace_trigger → workspace/trigger/{name}.xs
139
- typeDir = path.join(outputDir, 'workspace', 'trigger');
140
- baseName = this.sanitizeFilename(doc.name);
141
- }
142
- else if (doc.type === 'error_trigger') {
143
- // error_trigger → workspace/trigger/{name}.xs (singleton, colocated with workspace triggers)
144
- typeDir = path.join(outputDir, 'workspace', 'trigger');
145
- baseName = this.sanitizeFilename(doc.name);
146
- }
147
- else if (doc.type === 'agent') {
148
- // agent → ai/agent/{name}.xs
149
- typeDir = path.join(outputDir, 'ai', 'agent');
150
- baseName = this.sanitizeFilename(doc.name);
151
- }
152
- else if (doc.type === 'mcp_server') {
153
- // mcp_server → ai/mcp_server/{name}.xs
154
- typeDir = path.join(outputDir, 'ai', 'mcp_server');
155
- baseName = this.sanitizeFilename(doc.name);
156
- }
157
- else if (doc.type === 'tool') {
158
- // tool → ai/tool/{name}.xs
159
- typeDir = path.join(outputDir, 'ai', 'tool');
160
- baseName = this.sanitizeFilename(doc.name);
161
- }
162
- else if (doc.type === 'agent_trigger') {
163
- // agent_trigger → ai/agent/trigger/{name}.xs
164
- typeDir = path.join(outputDir, 'ai', 'agent', 'trigger');
165
- baseName = this.sanitizeFilename(doc.name);
166
- }
167
- else if (doc.type === 'mcp_server_trigger') {
168
- // mcp_server_trigger → ai/mcp_server/trigger/{name}.xs
169
- typeDir = path.join(outputDir, 'ai', 'mcp_server', 'trigger');
170
- baseName = this.sanitizeFilename(doc.name);
171
- }
172
- else if (doc.type === 'table_trigger') {
173
- // table_trigger → table/trigger/{name}.xs
174
- typeDir = path.join(outputDir, 'table', 'trigger');
175
- baseName = this.sanitizeFilename(doc.name);
176
- }
177
- else if (doc.type === 'realtime_channel') {
178
- // realtime_channel → realtime/channel/{name}.xs
179
- typeDir = path.join(outputDir, 'realtime', 'channel');
180
- baseName = this.sanitizeFilename(doc.name);
181
- }
182
- else if (doc.type === 'realtime_trigger') {
183
- // realtime_trigger → realtime/trigger/{name}.xs
184
- typeDir = path.join(outputDir, 'realtime', 'trigger');
185
- baseName = this.sanitizeFilename(doc.name);
186
- }
187
- else if (doc.type === 'api_group') {
188
- // api_group "test" → api/{resolved_folder}/{name}.xs
189
- const groupFolder = getApiGroupFolder(doc.name);
190
- typeDir = path.join(outputDir, 'api', groupFolder);
191
- baseName = this.sanitizeFilename(doc.name);
192
- }
193
- else if (doc.type === 'query' && doc.apiGroup) {
194
- // query in group "test" → api/{resolved_folder}/{query_name}.xs
195
- const groupFolder = getApiGroupFolder(doc.apiGroup);
196
- const nameParts = doc.name.split('/');
197
- const leafName = nameParts.pop();
198
- const folderParts = nameParts.map((part) => snakeCase(part));
199
- typeDir = path.join(outputDir, 'api', groupFolder, ...folderParts);
200
- baseName = this.sanitizeFilename(leafName);
201
- if (doc.verb) {
202
- baseName = `${baseName}_${doc.verb}`;
203
- }
204
- }
205
- else {
206
- // Default: split folder path from name
207
- const nameParts = doc.name.split('/');
208
- const leafName = nameParts.pop();
209
- const folderParts = nameParts.map((part) => snakeCase(part));
210
- typeDir = path.join(outputDir, doc.type, ...folderParts);
211
- baseName = this.sanitizeFilename(leafName);
212
- if (doc.verb) {
213
- baseName = `${baseName}_${doc.verb}`;
214
- }
215
- }
133
+ const { baseName, typeDir } = resolveDocumentPath(doc, outputDir, {
134
+ getApiGroupFolder,
135
+ getChannelServer,
136
+ join: path.join,
137
+ snakeCase,
138
+ });
216
139
  fs.mkdirSync(typeDir, { recursive: true });
217
140
  // Track duplicates per directory
218
141
  const dirKey = path.relative(outputDir, typeDir);
@@ -223,8 +146,7 @@ Pulled 58 documents from release 'v1.0'
223
146
  const count = typeCounters.get(baseName) || 0;
224
147
  typeCounters.set(baseName, count + 1);
225
148
  // Append numeric suffix for duplicates
226
- let filename;
227
- filename = count === 0 ? `${baseName}.xs` : `${baseName}_${count + 1}.xs`;
149
+ const filename = count === 0 ? `${baseName}.xs` : `${baseName}_${count + 1}.xs`;
228
150
  const filePath = path.join(typeDir, filename);
229
151
  fs.writeFileSync(filePath, doc.content, 'utf8');
230
152
  writtenCount++;
@@ -257,12 +179,4 @@ Pulled 58 documents from release 'v1.0'
257
179
  }
258
180
  return match.id;
259
181
  }
260
- /**
261
- * Sanitize a document name for use as a filename.
262
- * Strips quotes, replaces spaces with underscores, and removes
263
- * characters that are unsafe in filenames.
264
- */
265
- sanitizeFilename(name) {
266
- return snakeCase(name.replaceAll('"', ''));
267
- }
268
182
  }
@@ -1,6 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../base-command.js';
5
5
  import { findFilesWithGuid } from '../../../utils/document-parser.js';
6
6
  export default class ReleasePush extends BaseCommand {
@@ -72,7 +72,7 @@ Output release details as JSON
72
72
  };
73
73
  async run() {
74
74
  const { flags } = await this.parse(ReleasePush);
75
- const { profileName, profile } = this.resolveProfile(flags);
75
+ const { profile, profileName } = this.resolveProfile(flags);
76
76
  // Determine workspace_id from flag or profile
77
77
  let workspaceId;
78
78
  if (flags.workspace) {
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
- import * as path from 'node:path';
4
+ import path from 'node:path';
5
5
  import BaseCommand from '../../../../base-command.js';
6
6
  export default class SandboxEnvGetAll extends BaseCommand {
7
7
  static description = 'Get all environment variables for a sandbox environment and save to a YAML file';
@@ -1,7 +1,7 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
- import * as path from 'node:path';
4
+ import path from 'node:path';
5
5
  import BaseCommand from '../../../../base-command.js';
6
6
  export default class SandboxEnvSetAll extends BaseCommand {
7
7
  static description = '[CRITICAL] STOP and confirm with the user; this replaces all environment variables with the imported file. Sets all environment variables for a sandbox environment from a YAML file.';
@@ -36,7 +36,7 @@ Sandbox Environment: (tc24-abcd-x1y2)
36
36
  this.log(` Domain: ${tenant.xano_domain}`);
37
37
  if (tenant.sandbox_expires_at) {
38
38
  const expiresAt = new Date(tenant.sandbox_expires_at);
39
- if (!isNaN(expiresAt.getTime())) {
39
+ if (!Number.isNaN(expiresAt.getTime())) {
40
40
  const msLeft = expiresAt.getTime() - Date.now();
41
41
  if (msLeft > 0) {
42
42
  const minsLeft = Math.ceil(msLeft / 60_000);
@@ -1,6 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  export default class SandboxLicenseGet extends BaseCommand {
6
6
  static description = 'Get the license for a sandbox environment';
@@ -1,6 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  export default class SandboxLicenseSet extends BaseCommand {
6
6
  static description = 'Set/update the license for a sandbox environment';
@@ -12,5 +12,4 @@ export default class SandboxPull extends BaseCommand {
12
12
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
13
13
  };
14
14
  run(): Promise<void>;
15
- private sanitizeFilename;
16
15
  }
@@ -1,10 +1,10 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import snakeCase from 'lodash.snakecase';
3
+ import * as fs from 'node:fs';
4
+ import path from 'node:path';
3
5
  import BaseCommand from '../../../base-command.js';
4
- import { buildApiGroupFolderResolver, parseDocument } from '../../../utils/document-parser.js';
6
+ import { buildApiGroupFolderResolver, buildChannelServerResolver, parseDocument, resolveDocumentPath, } from '../../../utils/document-parser.js';
5
7
  import { fetchKnowledge, writeKnowledge } from '../../../utils/knowledge-sync.js';
6
- import * as fs from 'node:fs';
7
- import * as path from 'node:path';
8
8
  export default class SandboxPull extends BaseCommand {
9
9
  static description = 'Pull documents from your sandbox environment and split into individual files';
10
10
  static examples = [
@@ -92,82 +92,18 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
92
92
  const outputDir = path.resolve(flags.directory);
93
93
  fs.mkdirSync(outputDir, { recursive: true });
94
94
  const getApiGroupFolder = buildApiGroupFolderResolver(documents, snakeCase);
95
+ // Resolve a realtime v2 channel path -> owning realtime_server name, so
96
+ // messages can nest under their channel's server (see resolver docs).
97
+ const getChannelServer = buildChannelServerResolver(documents);
95
98
  const filenameCounters = new Map();
96
99
  let writtenCount = 0;
97
100
  for (const doc of documents) {
98
- let typeDir;
99
- let baseName;
100
- if (doc.type === 'workspace') {
101
- typeDir = path.join(outputDir, 'workspace');
102
- baseName = this.sanitizeFilename(doc.name);
103
- }
104
- else if (doc.type === 'workspace_trigger') {
105
- typeDir = path.join(outputDir, 'workspace', 'trigger');
106
- baseName = this.sanitizeFilename(doc.name);
107
- }
108
- else if (doc.type === 'error_trigger') {
109
- // error_trigger → workspace/trigger/{name}.xs (singleton, colocated with workspace triggers)
110
- typeDir = path.join(outputDir, 'workspace', 'trigger');
111
- baseName = this.sanitizeFilename(doc.name);
112
- }
113
- else if (doc.type === 'agent') {
114
- typeDir = path.join(outputDir, 'ai', 'agent');
115
- baseName = this.sanitizeFilename(doc.name);
116
- }
117
- else if (doc.type === 'mcp_server') {
118
- typeDir = path.join(outputDir, 'ai', 'mcp_server');
119
- baseName = this.sanitizeFilename(doc.name);
120
- }
121
- else if (doc.type === 'tool') {
122
- typeDir = path.join(outputDir, 'ai', 'tool');
123
- baseName = this.sanitizeFilename(doc.name);
124
- }
125
- else if (doc.type === 'agent_trigger') {
126
- typeDir = path.join(outputDir, 'ai', 'agent', 'trigger');
127
- baseName = this.sanitizeFilename(doc.name);
128
- }
129
- else if (doc.type === 'mcp_server_trigger') {
130
- typeDir = path.join(outputDir, 'ai', 'mcp_server', 'trigger');
131
- baseName = this.sanitizeFilename(doc.name);
132
- }
133
- else if (doc.type === 'table_trigger') {
134
- typeDir = path.join(outputDir, 'table', 'trigger');
135
- baseName = this.sanitizeFilename(doc.name);
136
- }
137
- else if (doc.type === 'realtime_channel') {
138
- typeDir = path.join(outputDir, 'realtime', 'channel');
139
- baseName = this.sanitizeFilename(doc.name);
140
- }
141
- else if (doc.type === 'realtime_trigger') {
142
- typeDir = path.join(outputDir, 'realtime', 'trigger');
143
- baseName = this.sanitizeFilename(doc.name);
144
- }
145
- else if (doc.type === 'api_group') {
146
- const groupFolder = getApiGroupFolder(doc.name);
147
- typeDir = path.join(outputDir, 'api', groupFolder);
148
- baseName = this.sanitizeFilename(doc.name);
149
- }
150
- else if (doc.type === 'query' && doc.apiGroup) {
151
- const groupFolder = getApiGroupFolder(doc.apiGroup);
152
- const nameParts = doc.name.split('/');
153
- const leafName = nameParts.pop();
154
- const folderParts = nameParts.map((part) => snakeCase(part));
155
- typeDir = path.join(outputDir, 'api', groupFolder, ...folderParts);
156
- baseName = this.sanitizeFilename(leafName);
157
- if (doc.verb) {
158
- baseName = `${baseName}_${doc.verb}`;
159
- }
160
- }
161
- else {
162
- const nameParts = doc.name.split('/');
163
- const leafName = nameParts.pop();
164
- const folderParts = nameParts.map((part) => snakeCase(part));
165
- typeDir = path.join(outputDir, doc.type, ...folderParts);
166
- baseName = this.sanitizeFilename(leafName);
167
- if (doc.verb) {
168
- baseName = `${baseName}_${doc.verb}`;
169
- }
170
- }
101
+ const { baseName, typeDir } = resolveDocumentPath(doc, outputDir, {
102
+ getApiGroupFolder,
103
+ getChannelServer,
104
+ join: path.join,
105
+ snakeCase,
106
+ });
171
107
  fs.mkdirSync(typeDir, { recursive: true });
172
108
  const dirKey = path.relative(outputDir, typeDir);
173
109
  if (!filenameCounters.has(dirKey)) {
@@ -176,8 +112,7 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
176
112
  const typeCounters = filenameCounters.get(dirKey);
177
113
  const count = typeCounters.get(baseName) || 0;
178
114
  typeCounters.set(baseName, count + 1);
179
- let filename;
180
- filename = count === 0 ? `${baseName}.xs` : `${baseName}_${count + 1}.xs`;
115
+ const filename = count === 0 ? `${baseName}.xs` : `${baseName}_${count + 1}.xs`;
181
116
  const filePath = path.join(typeDir, filename);
182
117
  fs.writeFileSync(filePath, doc.content, 'utf8');
183
118
  writtenCount++;
@@ -194,7 +129,4 @@ Pulled 42 documents from sandbox environment to ./my-sandbox
194
129
  parts.push(`${knowledgeCount} knowledge file${knowledgeCount === 1 ? '' : 's'}`);
195
130
  this.log(`Pulled ${parts.join(' + ')} from sandbox environment to ${flags.directory}`);
196
131
  }
197
- sanitizeFilename(name) {
198
- return snakeCase(name.replaceAll('"', ''));
199
- }
200
132
  }
@@ -3,8 +3,8 @@ export default class SandboxPush extends BaseCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
5
  static flags: {
6
- directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
6
  delete: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
8
  'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
9
9
  env: import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
10
  force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
@@ -33,17 +33,17 @@ Push and open sandbox review in the browser
33
33
  ];
34
34
  static flags = {
35
35
  ...BaseCommand.baseFlags,
36
+ delete: Flags.boolean({
37
+ default: false,
38
+ description: 'Delete sandbox objects not included in the push (requires --sync)',
39
+ required: false,
40
+ }),
36
41
  directory: Flags.string({
37
42
  char: 'd',
38
43
  default: '.',
39
44
  description: 'Directory containing documents to push (defaults to current directory)',
40
45
  required: false,
41
46
  }),
42
- delete: Flags.boolean({
43
- default: false,
44
- description: 'Delete sandbox objects not included in the push (requires --sync)',
45
- required: false,
46
- }),
47
47
  'dry-run': Flags.boolean({
48
48
  default: false,
49
49
  description: 'Show preview of changes without pushing (exit after preview)',
@@ -6,7 +6,6 @@ import BaseCommand from '../../../../base-command.js';
6
6
  */
7
7
  export declare function generateBuildName(date?: Date): string;
8
8
  export default class StaticHostBuildCreate extends BaseCommand {
9
- static hidden: boolean;
10
9
  static args: {
11
10
  static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
12
11
  };
@@ -23,5 +22,6 @@ export default class StaticHostBuildCreate extends BaseCommand {
23
22
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
24
23
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
25
24
  };
25
+ static hidden: boolean;
26
26
  run(): Promise<void>;
27
27
  }
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  const pad2 = (n) => String(n).padStart(2, '0');
6
6
  /**
@@ -18,7 +18,6 @@ export function generateBuildName(date = new Date()) {
18
18
  return `${y}${mo}${d}-${h}${mi}${s}`;
19
19
  }
20
20
  export default class StaticHostBuildCreate extends BaseCommand {
21
- static hidden = true;
22
21
  static args = {
23
22
  static_host: Args.string({
24
23
  description: 'Static Host name',
@@ -88,6 +87,7 @@ Description: Production build
88
87
  required: false,
89
88
  }),
90
89
  };
90
+ static hidden = true;
91
91
  async run() {
92
92
  this.warn('`static_host build create` is deprecated. Use `static_host build push -f <file>` instead.');
93
93
  const { args, flags } = await this.parse(StaticHostBuildCreate);
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  import { normalizeListResponse } from '../../../../utils/paging.js';
6
6
  /**
@@ -1,7 +1,7 @@
1
1
  import { Args, Flags, ux } from '@oclif/core';
2
2
  import archiver from 'archiver';
3
3
  import * as fs from 'node:fs';
4
- import * as path from 'node:path';
4
+ import path from 'node:path';
5
5
  import BaseCommand from '../../../../base-command.js';
6
6
  import { collectStaticHostFiles } from '../../../../utils/static-host-files.js';
7
7
  import { generateBuildName } from '../create/index.js';
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../base-command.js';
5
5
  export default class StaticHostEdit extends BaseCommand {
6
6
  static args = {
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand, { buildUserAgent } from '../../../../base-command.js';
5
5
  export default class TenantBackupExport extends BaseCommand {
6
6
  static args = {
@@ -82,7 +82,6 @@ Downloaded backup #10 to ./tenant-t1234-abcd-xyz1-backup-10.tar.gz
82
82
  const fileStream = fs.createWriteStream(resolvedPath);
83
83
  const reader = downloadResponse.body.getReader();
84
84
  let totalBytes = 0;
85
- // eslint-disable-next-line no-constant-condition
86
85
  while (true) {
87
86
  // eslint-disable-next-line no-await-in-loop
88
87
  const { done, value } = await reader.read();
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  export default class TenantBackupImport extends BaseCommand {
6
6
  static args = {
@@ -1,6 +1,6 @@
1
1
  import { Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
5
  export default class TenantClusterCreate extends BaseCommand {
6
6
  static description = 'Create a new tenant cluster';
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../../base-command.js';
5
5
  export default class TenantClusterLicenseGet extends BaseCommand {
6
6
  static args = {
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../../../base-command.js';
5
5
  export default class TenantClusterLicenseSet extends BaseCommand {
6
6
  static args = {
@@ -13,8 +13,8 @@ export default class TenantCreate extends BaseCommand {
13
13
  license: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
14
14
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
15
15
  platform_id: import("@oclif/core/interfaces").OptionFlag<number | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
- type: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
17
16
  tasks: import("@oclif/core/interfaces").BooleanFlag<boolean>;
17
+ type: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
18
18
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
19
  config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
20
20
  profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -1,7 +1,7 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as yaml from 'js-yaml';
3
3
  import * as fs from 'node:fs';
4
- import * as path from 'node:path';
4
+ import path from 'node:path';
5
5
  import BaseCommand from '../../../base-command.js';
6
6
  export default class TenantCreate extends BaseCommand {
7
7
  static args = {
@@ -54,17 +54,17 @@ Created tenant: Production (production) - ID: 42
54
54
  description: 'Platform ID to use',
55
55
  required: false,
56
56
  }),
57
+ tasks: Flags.boolean({
58
+ allowNo: true,
59
+ default: true,
60
+ description: 'Enable background tasks',
61
+ }),
57
62
  type: Flags.string({
58
63
  default: 'tier1',
59
64
  description: 'Tenant type',
60
65
  options: ['tier1', 'tier2', 'tier3'],
61
66
  required: false,
62
67
  }),
63
- tasks: Flags.boolean({
64
- allowNo: true,
65
- default: true,
66
- description: 'Enable background tasks',
67
- }),
68
68
  workspace: Flags.string({
69
69
  char: 'w',
70
70
  description: 'Workspace ID (uses profile workspace if not provided)',
@@ -1,6 +1,6 @@
1
1
  import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
- import * as path from 'node:path';
3
+ import path from 'node:path';
4
4
  import BaseCommand from '../../../base-command.js';
5
5
  export default class TenantDeployPlatform extends BaseCommand {
6
6
  static args = {
@@ -91,16 +91,16 @@ Updated tenant: New Name (my-tenant) - ID: 42
91
91
  const current = await getResponse.json();
92
92
  // Merge in user-provided values
93
93
  const body = {
94
- description: flags.description !== undefined ? flags.description : (current.description ?? ''),
95
- display: flags.display !== undefined ? flags.display : (current.display ?? current.name),
96
- domain: flags.domain !== undefined ? flags.domain : (current.domain ?? ''),
97
- ingress: flags.ingress !== undefined ? flags.ingress : (current.ingress ?? true),
98
- proxy: flags.proxy !== undefined ? flags.proxy : (current.proxy ?? ''),
94
+ description: flags.description === undefined ? (current.description ?? '') : flags.description,
95
+ display: flags.display === undefined ? (current.display ?? current.name) : flags.display,
96
+ domain: flags.domain === undefined ? (current.domain ?? '') : flags.domain,
97
+ ingress: flags.ingress === undefined ? (current.ingress ?? true) : flags.ingress,
98
+ proxy: flags.proxy === undefined ? (current.proxy ?? '') : flags.proxy,
99
99
  rbac: {
100
- enabled: flags.rbac !== undefined ? flags.rbac : (current.rbac?.enabled ?? false),
100
+ enabled: flags.rbac === undefined ? (current.rbac?.enabled ?? false) : flags.rbac,
101
101
  },
102
102
  tag: current.tag ?? [],
103
- tasks: flags.tasks !== undefined ? flags.tasks : (current.tasks ?? true),
103
+ tasks: flags.tasks === undefined ? (current.tasks ?? true) : flags.tasks,
104
104
  };
105
105
  // Update tenant
106
106
  const putResponse = await this.verboseFetch(baseUrl, {