@xano/cli 1.0.2-beta.4 → 1.0.2-beta.6

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 (155) hide show
  1. package/README.md +87 -0
  2. package/dist/base-command.d.ts +21 -1
  3. package/dist/base-command.js +92 -6
  4. package/dist/commands/branch/create/index.d.ts +0 -1
  5. package/dist/commands/branch/create/index.js +1 -38
  6. package/dist/commands/branch/delete/index.d.ts +0 -1
  7. package/dist/commands/branch/delete/index.js +1 -39
  8. package/dist/commands/branch/edit/index.d.ts +0 -1
  9. package/dist/commands/branch/edit/index.js +1 -39
  10. package/dist/commands/branch/get/index.d.ts +0 -1
  11. package/dist/commands/branch/get/index.js +1 -39
  12. package/dist/commands/branch/list/index.d.ts +0 -1
  13. package/dist/commands/branch/list/index.js +1 -39
  14. package/dist/commands/branch/set_live/index.d.ts +0 -1
  15. package/dist/commands/branch/set_live/index.js +1 -39
  16. package/dist/commands/function/create/index.d.ts +0 -1
  17. package/dist/commands/function/create/index.js +1 -38
  18. package/dist/commands/function/edit/index.d.ts +0 -1
  19. package/dist/commands/function/edit/index.js +1 -37
  20. package/dist/commands/function/get/index.d.ts +0 -1
  21. package/dist/commands/function/get/index.js +1 -38
  22. package/dist/commands/function/list/index.d.ts +0 -1
  23. package/dist/commands/function/list/index.js +1 -39
  24. package/dist/commands/platform/get/index.d.ts +0 -1
  25. package/dist/commands/platform/get/index.js +1 -33
  26. package/dist/commands/platform/list/index.d.ts +0 -1
  27. package/dist/commands/platform/list/index.js +1 -33
  28. package/dist/commands/profile/use/index.d.ts +33 -0
  29. package/dist/commands/profile/use/index.js +179 -0
  30. package/dist/commands/profile/wizard/index.js +8 -2
  31. package/dist/commands/release/create/index.d.ts +0 -1
  32. package/dist/commands/release/create/index.js +1 -33
  33. package/dist/commands/release/delete/index.d.ts +0 -1
  34. package/dist/commands/release/delete/index.js +1 -33
  35. package/dist/commands/release/deploy/index.js +1 -12
  36. package/dist/commands/release/edit/index.d.ts +0 -1
  37. package/dist/commands/release/edit/index.js +1 -33
  38. package/dist/commands/release/export/index.d.ts +0 -1
  39. package/dist/commands/release/export/index.js +1 -31
  40. package/dist/commands/release/get/index.d.ts +0 -1
  41. package/dist/commands/release/get/index.js +1 -33
  42. package/dist/commands/release/import/index.d.ts +0 -1
  43. package/dist/commands/release/import/index.js +1 -32
  44. package/dist/commands/release/list/index.d.ts +0 -1
  45. package/dist/commands/release/list/index.js +1 -32
  46. package/dist/commands/release/pull/index.d.ts +0 -1
  47. package/dist/commands/release/pull/index.js +2 -38
  48. package/dist/commands/release/push/index.d.ts +0 -1
  49. package/dist/commands/release/push/index.js +1 -37
  50. package/dist/commands/static_host/build/create/index.d.ts +0 -1
  51. package/dist/commands/static_host/build/create/index.js +1 -39
  52. package/dist/commands/static_host/build/get/index.d.ts +0 -1
  53. package/dist/commands/static_host/build/get/index.js +1 -39
  54. package/dist/commands/static_host/build/list/index.d.ts +0 -1
  55. package/dist/commands/static_host/build/list/index.js +1 -39
  56. package/dist/commands/static_host/list/index.d.ts +0 -1
  57. package/dist/commands/static_host/list/index.js +1 -39
  58. package/dist/commands/tenant/backup/create/index.d.ts +0 -1
  59. package/dist/commands/tenant/backup/create/index.js +1 -33
  60. package/dist/commands/tenant/backup/delete/index.d.ts +0 -1
  61. package/dist/commands/tenant/backup/delete/index.js +1 -32
  62. package/dist/commands/tenant/backup/export/index.d.ts +0 -1
  63. package/dist/commands/tenant/backup/export/index.js +1 -31
  64. package/dist/commands/tenant/backup/import/index.d.ts +0 -1
  65. package/dist/commands/tenant/backup/import/index.js +1 -32
  66. package/dist/commands/tenant/backup/list/index.d.ts +0 -1
  67. package/dist/commands/tenant/backup/list/index.js +1 -33
  68. package/dist/commands/tenant/backup/restore/index.d.ts +0 -1
  69. package/dist/commands/tenant/backup/restore/index.js +1 -32
  70. package/dist/commands/tenant/cluster/create/index.d.ts +0 -1
  71. package/dist/commands/tenant/cluster/create/index.js +1 -31
  72. package/dist/commands/tenant/cluster/delete/index.d.ts +0 -1
  73. package/dist/commands/tenant/cluster/delete/index.js +1 -33
  74. package/dist/commands/tenant/cluster/edit/index.d.ts +0 -1
  75. package/dist/commands/tenant/cluster/edit/index.js +1 -33
  76. package/dist/commands/tenant/cluster/get/index.d.ts +0 -1
  77. package/dist/commands/tenant/cluster/get/index.js +1 -32
  78. package/dist/commands/tenant/cluster/license/get/index.d.ts +0 -1
  79. package/dist/commands/tenant/cluster/license/get/index.js +1 -31
  80. package/dist/commands/tenant/cluster/license/set/index.d.ts +0 -1
  81. package/dist/commands/tenant/cluster/license/set/index.js +1 -31
  82. package/dist/commands/tenant/cluster/list/index.d.ts +0 -1
  83. package/dist/commands/tenant/cluster/list/index.js +1 -32
  84. package/dist/commands/tenant/create/index.d.ts +0 -1
  85. package/dist/commands/tenant/create/index.js +1 -30
  86. package/dist/commands/tenant/delete/index.d.ts +0 -1
  87. package/dist/commands/tenant/delete/index.js +1 -33
  88. package/dist/commands/tenant/deploy_platform/index.d.ts +0 -1
  89. package/dist/commands/tenant/deploy_platform/index.js +1 -31
  90. package/dist/commands/tenant/deploy_release/index.d.ts +0 -1
  91. package/dist/commands/tenant/deploy_release/index.js +1 -32
  92. package/dist/commands/tenant/edit/index.d.ts +0 -1
  93. package/dist/commands/tenant/edit/index.js +1 -33
  94. package/dist/commands/tenant/env/delete/index.d.ts +0 -1
  95. package/dist/commands/tenant/env/delete/index.js +1 -32
  96. package/dist/commands/tenant/env/get/index.d.ts +0 -1
  97. package/dist/commands/tenant/env/get/index.js +1 -32
  98. package/dist/commands/tenant/env/get_all/index.d.ts +0 -1
  99. package/dist/commands/tenant/env/get_all/index.js +1 -30
  100. package/dist/commands/tenant/env/list/index.d.ts +0 -1
  101. package/dist/commands/tenant/env/list/index.js +1 -32
  102. package/dist/commands/tenant/env/set/index.d.ts +0 -1
  103. package/dist/commands/tenant/env/set/index.js +1 -32
  104. package/dist/commands/tenant/env/set_all/index.d.ts +0 -1
  105. package/dist/commands/tenant/env/set_all/index.js +1 -30
  106. package/dist/commands/tenant/get/index.d.ts +0 -1
  107. package/dist/commands/tenant/get/index.js +1 -32
  108. package/dist/commands/tenant/impersonate/index.d.ts +0 -1
  109. package/dist/commands/tenant/impersonate/index.js +1 -32
  110. package/dist/commands/tenant/license/get/index.d.ts +0 -1
  111. package/dist/commands/tenant/license/get/index.js +1 -31
  112. package/dist/commands/tenant/license/set/index.d.ts +0 -1
  113. package/dist/commands/tenant/license/set/index.js +1 -31
  114. package/dist/commands/tenant/list/index.d.ts +0 -1
  115. package/dist/commands/tenant/list/index.js +1 -32
  116. package/dist/commands/tenant/pull/index.d.ts +0 -1
  117. package/dist/commands/tenant/pull/index.js +1 -37
  118. package/dist/commands/tenant/unit_test/list/index.js +1 -12
  119. package/dist/commands/tenant/unit_test/run/index.js +1 -12
  120. package/dist/commands/tenant/unit_test/run_all/index.js +1 -12
  121. package/dist/commands/tenant/workflow_test/list/index.js +1 -12
  122. package/dist/commands/tenant/workflow_test/run/index.js +1 -12
  123. package/dist/commands/tenant/workflow_test/run_all/index.js +1 -12
  124. package/dist/commands/unit_test/list/index.d.ts +0 -1
  125. package/dist/commands/unit_test/list/index.js +1 -33
  126. package/dist/commands/unit_test/run/index.d.ts +0 -1
  127. package/dist/commands/unit_test/run/index.js +1 -33
  128. package/dist/commands/unit_test/run_all/index.d.ts +0 -1
  129. package/dist/commands/unit_test/run_all/index.js +1 -32
  130. package/dist/commands/workflow_test/delete/index.d.ts +0 -1
  131. package/dist/commands/workflow_test/delete/index.js +1 -33
  132. package/dist/commands/workflow_test/get/index.d.ts +0 -1
  133. package/dist/commands/workflow_test/get/index.js +1 -33
  134. package/dist/commands/workflow_test/list/index.d.ts +0 -1
  135. package/dist/commands/workflow_test/list/index.js +1 -33
  136. package/dist/commands/workflow_test/run/index.d.ts +0 -1
  137. package/dist/commands/workflow_test/run/index.js +1 -33
  138. package/dist/commands/workflow_test/run_all/index.d.ts +0 -1
  139. package/dist/commands/workflow_test/run_all/index.js +1 -32
  140. package/dist/commands/workspace/create/index.d.ts +0 -1
  141. package/dist/commands/workspace/create/index.js +1 -39
  142. package/dist/commands/workspace/delete/index.d.ts +0 -1
  143. package/dist/commands/workspace/delete/index.js +1 -39
  144. package/dist/commands/workspace/edit/index.d.ts +0 -1
  145. package/dist/commands/workspace/edit/index.js +1 -38
  146. package/dist/commands/workspace/get/index.d.ts +0 -1
  147. package/dist/commands/workspace/get/index.js +1 -38
  148. package/dist/commands/workspace/list/index.d.ts +0 -1
  149. package/dist/commands/workspace/list/index.js +1 -38
  150. package/dist/commands/workspace/pull/index.d.ts +0 -1
  151. package/dist/commands/workspace/pull/index.js +1 -37
  152. package/dist/utils/local-config.d.ts +43 -0
  153. package/dist/utils/local-config.js +88 -0
  154. package/oclif.manifest.json +2153 -2066
  155. package/package.json +1 -1
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class WorkspaceDelete extends BaseCommand {
6
4
  static description = 'Delete a workspace via the Xano Metadata API. Cannot delete workspaces with active tenants.';
@@ -42,23 +40,7 @@ Deleted workspace 123
42
40
  };
