@hyperdrive.bot/cli 1.0.13 → 1.0.17
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 +4526 -780
- package/dist/commands/deploy.d.ts +18 -0
- package/dist/commands/deploy.js +239 -0
- package/dist/commands/deployment/create.js +10 -2
- package/dist/commands/domain/{switch.d.ts → set-production.d.ts} +1 -1
- package/dist/commands/domain/set-production.js +27 -0
- package/dist/commands/git/list-open-prs.d.ts +12 -0
- package/dist/commands/git/list-open-prs.js +87 -0
- package/dist/commands/hook/add.d.ts +22 -0
- package/dist/commands/hook/add.js +299 -0
- package/dist/commands/hook/list.d.ts +11 -0
- package/dist/commands/hook/list.js +111 -0
- package/dist/commands/hook/logs.d.ts +13 -0
- package/dist/commands/hook/logs.js +124 -0
- package/dist/commands/hook/remove.d.ts +12 -0
- package/dist/commands/hook/remove.js +115 -0
- package/dist/commands/hook/toggle.d.ts +12 -0
- package/dist/commands/hook/toggle.js +125 -0
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +49 -9
- package/dist/commands/module/bindings.d.ts +14 -0
- package/dist/commands/module/bindings.js +125 -0
- package/dist/commands/module/create.d.ts +3 -0
- package/dist/commands/module/create.js +156 -78
- package/dist/commands/module/list.d.ts +1 -0
- package/dist/commands/module/list.js +22 -1
- package/dist/commands/module/sync.d.ts +29 -0
- package/dist/commands/module/sync.js +409 -0
- package/dist/commands/module/unlink.d.ts +11 -0
- package/dist/commands/module/unlink.js +77 -0
- package/dist/commands/module/update.d.ts +10 -0
- package/dist/commands/module/update.js +168 -5
- package/dist/commands/network/discover.d.ts +12 -0
- package/dist/commands/network/discover.js +210 -0
- package/dist/commands/network/get.d.ts +13 -0
- package/dist/commands/network/get.js +90 -0
- package/dist/commands/{auth/logout.d.ts → network/list.d.ts} +2 -9
- package/dist/commands/network/list.js +71 -0
- package/dist/commands/network/register.d.ts +16 -0
- package/dist/commands/network/register.js +144 -0
- package/dist/commands/parameter/sync.d.ts +13 -0
- package/dist/commands/parameter/sync.js +69 -1
- package/dist/commands/project/sync.d.ts +5 -11
- package/dist/commands/project/sync.js +12 -381
- package/dist/commands/seed.d.ts +93 -0
- package/dist/commands/seed.js +324 -0
- package/dist/commands/service/backup.d.ts +17 -0
- package/dist/commands/service/backup.js +156 -0
- package/dist/commands/service/backups.d.ts +14 -0
- package/dist/commands/service/backups.js +110 -0
- package/dist/commands/service/bind.d.ts +16 -0
- package/dist/commands/service/bind.js +106 -0
- package/dist/commands/service/bindings.d.ts +13 -0
- package/dist/commands/service/bindings.js +78 -0
- package/dist/commands/service/clone.d.ts +19 -0
- package/dist/commands/service/clone.js +153 -0
- package/dist/commands/service/create.d.ts +16 -0
- package/dist/commands/service/create.js +212 -0
- package/dist/commands/service/get.d.ts +13 -0
- package/dist/commands/service/get.js +97 -0
- package/dist/commands/service/list.d.ts +12 -0
- package/dist/commands/service/list.js +86 -0
- package/dist/commands/service/register.d.ts +21 -0
- package/dist/commands/service/register.js +215 -0
- package/dist/commands/service/restore.d.ts +19 -0
- package/dist/commands/service/restore.js +158 -0
- package/dist/commands/service/seed.d.ts +17 -0
- package/dist/commands/service/seed.js +173 -0
- package/dist/commands/service/templates.d.ts +10 -0
- package/dist/commands/service/templates.js +66 -0
- package/dist/commands/service/unbind.d.ts +15 -0
- package/dist/commands/service/unbind.js +74 -0
- package/dist/commands/stage/create.d.ts +23 -0
- package/dist/commands/stage/create.js +145 -6
- package/dist/commands/stage/delete.d.ts +11 -0
- package/dist/commands/stage/delete.js +85 -0
- package/dist/commands/stage/deploy.d.ts +34 -0
- package/dist/commands/stage/deploy.js +294 -0
- package/dist/commands/stage/ensure-branches.d.ts +23 -0
- package/dist/commands/stage/ensure-branches.js +101 -0
- package/dist/commands/stage/list.js +4 -0
- package/dist/commands/stage/status.d.ts +14 -0
- package/dist/commands/stage/status.js +100 -0
- package/dist/commands/{jira → tracker}/connect.js +32 -23
- package/dist/commands/tracker/hook/add.d.ts +25 -0
- package/dist/commands/tracker/hook/add.js +284 -0
- package/dist/commands/{jira → tracker}/hook/list.js +20 -11
- package/dist/commands/{jira/hook/add.d.ts → tracker/hook/logs.d.ts} +2 -3
- package/dist/commands/tracker/hook/logs.js +126 -0
- package/dist/commands/{jira → tracker}/hook/remove.js +9 -8
- package/dist/commands/{jira → tracker}/hook/toggle.js +14 -12
- package/dist/commands/tracker/project/init.d.ts +17 -0
- package/dist/commands/tracker/project/init.js +178 -0
- package/dist/commands/tracker/project/link-module.d.ts +17 -0
- package/dist/commands/tracker/project/link-module.js +287 -0
- package/dist/commands/tracker/project/list-modules.d.ts +11 -0
- package/dist/commands/tracker/project/list-modules.js +117 -0
- package/dist/commands/tracker/project/list.d.ts +10 -0
- package/dist/commands/tracker/project/list.js +90 -0
- package/dist/commands/tracker/project/status.d.ts +13 -0
- package/dist/commands/tracker/project/status.js +168 -0
- package/dist/commands/tracker/project/unlink-module.d.ts +13 -0
- package/dist/commands/tracker/project/unlink-module.js +251 -0
- package/dist/commands/{jira → tracker}/status.js +3 -3
- package/dist/lib/ensure-branches.d.ts +53 -0
- package/dist/lib/ensure-branches.js +149 -0
- package/dist/lib/git-providers/github.d.ts +16 -0
- package/dist/lib/git-providers/github.js +157 -0
- package/dist/lib/git-providers/gitlab.d.ts +16 -0
- package/dist/lib/git-providers/gitlab.js +148 -0
- package/dist/lib/git-providers/index.d.ts +67 -0
- package/dist/lib/git-providers/index.js +39 -0
- package/dist/lib/lambda-warmer.d.ts +106 -0
- package/dist/lib/lambda-warmer.js +189 -0
- package/dist/services/hyperdrive-sigv4.d.ts +359 -5
- package/dist/services/hyperdrive-sigv4.js +177 -12
- package/dist/utils/hook-flow.d.ts +60 -3
- package/dist/utils/hook-flow.js +437 -2
- package/dist/utils/hook-normalize.d.ts +6 -0
- package/dist/utils/hook-normalize.js +33 -0
- package/dist/utils/lifecycle-poller.d.ts +32 -0
- package/dist/utils/lifecycle-poller.js +72 -0
- package/dist/utils/retry.d.ts +43 -0
- package/dist/utils/retry.js +88 -0
- package/dist/utils/summary-display.js +1 -1
- package/dist/utils/tracker-project-flow.d.ts +84 -0
- package/dist/utils/tracker-project-flow.js +564 -0
- package/package.json +41 -13
- package/dist/commands/auth/login.d.ts +0 -16
- package/dist/commands/auth/login.js +0 -179
- package/dist/commands/auth/logout.js +0 -116
- package/dist/commands/auth/refresh.d.ts +0 -6
- package/dist/commands/auth/refresh.js +0 -66
- package/dist/commands/auth/status.d.ts +0 -6
- package/dist/commands/auth/status.js +0 -63
- package/dist/commands/config/get.d.ts +0 -9
- package/dist/commands/config/get.js +0 -37
- package/dist/commands/config/set.d.ts +0 -10
- package/dist/commands/config/set.js +0 -48
- package/dist/commands/config/show.d.ts +0 -6
- package/dist/commands/config/show.js +0 -10
- package/dist/commands/domain/current.d.ts +0 -6
- package/dist/commands/domain/current.js +0 -18
- package/dist/commands/domain/list.d.ts +0 -6
- package/dist/commands/domain/list.js +0 -42
- package/dist/commands/domain/switch.js +0 -40
- package/dist/commands/jira/hook/add.js +0 -147
- package/dist/services/tenant-service.d.ts +0 -127
- package/dist/services/tenant-service.js +0 -396
- package/dist/utils/auth-flow.d.ts +0 -147
- package/dist/utils/auth-flow.js +0 -479
- package/oclif.manifest.json +0 -3519
- /package/dist/commands/{jira → tracker}/connect.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/list.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/remove.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/hook/toggle.d.ts +0 -0
- /package/dist/commands/{jira → tracker}/status.d.ts +0 -0
|
@@ -1,396 +0,0 @@
|
|
|
1
|
-
import axios from 'axios';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
|
4
|
-
import { homedir } from 'os';
|
|
5
|
-
import { join } from 'path';
|
|
6
|
-
/**
|
|
7
|
-
* Tenant Service for CLI
|
|
8
|
-
*
|
|
9
|
-
* Handles tenant resolution and Cognito configuration discovery via bootstrap endpoint.
|
|
10
|
-
* Supports environment variables and config file overrides.
|
|
11
|
-
*/
|
|
12
|
-
export class TenantService {
|
|
13
|
-
configDir;
|
|
14
|
-
configPath;
|
|
15
|
-
defaultBootstrapUrl = 'https://api.hyperdrive.bot/tenant/bootstrap';
|
|
16
|
-
defaultDomainPath;
|
|
17
|
-
domain;
|
|
18
|
-
constructor(domain) {
|
|
19
|
-
this.configDir = join(homedir(), '.hyperdrive');
|
|
20
|
-
this.configPath = join(this.configDir, 'config.json');
|
|
21
|
-
this.defaultDomainPath = join(this.configDir, 'default-domain');
|
|
22
|
-
this.domain = domain;
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Clear cached tenant configuration
|
|
26
|
-
*/
|
|
27
|
-
clearCache() {
|
|
28
|
-
const config = this.loadConfigFile();
|
|
29
|
-
if (config) {
|
|
30
|
-
// Remove tenant-specific settings but keep custom URLs
|
|
31
|
-
const { tenantDomain, ...rest } = config;
|
|
32
|
-
this.saveConfig(rest);
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Fetch tenant configuration from bootstrap endpoint
|
|
37
|
-
*/
|
|
38
|
-
async fetchTenantConfig(tenantDomain) {
|
|
39
|
-
const domain = tenantDomain || this.getTenantDomain();
|
|
40
|
-
if (!domain) {
|
|
41
|
-
throw new Error('Tenant not configured. Run `hd init` to set up your environment.');
|
|
42
|
-
}
|
|
43
|
-
const bootstrapUrl = this.getBootstrapUrl();
|
|
44
|
-
try {
|
|
45
|
-
console.log(chalk.gray(`🔗 Fetching tenant config for: ${domain}`));
|
|
46
|
-
console.log(chalk.gray(`📍 Using bootstrap endpoint: ${bootstrapUrl}`));
|
|
47
|
-
const response = await axios.get(bootstrapUrl, {
|
|
48
|
-
headers: {
|
|
49
|
-
'Accept': 'application/json',
|
|
50
|
-
'X-Tenant-Domain': domain,
|
|
51
|
-
},
|
|
52
|
-
});
|
|
53
|
-
const bootstrap = response.data;
|
|
54
|
-
if (!bootstrap.amplifyConfig) {
|
|
55
|
-
throw new Error('Tenant authentication not configured');
|
|
56
|
-
}
|
|
57
|
-
const { Cognito } = bootstrap.amplifyConfig.Auth;
|
|
58
|
-
const region = Cognito.region;
|
|
59
|
-
// Extract Cognito domain from OAuth config or construct from tenant ID
|
|
60
|
-
// The bootstrap response may provide either:
|
|
61
|
-
// - Just the prefix (e.g., "api-tenants-dev-semana-43-a1c4ea06")
|
|
62
|
-
// - Full domain (e.g., "api-tenants-dev-devsquad-804677f8.auth.sa-east-1.amazoncognito.com")
|
|
63
|
-
let cognitoDomain;
|
|
64
|
-
if (Cognito.loginWith?.oauth?.domain) {
|
|
65
|
-
const oauthDomain = Cognito.loginWith.oauth.domain;
|
|
66
|
-
// Check if domain already includes amazoncognito.com (full domain provided)
|
|
67
|
-
if (oauthDomain.includes('.amazoncognito.com')) {
|
|
68
|
-
cognitoDomain = oauthDomain;
|
|
69
|
-
}
|
|
70
|
-
else {
|
|
71
|
-
cognitoDomain = `${oauthDomain}.auth.${region}.amazoncognito.com`;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
else {
|
|
75
|
-
// Fallback: construct from tenant ID
|
|
76
|
-
cognitoDomain = `${bootstrap.tenantId}.auth.${region}.amazoncognito.com`;
|
|
77
|
-
}
|
|
78
|
-
// Extract all additional API URLs from bootstrap (services self-serve by key)
|
|
79
|
-
const additionalApiUrls = this.extractAdditionalApiUrls(bootstrap.amplifyConfig.API);
|
|
80
|
-
const config = {
|
|
81
|
-
apiUrl: this.getApiUrl(region, bootstrap.amplifyConfig.API, domain),
|
|
82
|
-
cognitoClientId: Cognito.userPoolClientId,
|
|
83
|
-
cognitoDomain,
|
|
84
|
-
cognitoIdentityPoolId: Cognito.identityPoolId || '',
|
|
85
|
-
cognitoUserPoolId: Cognito.userPoolId,
|
|
86
|
-
displayName: bootstrap.displayName,
|
|
87
|
-
region,
|
|
88
|
-
tenantDomain: domain,
|
|
89
|
-
tenantId: bootstrap.tenantId,
|
|
90
|
-
additionalApiUrls: Object.keys(additionalApiUrls).length > 0 ? additionalApiUrls : undefined,
|
|
91
|
-
};
|
|
92
|
-
// Cache the tenant domain for future use
|
|
93
|
-
this.saveTenantDomainToConfig(domain);
|
|
94
|
-
// Set as default domain if no default exists
|
|
95
|
-
if (!this.getDefaultDomain()) {
|
|
96
|
-
this.setDefaultDomain(domain);
|
|
97
|
-
}
|
|
98
|
-
return config;
|
|
99
|
-
}
|
|
100
|
-
catch (error) {
|
|
101
|
-
if (axios.isAxiosError(error)) {
|
|
102
|
-
if (error.response?.status === 404) {
|
|
103
|
-
throw new Error(`Tenant not found: ${domain}`);
|
|
104
|
-
}
|
|
105
|
-
throw new Error(`Failed to fetch tenant config: ${error.response?.data?.message || error.message}`);
|
|
106
|
-
}
|
|
107
|
-
throw error;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Get all configured domains
|
|
112
|
-
*/
|
|
113
|
-
getConfiguredDomains() {
|
|
114
|
-
const config = this.loadConfigFile();
|
|
115
|
-
const domains = new Set();
|
|
116
|
-
// Add legacy single domain if exists
|
|
117
|
-
if (config?.tenantDomain) {
|
|
118
|
-
domains.add(config.tenantDomain);
|
|
119
|
-
}
|
|
120
|
-
// Add multi-domain entries
|
|
121
|
-
if (config?.domains) {
|
|
122
|
-
Object.keys(config.domains).forEach(d => domains.add(d));
|
|
123
|
-
}
|
|
124
|
-
return Array.from(domains);
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Get current tenant configuration (from cache or fetch)
|
|
128
|
-
*/
|
|
129
|
-
async getCurrentTenant() {
|
|
130
|
-
return this.fetchTenantConfig();
|
|
131
|
-
}
|
|
132
|
-
/**
|
|
133
|
-
* Get default domain from file
|
|
134
|
-
*/
|
|
135
|
-
getDefaultDomain() {
|
|
136
|
-
try {
|
|
137
|
-
if (!existsSync(this.defaultDomainPath)) {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
return readFileSync(this.defaultDomainPath, 'utf8').trim();
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Get tenant domain with fallback chain:
|
|
148
|
-
* 1. Constructor domain parameter (from --domain flag)
|
|
149
|
-
* 2. Environment variable
|
|
150
|
-
* 3. Default domain file
|
|
151
|
-
* 4. Legacy single domain from config
|
|
152
|
-
* 5. Return null (caller should prompt user interactively)
|
|
153
|
-
*/
|
|
154
|
-
getTenantDomain() {
|
|
155
|
-
// Priority 1: Explicit domain parameter (from --domain flag)
|
|
156
|
-
if (this.domain) {
|
|
157
|
-
return this.domain;
|
|
158
|
-
}
|
|
159
|
-
// Priority 2: Environment variable
|
|
160
|
-
if (process.env.HYPERDRIVE_TENANT_DOMAIN) {
|
|
161
|
-
return process.env.HYPERDRIVE_TENANT_DOMAIN;
|
|
162
|
-
}
|
|
163
|
-
// Priority 3: Default domain file
|
|
164
|
-
const defaultDomain = this.getDefaultDomain();
|
|
165
|
-
if (defaultDomain) {
|
|
166
|
-
return defaultDomain;
|
|
167
|
-
}
|
|
168
|
-
// Priority 4: Legacy single domain from config file
|
|
169
|
-
const config = this.loadConfigFile();
|
|
170
|
-
if (config?.tenantDomain) {
|
|
171
|
-
return config.tenantDomain;
|
|
172
|
-
}
|
|
173
|
-
// Priority 5: Return null to trigger interactive prompt
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Save CLI configuration to file
|
|
178
|
-
*/
|
|
179
|
-
saveConfig(config) {
|
|
180
|
-
try {
|
|
181
|
-
if (!existsSync(this.configDir)) {
|
|
182
|
-
mkdirSync(this.configDir, { recursive: true });
|
|
183
|
-
}
|
|
184
|
-
writeFileSync(this.configPath, JSON.stringify(config, null, 2), { mode: 0o600 });
|
|
185
|
-
console.log(chalk.gray(`✓ Configuration saved to ${this.configPath}`));
|
|
186
|
-
}
|
|
187
|
-
catch (error) {
|
|
188
|
-
console.error(chalk.red('Failed to save configuration:'), error);
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
/**
|
|
192
|
-
* Clear the default domain file
|
|
193
|
-
*/
|
|
194
|
-
clearDefaultDomain() {
|
|
195
|
-
try {
|
|
196
|
-
if (existsSync(this.defaultDomainPath)) {
|
|
197
|
-
unlinkSync(this.defaultDomainPath);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
catch (error) {
|
|
201
|
-
console.error(chalk.red('Failed to clear default domain:'), error);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Remove a specific domain from config.json domains map
|
|
206
|
-
*/
|
|
207
|
-
removeDomainConfig(domain) {
|
|
208
|
-
const config = this.loadConfigFile();
|
|
209
|
-
if (!config)
|
|
210
|
-
return;
|
|
211
|
-
if (config.domains?.[domain]) {
|
|
212
|
-
delete config.domains[domain];
|
|
213
|
-
}
|
|
214
|
-
// If this was the legacy tenantDomain, clear it too
|
|
215
|
-
if (config.tenantDomain === domain) {
|
|
216
|
-
delete config.tenantDomain;
|
|
217
|
-
}
|
|
218
|
-
this.saveConfig(config);
|
|
219
|
-
}
|
|
220
|
-
/**
|
|
221
|
-
* Remove the entire config file and default-domain file
|
|
222
|
-
*/
|
|
223
|
-
clearAllConfig() {
|
|
224
|
-
try {
|
|
225
|
-
if (existsSync(this.configPath)) {
|
|
226
|
-
unlinkSync(this.configPath);
|
|
227
|
-
}
|
|
228
|
-
this.clearDefaultDomain();
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
console.error(chalk.red('Failed to clear config:'), error);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
/**
|
|
235
|
-
* Set default domain
|
|
236
|
-
*/
|
|
237
|
-
setDefaultDomain(domain) {
|
|
238
|
-
try {
|
|
239
|
-
if (!existsSync(this.configDir)) {
|
|
240
|
-
mkdirSync(this.configDir, { recursive: true });
|
|
241
|
-
}
|
|
242
|
-
writeFileSync(this.defaultDomainPath, domain, { mode: 0o600 });
|
|
243
|
-
console.log(chalk.gray(`✓ Default domain set to ${domain}`));
|
|
244
|
-
}
|
|
245
|
-
catch (error) {
|
|
246
|
-
console.error(chalk.red('Failed to set default domain:'), error);
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
/**
|
|
250
|
-
* Set tenant domain in config file
|
|
251
|
-
*
|
|
252
|
-
* Public method for init wizard to persist tenant domain configuration.
|
|
253
|
-
* Creates config directory if needed and applies 0o600 permissions.
|
|
254
|
-
*
|
|
255
|
-
* @param domain - The tenant domain to save
|
|
256
|
-
*/
|
|
257
|
-
setTenantDomain(domain) {
|
|
258
|
-
this.saveTenantDomainToConfig(domain);
|
|
259
|
-
}
|
|
260
|
-
/**
|
|
261
|
-
* Display current configuration
|
|
262
|
-
*/
|
|
263
|
-
showConfig() {
|
|
264
|
-
const config = this.loadConfigFile();
|
|
265
|
-
const tenantDomain = this.getTenantDomain();
|
|
266
|
-
const bootstrapUrl = this.getBootstrapUrl();
|
|
267
|
-
console.log(chalk.blue('🔧 Current Configuration'));
|
|
268
|
-
console.log('');
|
|
269
|
-
console.log(chalk.white('Bootstrap URL:'), chalk.cyan(bootstrapUrl));
|
|
270
|
-
console.log(chalk.white('Source:'), process.env.HYPERDRIVE_BOOTSTRAP_URL
|
|
271
|
-
? chalk.yellow('ENV')
|
|
272
|
-
: config?.bootstrapUrl
|
|
273
|
-
? chalk.green('Config File')
|
|
274
|
-
: chalk.gray('Default'));
|
|
275
|
-
console.log('');
|
|
276
|
-
console.log(chalk.white('Tenant Domain:'), tenantDomain ? chalk.cyan(tenantDomain) : chalk.gray('Not set'));
|
|
277
|
-
if (tenantDomain) {
|
|
278
|
-
console.log(chalk.white('Source:'), process.env.HYPERDRIVE_TENANT_DOMAIN
|
|
279
|
-
? chalk.yellow('ENV')
|
|
280
|
-
: config?.tenantDomain
|
|
281
|
-
? chalk.green('Config File')
|
|
282
|
-
: chalk.gray('Unknown'));
|
|
283
|
-
}
|
|
284
|
-
console.log('');
|
|
285
|
-
console.log(chalk.gray('Config file: ' + this.configPath));
|
|
286
|
-
}
|
|
287
|
-
/**
|
|
288
|
-
* Get API URL for a region
|
|
289
|
-
*/
|
|
290
|
-
getApiUrl(region, apiConfig, domain) {
|
|
291
|
-
// Priority 1: Environment variable (for testing/override)
|
|
292
|
-
if (process.env.HYPERDRIVE_API_URL) {
|
|
293
|
-
console.log(chalk.gray(`✓ Using API endpoint from environment: ${process.env.HYPERDRIVE_API_URL}`));
|
|
294
|
-
return process.env.HYPERDRIVE_API_URL;
|
|
295
|
-
}
|
|
296
|
-
// Priority 2: Domain-specific config (for multi-domain setups)
|
|
297
|
-
const config = this.loadConfigFile();
|
|
298
|
-
if (domain && config?.domains?.[domain]?.apiUrl) {
|
|
299
|
-
const domainApiUrl = config.domains[domain].apiUrl;
|
|
300
|
-
console.log(chalk.gray(`✓ Using API endpoint from domain config: ${domainApiUrl}`));
|
|
301
|
-
return domainApiUrl;
|
|
302
|
-
}
|
|
303
|
-
// Priority 3: Legacy global config file (for manual override)
|
|
304
|
-
if (config?.apiUrl) {
|
|
305
|
-
console.log(chalk.gray(`✓ Using API endpoint from config: ${config.apiUrl}`));
|
|
306
|
-
return config.apiUrl;
|
|
307
|
-
}
|
|
308
|
-
// Priority 4: From bootstrap API config (REQUIRED - no fallback)
|
|
309
|
-
if (apiConfig?.REST?.hyperdrive?.endpoint) {
|
|
310
|
-
console.log(chalk.gray(`✓ Using API endpoint from bootstrap: ${apiConfig.REST.hyperdrive.endpoint}`));
|
|
311
|
-
return apiConfig.REST.hyperdrive.endpoint;
|
|
312
|
-
}
|
|
313
|
-
// No hyperdrive endpoint found - user doesn't have access
|
|
314
|
-
throw new Error('Hyperdrive API not available for this tenant.\n\n' +
|
|
315
|
-
chalk.yellow('This tenant does not have access to Hyperdrive.\n') +
|
|
316
|
-
chalk.gray('Please contact your administrator to enable the Hyperdrive module.'));
|
|
317
|
-
}
|
|
318
|
-
/**
|
|
319
|
-
* Extract all additional API URLs from bootstrap REST config.
|
|
320
|
-
* Returns a map of module name → endpoint URL for every REST API
|
|
321
|
-
* beyond the primary 'hyperdrive' endpoint. Services self-serve
|
|
322
|
-
* by looking up the key they need (e.g., 'hyperdrive-projects', 'user-groups').
|
|
323
|
-
*/
|
|
324
|
-
extractAdditionalApiUrls(apiConfig) {
|
|
325
|
-
const urls = {};
|
|
326
|
-
if (!apiConfig?.REST)
|
|
327
|
-
return urls;
|
|
328
|
-
for (const [apiName, config] of Object.entries(apiConfig.REST)) {
|
|
329
|
-
if (apiName !== 'hyperdrive' && config.endpoint) {
|
|
330
|
-
console.log(chalk.gray(`✓ Discovered API endpoint: ${apiName} → ${config.endpoint}`));
|
|
331
|
-
urls[apiName] = config.endpoint;
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return urls;
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Get bootstrap URL with fallback chain:
|
|
338
|
-
* 1. Environment variable
|
|
339
|
-
* 2. Config file
|
|
340
|
-
* 3. Construct from tenant domain
|
|
341
|
-
* 4. Default URL
|
|
342
|
-
*/
|
|
343
|
-
getBootstrapUrl() {
|
|
344
|
-
// Priority 1: Environment variable
|
|
345
|
-
if (process.env.HYPERDRIVE_BOOTSTRAP_URL) {
|
|
346
|
-
return process.env.HYPERDRIVE_BOOTSTRAP_URL;
|
|
347
|
-
}
|
|
348
|
-
// Priority 2: Config file
|
|
349
|
-
const config = this.loadConfigFile();
|
|
350
|
-
if (config?.bootstrapUrl) {
|
|
351
|
-
return config.bootstrapUrl;
|
|
352
|
-
}
|
|
353
|
-
// Priority 3: Construct from tenant domain if configured
|
|
354
|
-
const tenantDomain = this.getTenantDomain();
|
|
355
|
-
if (tenantDomain) {
|
|
356
|
-
return `https://${tenantDomain}/tenant/bootstrap`;
|
|
357
|
-
}
|
|
358
|
-
// Priority 4: Default
|
|
359
|
-
return this.defaultBootstrapUrl;
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Load CLI configuration from file
|
|
363
|
-
*/
|
|
364
|
-
loadConfigFile() {
|
|
365
|
-
try {
|
|
366
|
-
if (!existsSync(this.configPath)) {
|
|
367
|
-
return null;
|
|
368
|
-
}
|
|
369
|
-
const data = readFileSync(this.configPath, 'utf8');
|
|
370
|
-
return JSON.parse(data);
|
|
371
|
-
}
|
|
372
|
-
catch (error) {
|
|
373
|
-
console.error(chalk.yellow('⚠️ Failed to load config file, using defaults'));
|
|
374
|
-
return null;
|
|
375
|
-
}
|
|
376
|
-
}
|
|
377
|
-
/**
|
|
378
|
-
* Save tenant domain to config file for future use
|
|
379
|
-
*/
|
|
380
|
-
saveTenantDomainToConfig(tenantDomain) {
|
|
381
|
-
const existingConfig = this.loadConfigFile() || {};
|
|
382
|
-
// Initialize domains object if it doesn't exist
|
|
383
|
-
if (!existingConfig.domains) {
|
|
384
|
-
existingConfig.domains = {};
|
|
385
|
-
}
|
|
386
|
-
// Add this domain to the domains map (even if just an empty object for now)
|
|
387
|
-
if (!existingConfig.domains[tenantDomain]) {
|
|
388
|
-
existingConfig.domains[tenantDomain] = {};
|
|
389
|
-
}
|
|
390
|
-
// Also keep legacy tenantDomain for backward compatibility
|
|
391
|
-
this.saveConfig({
|
|
392
|
-
...existingConfig,
|
|
393
|
-
tenantDomain,
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import { TenantConfig } from '../services/tenant-service.js';
|
|
2
|
-
/**
|
|
3
|
-
* Options for executing the OAuth PKCE authentication flow
|
|
4
|
-
*/
|
|
5
|
-
export interface AuthFlowOptions {
|
|
6
|
-
callbackPort?: number;
|
|
7
|
-
logger?: (message: string) => void;
|
|
8
|
-
tenantDomain: string;
|
|
9
|
-
timeout?: number;
|
|
10
|
-
}
|
|
11
|
-
/**
|
|
12
|
-
* Result of the authentication flow
|
|
13
|
-
*/
|
|
14
|
-
export interface AuthResult {
|
|
15
|
-
error?: string;
|
|
16
|
-
skipped?: boolean;
|
|
17
|
-
success: boolean;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Cognito tokens received from OAuth token exchange
|
|
21
|
-
*/
|
|
22
|
-
export interface CognitoTokens {
|
|
23
|
-
access_token: string;
|
|
24
|
-
expires_in: number;
|
|
25
|
-
id_token: string;
|
|
26
|
-
refresh_token: string;
|
|
27
|
-
token_type: string;
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* AWS credentials obtained from Cognito Identity Pool
|
|
31
|
-
*/
|
|
32
|
-
export interface AWSCredentials {
|
|
33
|
-
accessKeyId: string;
|
|
34
|
-
expiration: Date;
|
|
35
|
-
secretAccessKey: string;
|
|
36
|
-
sessionToken: string;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Cognito configuration for storing with credentials
|
|
40
|
-
*/
|
|
41
|
-
export interface CognitoConfig {
|
|
42
|
-
clientId: string;
|
|
43
|
-
domain: string;
|
|
44
|
-
identityPoolId: string;
|
|
45
|
-
userPoolId: string;
|
|
46
|
-
}
|
|
47
|
-
/**
|
|
48
|
-
* Complete stored credentials including tokens and AWS credentials
|
|
49
|
-
*/
|
|
50
|
-
export interface StoredCredentials extends CognitoTokens {
|
|
51
|
-
additionalApiUrls?: Record<string, string>;
|
|
52
|
-
apiUrl: string;
|
|
53
|
-
awsCredentials: AWSCredentials;
|
|
54
|
-
cognitoConfig: CognitoConfig;
|
|
55
|
-
obtainedAt: string;
|
|
56
|
-
region: string;
|
|
57
|
-
tenantDomain: string;
|
|
58
|
-
tenantId: string;
|
|
59
|
-
}
|
|
60
|
-
/**
|
|
61
|
-
* Generate PKCE code verifier (random base64url string)
|
|
62
|
-
*/
|
|
63
|
-
export declare function generateCodeVerifier(): string;
|
|
64
|
-
/**
|
|
65
|
-
* Generate PKCE code challenge (SHA256 hash of verifier)
|
|
66
|
-
*/
|
|
67
|
-
export declare function generateCodeChallenge(verifier: string): string;
|
|
68
|
-
/**
|
|
69
|
-
* Build Cognito authorization URL with PKCE parameters
|
|
70
|
-
*/
|
|
71
|
-
export declare function buildAuthUrl(tenantConfig: TenantConfig, codeChallenge: string, port: number): string;
|
|
72
|
-
/**
|
|
73
|
-
* Start local HTTP server to receive OAuth callback
|
|
74
|
-
* Returns a promise that resolves with the authorization code
|
|
75
|
-
*/
|
|
76
|
-
export declare function startCallbackServer(port: number, timeout: number): Promise<string>;
|
|
77
|
-
/**
|
|
78
|
-
* Exchange authorization code for Cognito tokens
|
|
79
|
-
*/
|
|
80
|
-
export declare function exchangeCodeForTokens(tenantConfig: TenantConfig, code: string, codeVerifier: string, port: number): Promise<CognitoTokens>;
|
|
81
|
-
/**
|
|
82
|
-
* Get AWS credentials from Cognito Identity Pool
|
|
83
|
-
*/
|
|
84
|
-
export declare function getAWSCredentials(tenantConfig: TenantConfig, idToken: string): Promise<AWSCredentials>;
|
|
85
|
-
/**
|
|
86
|
-
* Save credentials to domain-specific path (always required)
|
|
87
|
-
*/
|
|
88
|
-
export declare function saveCredentials(credentials: StoredCredentials, domain: string): void;
|
|
89
|
-
/**
|
|
90
|
-
* Get the path to the credentials file for a domain
|
|
91
|
-
*/
|
|
92
|
-
export declare function getCredentialsPath(domain: string): string;
|
|
93
|
-
/**
|
|
94
|
-
* Execute the complete OAuth PKCE authentication flow
|
|
95
|
-
*
|
|
96
|
-
* This function orchestrates the entire authentication flow:
|
|
97
|
-
* 1. Bootstrap tenant to get Cognito config
|
|
98
|
-
* 2. Generate PKCE codes
|
|
99
|
-
* 3. Start callback server
|
|
100
|
-
* 4. Open browser for authentication
|
|
101
|
-
* 5. Wait for callback with timeout
|
|
102
|
-
* 6. Exchange code for tokens
|
|
103
|
-
* 7. Get AWS credentials from Identity Pool
|
|
104
|
-
* 8. Save credentials to file
|
|
105
|
-
*
|
|
106
|
-
* @param options - Configuration options for the auth flow
|
|
107
|
-
* @returns AuthResult indicating success or failure
|
|
108
|
-
*/
|
|
109
|
-
export declare function executeAuthFlow(options: AuthFlowOptions): Promise<AuthResult>;
|
|
110
|
-
/**
|
|
111
|
-
* Options for CI authentication flow
|
|
112
|
-
*/
|
|
113
|
-
export interface CIAuthOptions {
|
|
114
|
-
logger?: (message: string) => void;
|
|
115
|
-
password: string;
|
|
116
|
-
tenantDomain: string;
|
|
117
|
-
username: string;
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Execute CI authentication flow using USER_PASSWORD_AUTH
|
|
121
|
-
*
|
|
122
|
-
* This is for non-interactive CI/CD environments where browser-based
|
|
123
|
-
* OAuth is not possible. Uses Cognito's USER_PASSWORD_AUTH flow.
|
|
124
|
-
*
|
|
125
|
-
* @param options - CI authentication options
|
|
126
|
-
* @returns AuthResult indicating success or failure
|
|
127
|
-
*/
|
|
128
|
-
export declare function executeCIAuthFlow(options: CIAuthOptions): Promise<AuthResult>;
|
|
129
|
-
/**
|
|
130
|
-
* Check if running in a CI environment
|
|
131
|
-
*/
|
|
132
|
-
export declare function isCI(): boolean;
|
|
133
|
-
/**
|
|
134
|
-
* Decode a CI token into username and password
|
|
135
|
-
* Token format: hd_sk_{base64url(username:password)}
|
|
136
|
-
*/
|
|
137
|
-
export declare function decodeToken(token: string): {
|
|
138
|
-
password: string;
|
|
139
|
-
username: string;
|
|
140
|
-
} | null;
|
|
141
|
-
/**
|
|
142
|
-
* Get CI credentials from HD_TOKEN environment variable
|
|
143
|
-
*/
|
|
144
|
-
export declare function getCICredentials(): {
|
|
145
|
-
password: string;
|
|
146
|
-
username: string;
|
|
147
|
-
} | null;
|