43
41
  async run() {
44
42
  const { flags } = await this.parse(WorkspaceDelete);
45
- // Get profile name (default or from flag/env)
46
- const profileName = flags.profile || this.getDefaultProfile();
47
- // Load credentials
48
- const credentials = this.loadCredentials();
49
- // Get the profile configuration
50
- if (!(profileName in credentials.profiles)) {
51
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
52
- `Create a profile using 'xano profile create'`);
53
- }
54
- const profile = credentials.profiles[profileName];
55
- // Validate required fields
56
- if (!profile.instance_origin) {
57
- this.error(`Profile '${profileName}' is missing instance_origin`);
58
- }
59
- if (!profile.access_token) {
60
- this.error(`Profile '${profileName}' is missing access_token`);
61
- }
43
+ const { profile } = this.resolveProfile(flags);
62
44
  // Get workspace ID from flag or profile
63
45
  const workspaceId = flags.workspace || profile.workspace;
64
46
  if (!workspaceId) {
@@ -119,24 +101,4 @@ Deleted workspace 123
119
101
  });
120
102
  });
121
103
  }
122
- loadCredentials() {
123
- const credentialsPath = this.getCredentialsPath();
124
- // Check if credentials file exists
125
- if (!fs.existsSync(credentialsPath)) {
126
- this.error(`Credentials file not found at ${credentialsPath}\n` +
127
- `Create a profile using 'xano profile create'`);
128
- }
129
- // Read credentials file
130
- try {
131
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
132
- const parsed = yaml.load(fileContent);
133
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
134
- this.error('Credentials file has invalid format.');
135
- }
136
- return parsed;
137
- }
138
- catch (error) {
139
- this.error(`Failed to parse credentials file: ${error}`);
140
- }
141
- }
142
104
  }
@@ -15,5 +15,4 @@ export default class WorkspaceEdit extends BaseCommand {
15
15
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
16
16
  };
17
17
  run(): Promise<void>;
18
- private loadCredentials;
19
18
  }
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class WorkspaceEdit extends BaseCommand {
6
4
  static description = 'Edit an existing workspace via the Xano Metadata API';
@@ -67,23 +65,7 @@ Updated workspace: my-workspace (ID: 123)
67
65
  };
68
66
  async run() {
69
67
  const { flags } = await this.parse(WorkspaceEdit);
70
- // Get profile name (default or from flag/env)
71
- const profileName = flags.profile || this.getDefaultProfile();
72
- // Load credentials
73
- const credentials = this.loadCredentials();
74
- // Get the profile configuration
75
- if (!(profileName in credentials.profiles)) {
76
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
77
- `Create a profile using 'xano profile create'`);
78
- }
79
- const profile = credentials.profiles[profileName];
80
- // Validate required fields
81
- if (!profile.instance_origin) {
82
- this.error(`Profile '${profileName}' is missing instance_origin`);
83
- }
84
- if (!profile.access_token) {
85
- this.error(`Profile '${profileName}' is missing access_token`);
86
- }
68
+ const { profile } = this.resolveProfile(flags);
87
69
  // Get workspace ID from flag or profile
88
70
  const workspaceId = flags.workspace || profile.workspace;
89
71
  if (!workspaceId) {
@@ -160,23 +142,4 @@ Updated workspace: my-workspace (ID: 123)
160
142
  }
161
143
  }
162
144
  }
163
- loadCredentials() {
164
- const credentialsPath = this.getCredentialsPath();
165
- // Check if credentials file exists
166
- if (!fs.existsSync(credentialsPath)) {
167
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
168
- }
169
- // Read credentials file
170
- try {
171
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
172
- const parsed = yaml.load(fileContent);
173
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
174
- this.error('Credentials file has invalid format.');
175
- }
176
- return parsed;
177
- }
178
- catch (error) {
179
- this.error(`Failed to parse credentials file: ${error}`);
180
- }
181
- }
182
145
  }
@@ -10,5 +10,4 @@ export default class WorkspaceGet extends BaseCommand {
10
10
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  };
12
12
  run(): Promise<void>;
13
- private loadCredentials;
14
13
  }
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class WorkspaceGet extends BaseCommand {
6
4
  static description = 'Get details of a specific workspace from the Xano Metadata API';
@@ -41,23 +39,7 @@ Workspace: my-workspace (ID: 123)
41
39
  };
42
40
  async run() {
43
41
  const { flags } = await this.parse(WorkspaceGet);
44
- // Get profile name (default or from flag/env)
45
- const profileName = flags.profile || this.getDefaultProfile();
46
- // Load credentials
47
- const credentials = this.loadCredentials();
48
- // Get the profile configuration
49
- if (!(profileName in credentials.profiles)) {
50
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
51
- `Create a profile using 'xano profile create'`);
52
- }
53
- const profile = credentials.profiles[profileName];
54
- // Validate required fields
55
- if (!profile.instance_origin) {
56
- this.error(`Profile '${profileName}' is missing instance_origin`);
57
- }
58
- if (!profile.access_token) {
59
- this.error(`Profile '${profileName}' is missing access_token`);
60
- }
42
+ const { profile } = this.resolveProfile(flags);
61
43
  // Get workspace ID from flag or profile
62
44
  const workspaceId = flags.workspace || profile.workspace;
63
45
  if (!workspaceId) {
@@ -112,23 +94,4 @@ Workspace: my-workspace (ID: 123)
112
94
  }
113
95
  }
114
96
  }
115
- loadCredentials() {
116
- const credentialsPath = this.getCredentialsPath();
117
- // Check if credentials file exists
118
- if (!fs.existsSync(credentialsPath)) {
119
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile create'`);
120
- }
121
- // Read credentials file
122
- try {
123
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
124
- const parsed = yaml.load(fileContent);
125
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
126
- this.error('Credentials file has invalid format.');
127
- }
128
- return parsed;
129
- }
130
- catch (error) {
131
- this.error(`Failed to parse credentials file: ${error}`);
132
- }
133
- }
134
97
  }
@@ -10,5 +10,4 @@ export default class WorkspaceList extends BaseCommand {
10
10
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
11
  };
12
12
  run(): Promise<void>;
13
- private loadCredentials;
14
13
  }
@@ -1,6 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
- import * as fs from 'node:fs';
4
2
  import BaseCommand from '../../../base-command.js';
5
3
  export default class WorkspaceList extends BaseCommand {
6
4
  static description = 'List all workspaces from the Xano Metadata API';
@@ -57,23 +55,7 @@ Available workspaces:
57
55
  };
58
56
  async run() {
59
57
  const { flags } = await this.parse(WorkspaceList);
60
- // Get profile name (default or from flag/env)
61
- const profileName = flags.profile || this.getDefaultProfile();
62
- // Load credentials
63
- const credentials = this.loadCredentials();
64
- // Get the profile configuration
65
- if (!(profileName in credentials.profiles)) {
66
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
67
- `Create a profile using 'xano profile:create'`);
68
- }
69
- const profile = credentials.profiles[profileName];
70
- // Validate required fields
71
- if (!profile.instance_origin) {
72
- this.error(`Profile '${profileName}' is missing instance_origin`);
73
- }
74
- if (!profile.access_token) {
75
- this.error(`Profile '${profileName}' is missing access_token`);
76
- }
58
+ const { profile } = this.resolveProfile(flags);
77
59
  // Construct the API URL
78
60
  const apiUrl = `${profile.instance_origin}/api:meta/workspace`;
79
61
  // Fetch workspaces from the API
@@ -136,23 +118,4 @@ Available workspaces:
136
118
  }
137
119
  }
138
120
  }
139
- loadCredentials() {
140
- const credentialsPath = this.getCredentialsPath();
141
- // Check if credentials file exists
142
- if (!fs.existsSync(credentialsPath)) {
143
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
144
- }
145
- // Read credentials file
146
- try {
147
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
148
- const parsed = yaml.load(fileContent);
149
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
150
- this.error('Credentials file has invalid format.');
151
- }
152
- return parsed;
153
- }
154
- catch (error) {
155
- this.error(`Failed to parse credentials file: ${error}`);
156
- }
157
- }
158
121
  }
@@ -14,7 +14,6 @@ export default class Pull extends BaseCommand {
14
14
  verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
15
15
  };
16
16
  run(): Promise<void>;
17
- private loadCredentials;
18
17
  /**
19
18
  * Sanitize a document name for use as a filename.
20
19
  * Strips quotes, replaces spaces with underscores, and removes
@@ -1,5 +1,4 @@
1
1
  import { Flags } from '@oclif/core';
2
- import * as yaml from 'js-yaml';
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import snakeCase from 'lodash.snakecase';
@@ -59,23 +58,7 @@ Pulled 58 documents
59
58
  };
60
59
  async run() {
61
60
  const { flags } = await this.parse(Pull);
62
- // Get profile name (default or from flag/env)
63
- const profileName = flags.profile || this.getDefaultProfile();
64
- // Load credentials
65
- const credentials = this.loadCredentials();
66
- // Get the profile configuration
67
- if (!(profileName in credentials.profiles)) {
68
- this.error(`Profile '${profileName}' not found. Available profiles: ${Object.keys(credentials.profiles).join(', ')}\n` +
69
- `Create a profile using 'xano profile:create'`);
70
- }
71
- const profile = credentials.profiles[profileName];
72
- // Validate required fields
73
- if (!profile.instance_origin) {
74
- this.error(`Profile '${profileName}' is missing instance_origin`);
75
- }
76
- if (!profile.access_token) {
77
- this.error(`Profile '${profileName}' is missing access_token`);
78
- }
61
+ const { profile, profileName } = this.resolveProfile(flags);
79
62
  // Determine workspace_id from flag or profile
80
63
  let workspaceId;
81
64
  if (flags.workspace) {
@@ -258,25 +241,6 @@ Pulled 58 documents
258
241
  }
259
242
  this.log(`Pulled ${writtenCount} documents to ${flags.directory}`);
260
243
  }
261
- loadCredentials() {
262
- const credentialsPath = this.getCredentialsPath();
263
- // Check if credentials file exists
264
- if (!fs.existsSync(credentialsPath)) {
265
- this.error(`Credentials file not found at ${credentialsPath}\n` + `Create a profile using 'xano profile:create'`);
266
- }
267
- // Read credentials file
268
- try {
269
- const fileContent = fs.readFileSync(credentialsPath, 'utf8');
270
- const parsed = yaml.load(fileContent);
271
- if (!parsed || typeof parsed !== 'object' || !('profiles' in parsed)) {
272
- this.error('Credentials file has invalid format.');
273
- }
274
- return parsed;
275
- }
276
- catch (error) {
277
- this.error(`Failed to parse credentials file: ${error}`);
278
- }
279
- }
280
244
  /**
281
245
  * Sanitize a document name for use as a filename.
282
246
  * Strips quotes, replaces spaces with underscores, and removes
@@ -0,0 +1,43 @@
1
+ import type { ProfileConfig } from '../base-command.js';
2
+ export declare const LOCAL_PROFILE_FILENAME = "profile.yaml";
3
+ /** Fields a project-local profile.yaml may set. No secrets allowed. */
4
+ export interface LocalProfileConfig {
5
+ account_origin?: string;
6
+ branch?: string;
7
+ instance_origin?: string;
8
+ profile?: string;
9
+ workspace?: string;
10
+ }
11
+ /**
12
+ * Parse the raw contents of a profile.yaml.
13
+ * - Throws if `access_token` is present (secrets belong in credentials.yaml).
14
+ * - Returns null if the content is not an object or has no recognized keys
15
+ * (so an unrelated profile.yaml from another tool is ignored, not hijacked).
16
+ */
17
+ export declare function parseLocalProfile(raw: string): LocalProfileConfig | null;
18
+ /**
19
+ * Return a new profile with the local override fields applied.
20
+ * The `profile` pointer is never copied; secrets are preserved from the base.
21
+ */
22
+ export declare function applyLocalOverrides(base: ProfileConfig, local: LocalProfileConfig): ProfileConfig;
23
+ /**
24
+ * Decide which profile name to use and whether local overrides apply.
25
+ * Precedence: explicit -p/XANO_PROFILE > local profile.yaml > credentials default.
26
+ * An explicit profile disables the local file entirely (name and overrides).
27
+ */
28
+ export declare function resolveProfileSelection(params: {
29
+ defaultProfile: string;
30
+ explicitProfile?: string;
31
+ hasLocal: boolean;
32
+ localProfileName?: string;
33
+ }): {
34
+ applyLocal: boolean;
35
+ profileName: string;
36
+ };
37
+ /** Format the one-line banner shown when a local profile.yaml is in effect. */
38
+ export declare function formatLocalProfileBanner(profileName: string, workspace: string | undefined, relativePath: string): string;
39
+ /**
40
+ * Walk up from `startDir` to the filesystem root, returning the path of the
41
+ * first profile.yaml found, or null if none exists.
42
+ */
43
+ export declare function findLocalProfilePath(startDir: string): null | string;
@@ -0,0 +1,88 @@
1
+ import * as yaml from 'js-yaml';
2
+ import * as fs from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ export const LOCAL_PROFILE_FILENAME = 'profile.yaml';
5
+ const RECOGNIZED_KEYS = ['profile', 'workspace', 'instance_origin', 'account_origin', 'branch'];
6
+ /**
7
+ * Fields that may be layered onto a resolved profile (everything except the profile pointer).
8
+ * NOTE: `insecure` is intentionally NOT listed here — a project file must never silently
9
+ * disable TLS verification (security boundary).
10
+ */
11
+ const OVERRIDE_KEYS = ['workspace', 'instance_origin', 'account_origin', 'branch'];
12
+ /**
13
+ * Parse the raw contents of a profile.yaml.
14
+ * - Throws if `access_token` is present (secrets belong in credentials.yaml).
15
+ * - Returns null if the content is not an object or has no recognized keys
16
+ * (so an unrelated profile.yaml from another tool is ignored, not hijacked).
17
+ */
18
+ export function parseLocalProfile(raw) {
19
+ const parsed = yaml.load(raw);
20
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
21
+ return null;
22
+ }
23
+ const obj = parsed;
24
+ if ('access_token' in obj) {
25
+ throw new Error(`profile.yaml must not contain access_token. ` +
26
+ `Tokens belong in credentials.yaml — reference a profile by name instead.`);
27
+ }
28
+ const config = {};
29
+ for (const key of RECOGNIZED_KEYS) {
30
+ if (obj[key] !== undefined && obj[key] !== null) {
31
+ config[key] = String(obj[key]);
32
+ }
33
+ }
34
+ if (Object.keys(config).length === 0) {
35
+ return null;
36
+ }
37
+ return config;
38
+ }
39
+ /**
40
+ * Return a new profile with the local override fields applied.
41
+ * The `profile` pointer is never copied; secrets are preserved from the base.
42
+ */
43
+ export function applyLocalOverrides(base, local) {
44
+ const result = { ...base };
45
+ for (const key of OVERRIDE_KEYS) {
46
+ if (local[key] !== undefined) {
47
+ result[key] = local[key];
48
+ }
49
+ }
50
+ return result;
51
+ }
52
+ /**
53
+ * Decide which profile name to use and whether local overrides apply.
54
+ * Precedence: explicit -p/XANO_PROFILE > local profile.yaml > credentials default.
55
+ * An explicit profile disables the local file entirely (name and overrides).
56
+ */
57
+ export function resolveProfileSelection(params) {
58
+ if (params.explicitProfile) {
59
+ return { applyLocal: false, profileName: params.explicitProfile };
60
+ }
61
+ if (params.hasLocal) {
62
+ return { applyLocal: true, profileName: params.localProfileName ?? params.defaultProfile };
63
+ }
64
+ return { applyLocal: false, profileName: params.defaultProfile };
65
+ }
66
+ /** Format the one-line banner shown when a local profile.yaml is in effect. */
67
+ export function formatLocalProfileBanner(profileName, workspace, relativePath) {
68
+ const workspaceClause = workspace ? ` (workspace ${workspace})` : '';
69
+ return `Using profile '${profileName}'${workspaceClause} · ${relativePath}`;
70
+ }
71
+ /**
72
+ * Walk up from `startDir` to the filesystem root, returning the path of the
73
+ * first profile.yaml found, or null if none exists.
74
+ */
75
+ export function findLocalProfilePath(startDir) {
76
+ let dir = resolve(startDir);
77
+ while (true) {
78
+ const candidate = join(dir, LOCAL_PROFILE_FILENAME);
79
+ if (fs.existsSync(candidate) && fs.statSync(candidate).isFile()) {
80
+ return candidate;
81
+ }
82
+ const parent = dirname(dir);
83
+ if (parent === dir) {
84
+ return null;
85
+ }
86
+ dir = parent;
87
+ }
88
+ }