@sembix/cli 1.3.0 → 1.4.1
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/COMMANDS.md +1522 -0
- package/QUICKSTART.md +829 -0
- package/README.md +1949 -285
- package/USAGE-EXAMPLES.md +872 -0
- package/dist/commands/configure.d.ts.map +1 -1
- package/dist/commands/configure.js +172 -2
- package/dist/commands/configure.js.map +1 -1
- package/dist/commands/index.d.ts +10 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +11 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/login.d.ts +19 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +118 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +21 -0
- package/dist/commands/logout.d.ts.map +1 -0
- package/dist/commands/logout.js +66 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/profile-project.d.ts +14 -0
- package/dist/commands/profile-project.d.ts.map +1 -0
- package/dist/commands/profile-project.js +123 -0
- package/dist/commands/profile-project.js.map +1 -0
- package/dist/commands/profile.d.ts +26 -0
- package/dist/commands/profile.d.ts.map +1 -0
- package/dist/commands/profile.js +177 -0
- package/dist/commands/profile.js.map +1 -0
- package/dist/commands/project.d.ts +16 -0
- package/dist/commands/project.d.ts.map +1 -0
- package/dist/commands/project.js +153 -0
- package/dist/commands/project.js.map +1 -0
- package/dist/commands/setup.js +1 -1
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/update.js +2 -2
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/workflow.d.ts +91 -0
- package/dist/commands/workflow.d.ts.map +1 -0
- package/dist/commands/workflow.js +1201 -0
- package/dist/commands/workflow.js.map +1 -0
- package/dist/config-schema.d.ts +23 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config-schema.js +21 -1
- package/dist/config-schema.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +23 -2
- package/dist/config.js.map +1 -1
- package/dist/index.js +318 -1
- package/dist/index.js.map +1 -1
- package/dist/prompts/project-selection.d.ts +8 -0
- package/dist/prompts/project-selection.d.ts.map +1 -0
- package/dist/prompts/project-selection.js +132 -0
- package/dist/prompts/project-selection.js.map +1 -0
- package/dist/prompts/workflow-inputs.d.ts +10 -0
- package/dist/prompts/workflow-inputs.d.ts.map +1 -0
- package/dist/prompts/workflow-inputs.js +71 -0
- package/dist/prompts/workflow-inputs.js.map +1 -0
- package/dist/prompts/workflow-selection.d.ts +8 -0
- package/dist/prompts/workflow-selection.d.ts.map +1 -0
- package/dist/prompts/workflow-selection.js +147 -0
- package/dist/prompts/workflow-selection.js.map +1 -0
- package/dist/sembix-cli-1.4.1.tgz +0 -0
- package/dist/services/cognito-auth.d.ts +92 -0
- package/dist/services/cognito-auth.d.ts.map +1 -0
- package/dist/services/cognito-auth.js +319 -0
- package/dist/services/cognito-auth.js.map +1 -0
- package/dist/services/studio-api-client.d.ts +127 -0
- package/dist/services/studio-api-client.d.ts.map +1 -0
- package/dist/services/studio-api-client.js +291 -0
- package/dist/services/studio-api-client.js.map +1 -0
- package/dist/types/studio.d.ts +82 -0
- package/dist/types/studio.d.ts.map +1 -0
- package/dist/types/studio.js +7 -0
- package/dist/types/studio.js.map +1 -0
- package/dist/types.d.ts +283 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -1
- package/dist/utils/browser-auth.d.ts +45 -0
- package/dist/utils/browser-auth.d.ts.map +1 -0
- package/dist/utils/browser-auth.js +168 -0
- package/dist/utils/browser-auth.js.map +1 -0
- package/dist/utils/cognito-auth.d.ts +3 -0
- package/dist/utils/cognito-auth.d.ts.map +1 -0
- package/dist/utils/cognito-auth.js +3 -0
- package/dist/utils/cognito-auth.js.map +1 -0
- package/dist/utils/config-file.d.ts +40 -0
- package/dist/utils/config-file.d.ts.map +1 -1
- package/dist/utils/config-file.js +158 -4
- package/dist/utils/config-file.js.map +1 -1
- package/dist/utils/environment.d.ts +22 -0
- package/dist/utils/environment.d.ts.map +1 -0
- package/dist/utils/environment.js +39 -0
- package/dist/utils/environment.js.map +1 -0
- package/dist/utils/error-handler.d.ts +53 -0
- package/dist/utils/error-handler.d.ts.map +1 -0
- package/dist/utils/error-handler.js +174 -0
- package/dist/utils/error-handler.js.map +1 -0
- package/dist/utils/fuzzy-match.d.ts +31 -0
- package/dist/utils/fuzzy-match.d.ts.map +1 -0
- package/dist/utils/fuzzy-match.js +138 -0
- package/dist/utils/fuzzy-match.js.map +1 -0
- package/dist/utils/github.d.ts +2 -2
- package/dist/utils/github.d.ts.map +1 -1
- package/dist/utils/github.js +30 -10
- package/dist/utils/github.js.map +1 -1
- package/dist/utils/input-parser.d.ts +14 -0
- package/dist/utils/input-parser.d.ts.map +1 -0
- package/dist/utils/input-parser.js +34 -0
- package/dist/utils/input-parser.js.map +1 -0
- package/dist/utils/output.d.ts +55 -0
- package/dist/utils/output.d.ts.map +1 -0
- package/dist/utils/output.js +80 -0
- package/dist/utils/output.js.map +1 -0
- package/dist/utils/recent-workflows.d.ts +37 -0
- package/dist/utils/recent-workflows.d.ts.map +1 -0
- package/dist/utils/recent-workflows.js +172 -0
- package/dist/utils/recent-workflows.js.map +1 -0
- package/dist/utils/studio-api-client.d.ts +3 -0
- package/dist/utils/studio-api-client.d.ts.map +1 -0
- package/dist/utils/studio-api-client.js +3 -0
- package/dist/utils/studio-api-client.js.map +1 -0
- package/dist/utils/studio-api.d.ts +53 -0
- package/dist/utils/studio-api.d.ts.map +1 -0
- package/dist/utils/studio-api.js +102 -0
- package/dist/utils/studio-api.js.map +1 -0
- package/dist/utils/studio-config.d.ts +74 -0
- package/dist/utils/studio-config.d.ts.map +1 -0
- package/dist/utils/studio-config.js +213 -0
- package/dist/utils/studio-config.js.map +1 -0
- package/dist/utils/token-manager.d.ts +4 -0
- package/dist/utils/token-manager.d.ts.map +1 -0
- package/dist/utils/token-manager.js +3 -0
- package/dist/utils/token-manager.js.map +1 -0
- package/dist/utils/ui.d.ts +55 -1
- package/dist/utils/ui.d.ts.map +1 -1
- package/dist/utils/ui.js +151 -2
- package/dist/utils/ui.js.map +1 -1
- package/package.json +4 -1
- package/dist/__tests__/config-schema.test.d.ts +0 -2
- package/dist/__tests__/config-schema.test.d.ts.map +0 -1
- package/dist/__tests__/config-schema.test.js +0 -471
- package/dist/__tests__/config-schema.test.js.map +0 -1
- package/dist/__tests__/config.test.d.ts +0 -2
- package/dist/__tests__/config.test.d.ts.map +0 -1
- package/dist/__tests__/config.test.js +0 -75
- package/dist/__tests__/config.test.js.map +0 -1
- package/dist/__tests__/integration/configure.test.d.ts +0 -2
- package/dist/__tests__/integration/configure.test.d.ts.map +0 -1
- package/dist/__tests__/integration/configure.test.js +0 -247
- package/dist/__tests__/integration/configure.test.js.map +0 -1
- package/dist/__tests__/integration/fixtures/configs.d.ts +0 -477
- package/dist/__tests__/integration/fixtures/configs.d.ts.map +0 -1
- package/dist/__tests__/integration/fixtures/configs.js +0 -175
- package/dist/__tests__/integration/fixtures/configs.js.map +0 -1
- package/dist/__tests__/integration/helpers/cli-runner.d.ts +0 -63
- package/dist/__tests__/integration/helpers/cli-runner.d.ts.map +0 -1
- package/dist/__tests__/integration/helpers/cli-runner.js +0 -152
- package/dist/__tests__/integration/helpers/cli-runner.js.map +0 -1
- package/dist/__tests__/integration/helpers/command-runner.d.ts +0 -53
- package/dist/__tests__/integration/helpers/command-runner.d.ts.map +0 -1
- package/dist/__tests__/integration/helpers/command-runner.js +0 -117
- package/dist/__tests__/integration/helpers/command-runner.js.map +0 -1
- package/dist/__tests__/integration/studio-create.test.d.ts +0 -2
- package/dist/__tests__/integration/studio-create.test.d.ts.map +0 -1
- package/dist/__tests__/integration/studio-create.test.js +0 -209
- package/dist/__tests__/integration/studio-create.test.js.map +0 -1
- package/dist/__tests__/integration/studio-update.test.d.ts +0 -2
- package/dist/__tests__/integration/studio-update.test.d.ts.map +0 -1
- package/dist/__tests__/integration/studio-update.test.js +0 -166
- package/dist/__tests__/integration/studio-update.test.js.map +0 -1
- package/dist/commands/__tests__/configure.test.d.ts +0 -2
- package/dist/commands/__tests__/configure.test.d.ts.map +0 -1
- package/dist/commands/__tests__/configure.test.js +0 -229
- package/dist/commands/__tests__/configure.test.js.map +0 -1
- package/dist/prompts/__tests__/environment-setup.test.d.ts +0 -2
- package/dist/prompts/__tests__/environment-setup.test.d.ts.map +0 -1
- package/dist/prompts/__tests__/environment-setup.test.js +0 -206
- package/dist/prompts/__tests__/environment-setup.test.js.map +0 -1
- package/dist/prompts/__tests__/hub-integration.test.d.ts +0 -2
- package/dist/prompts/__tests__/hub-integration.test.d.ts.map +0 -1
- package/dist/prompts/__tests__/hub-integration.test.js +0 -126
- package/dist/prompts/__tests__/hub-integration.test.js.map +0 -1
- package/dist/prompts/__tests__/prompt-helpers.test.d.ts +0 -2
- package/dist/prompts/__tests__/prompt-helpers.test.d.ts.map +0 -1
- package/dist/prompts/__tests__/prompt-helpers.test.js +0 -235
- package/dist/prompts/__tests__/prompt-helpers.test.js.map +0 -1
- package/dist/sembix-cli-1.3.0.tgz +0 -0
- package/dist/utils/__tests__/config-file.test.d.ts +0 -2
- package/dist/utils/__tests__/config-file.test.d.ts.map +0 -1
- package/dist/utils/__tests__/config-file.test.js +0 -218
- package/dist/utils/__tests__/config-file.test.js.map +0 -1
- package/dist/utils/__tests__/config-loader.test.d.ts +0 -2
- package/dist/utils/__tests__/config-loader.test.d.ts.map +0 -1
- package/dist/utils/__tests__/config-loader.test.js +0 -325
- package/dist/utils/__tests__/config-loader.test.js.map +0 -1
- package/dist/utils/__tests__/github.test.d.ts +0 -2
- package/dist/utils/__tests__/github.test.d.ts.map +0 -1
- package/dist/utils/__tests__/github.test.js +0 -282
- package/dist/utils/__tests__/github.test.js.map +0 -1
- package/dist/utils/__tests__/ui.test.d.ts +0 -2
- package/dist/utils/__tests__/ui.test.d.ts.map +0 -1
- package/dist/utils/__tests__/ui.test.js +0 -256
- package/dist/utils/__tests__/ui.test.js.map +0 -1
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
const CACHE_DIR = join(homedir(), '.sembix');
|
|
6
|
+
const CACHE_FILE = join(CACHE_DIR, 'recent-workflows.json');
|
|
7
|
+
const MAX_ENTRIES = 50;
|
|
8
|
+
const MAX_ENTRIES_PER_PROFILE = 10;
|
|
9
|
+
const CACHE_VERSION = '1.0';
|
|
10
|
+
/**
|
|
11
|
+
* Adds or updates a recent workflow entry
|
|
12
|
+
* Increments use count if entry already exists
|
|
13
|
+
*/
|
|
14
|
+
export async function addRecentWorkflow(profileName, projectId, projectName, workflowId, workflowName) {
|
|
15
|
+
const cache = await loadCache();
|
|
16
|
+
// Find existing entry
|
|
17
|
+
const existingIndex = cache.entries.findIndex(e => e.profileName === profileName &&
|
|
18
|
+
e.projectId === projectId &&
|
|
19
|
+
e.workflowId === workflowId);
|
|
20
|
+
if (existingIndex >= 0) {
|
|
21
|
+
// Update existing entry
|
|
22
|
+
cache.entries[existingIndex].lastUsed = new Date().toISOString();
|
|
23
|
+
cache.entries[existingIndex].useCount++;
|
|
24
|
+
cache.entries[existingIndex].projectName = projectName; // update in case changed
|
|
25
|
+
cache.entries[existingIndex].workflowName = workflowName; // update in case changed
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Add new entry
|
|
29
|
+
cache.entries.push({
|
|
30
|
+
profileName,
|
|
31
|
+
projectId,
|
|
32
|
+
projectName,
|
|
33
|
+
workflowId,
|
|
34
|
+
workflowName,
|
|
35
|
+
lastUsed: new Date().toISOString(),
|
|
36
|
+
useCount: 1
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Evict old entries if needed
|
|
40
|
+
await evictOldEntries(cache);
|
|
41
|
+
await saveCache(cache);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Gets recent workflows for a profile, optionally filtered by project
|
|
45
|
+
* Sorted by use count (desc) then last used (desc)
|
|
46
|
+
*/
|
|
47
|
+
export async function getRecentWorkflows(profileName, projectId, limit = 10) {
|
|
48
|
+
const cache = await loadCache();
|
|
49
|
+
let filtered = cache.entries.filter(e => e.profileName === profileName);
|
|
50
|
+
if (projectId) {
|
|
51
|
+
filtered = filtered.filter(e => e.projectId === projectId);
|
|
52
|
+
}
|
|
53
|
+
// Sort by useCount (desc), then lastUsed (desc)
|
|
54
|
+
filtered.sort((a, b) => {
|
|
55
|
+
if (b.useCount !== a.useCount) {
|
|
56
|
+
return b.useCount - a.useCount;
|
|
57
|
+
}
|
|
58
|
+
return new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime();
|
|
59
|
+
});
|
|
60
|
+
return filtered.slice(0, limit);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Gets recent projects for a profile
|
|
64
|
+
* Returns unique projects sorted by most recently used workflow
|
|
65
|
+
*/
|
|
66
|
+
export async function getRecentProjects(profileName, limit = 5) {
|
|
67
|
+
const cache = await loadCache();
|
|
68
|
+
const filtered = cache.entries.filter(e => e.profileName === profileName);
|
|
69
|
+
// Group by project and get most recent usage
|
|
70
|
+
const projectMap = new Map();
|
|
71
|
+
for (const entry of filtered) {
|
|
72
|
+
const existing = projectMap.get(entry.projectId);
|
|
73
|
+
if (!existing || new Date(entry.lastUsed) > new Date(existing.lastUsed)) {
|
|
74
|
+
projectMap.set(entry.projectId, {
|
|
75
|
+
projectId: entry.projectId,
|
|
76
|
+
projectName: entry.projectName,
|
|
77
|
+
lastUsed: entry.lastUsed
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
// Convert to array and sort by most recent
|
|
82
|
+
const projects = Array.from(projectMap.values());
|
|
83
|
+
projects.sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
84
|
+
return projects.slice(0, limit);
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Clears all cached workflows for a specific profile
|
|
88
|
+
*/
|
|
89
|
+
export async function clearCacheForProfile(profileName) {
|
|
90
|
+
const cache = await loadCache();
|
|
91
|
+
cache.entries = cache.entries.filter(e => e.profileName !== profileName);
|
|
92
|
+
await saveCache(cache);
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Clears the entire cache
|
|
96
|
+
*/
|
|
97
|
+
export async function clearCache() {
|
|
98
|
+
if (existsSync(CACHE_FILE)) {
|
|
99
|
+
await fs.unlink(CACHE_FILE);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Evicts old entries based on LRU and per-profile limits
|
|
104
|
+
*/
|
|
105
|
+
async function evictOldEntries(cache) {
|
|
106
|
+
// Overall limit - keep most recently used
|
|
107
|
+
if (cache.entries.length > MAX_ENTRIES) {
|
|
108
|
+
cache.entries.sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
109
|
+
cache.entries = cache.entries.slice(0, MAX_ENTRIES);
|
|
110
|
+
}
|
|
111
|
+
// Per-profile limit - keep most frequently used within each profile
|
|
112
|
+
const profileGroups = new Map();
|
|
113
|
+
for (const entry of cache.entries) {
|
|
114
|
+
if (!profileGroups.has(entry.profileName)) {
|
|
115
|
+
profileGroups.set(entry.profileName, []);
|
|
116
|
+
}
|
|
117
|
+
profileGroups.get(entry.profileName).push(entry);
|
|
118
|
+
}
|
|
119
|
+
const kept = [];
|
|
120
|
+
for (const [, entries] of profileGroups) {
|
|
121
|
+
// Sort by useCount (desc), then lastUsed (desc)
|
|
122
|
+
entries.sort((a, b) => {
|
|
123
|
+
if (b.useCount !== a.useCount)
|
|
124
|
+
return b.useCount - a.useCount;
|
|
125
|
+
return new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime();
|
|
126
|
+
});
|
|
127
|
+
kept.push(...entries.slice(0, MAX_ENTRIES_PER_PROFILE));
|
|
128
|
+
}
|
|
129
|
+
cache.entries = kept;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Loads the cache from disk
|
|
133
|
+
* Returns empty cache if file doesn't exist or can't be parsed
|
|
134
|
+
*/
|
|
135
|
+
async function loadCache() {
|
|
136
|
+
try {
|
|
137
|
+
if (!existsSync(CACHE_FILE)) {
|
|
138
|
+
return { version: CACHE_VERSION, entries: [] };
|
|
139
|
+
}
|
|
140
|
+
const content = await fs.readFile(CACHE_FILE, 'utf-8');
|
|
141
|
+
const cache = JSON.parse(content);
|
|
142
|
+
// Validate version and structure
|
|
143
|
+
if (!cache.version || !Array.isArray(cache.entries)) {
|
|
144
|
+
return { version: CACHE_VERSION, entries: [] };
|
|
145
|
+
}
|
|
146
|
+
return cache;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
// If we can't read or parse the cache, return empty cache
|
|
150
|
+
return { version: CACHE_VERSION, entries: [] };
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Saves the cache to disk with restricted permissions
|
|
155
|
+
*/
|
|
156
|
+
async function saveCache(cache) {
|
|
157
|
+
try {
|
|
158
|
+
// Ensure directory exists
|
|
159
|
+
if (!existsSync(CACHE_DIR)) {
|
|
160
|
+
await fs.mkdir(CACHE_DIR, { recursive: true, mode: 0o700 });
|
|
161
|
+
}
|
|
162
|
+
// Write cache file with restricted permissions (only user can read/write)
|
|
163
|
+
const content = JSON.stringify(cache, null, 2);
|
|
164
|
+
await fs.writeFile(CACHE_FILE, content, { mode: 0o600 });
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
// Silently fail if we can't write the cache
|
|
168
|
+
// This shouldn't break the CLI functionality
|
|
169
|
+
console.error('Warning: Failed to save recent workflows cache:', error instanceof Error ? error.message : 'Unknown error');
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
//# sourceMappingURL=recent-workflows.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recent-workflows.js","sourceRoot":"","sources":["../../src/utils/recent-workflows.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { StudioApiClient } from '../services/studio-api-client.js';
|
|
2
|
+
export type { StudioProfile, StudioAuthTokens, StartWorkflowConfiguration, WorkflowStartResponse, FetchWorkflowRunResponse, FetchWorkflowRunListItem, SearchParams } from '../types.js';
|
|
3
|
+
//# sourceMappingURL=studio-api-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio-api-client.d.ts","sourceRoot":"","sources":["../../src/utils/studio-api-client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGnE,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EACb,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio-api-client.js","sourceRoot":"","sources":["../../src/utils/studio-api-client.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { StudioApiClient } from '../services/studio-api-client.js';
|
|
2
|
+
import type { StudioProfile, StudioAuthTokens, StartWorkflowConfiguration, WorkflowStartResponse, FetchWorkflowRunResponse, FetchWorkflowRunListItem, SearchParams } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a Studio API client with automatic token refresh handling.
|
|
5
|
+
*
|
|
6
|
+
* This factory function:
|
|
7
|
+
* 1. Loads the specified profile (or default) and validates authentication
|
|
8
|
+
* 2. Creates a StudioApiClient instance
|
|
9
|
+
* 3. Wraps API calls to handle token refresh on 401 errors
|
|
10
|
+
*
|
|
11
|
+
* @param profileName - Optional profile name (defaults to active profile)
|
|
12
|
+
* @returns StudioApiClient instance with token refresh capability
|
|
13
|
+
* @throws Error if profile not found or tokens invalid/expired
|
|
14
|
+
*/
|
|
15
|
+
export declare function createStudioApiClient(profileName?: string): Promise<StudioApiClient>;
|
|
16
|
+
/**
|
|
17
|
+
* Convenience function to start a workflow execution.
|
|
18
|
+
*
|
|
19
|
+
* @param projectId - Project ID containing the workflow
|
|
20
|
+
* @param workflowId - Workflow ID to execute
|
|
21
|
+
* @param startConfiguration - Workflow input configuration
|
|
22
|
+
* @param profileName - Optional profile name
|
|
23
|
+
* @returns Workflow start response with run ID and task ARN
|
|
24
|
+
*/
|
|
25
|
+
export declare function startWorkflow(projectId: string, workflowId: string, startConfiguration: StartWorkflowConfiguration, profileName?: string): Promise<WorkflowStartResponse>;
|
|
26
|
+
/**
|
|
27
|
+
* Convenience function to get workflow run details.
|
|
28
|
+
*
|
|
29
|
+
* @param workflowId - Workflow ID
|
|
30
|
+
* @param runId - Run ID to fetch
|
|
31
|
+
* @param profileName - Optional profile name
|
|
32
|
+
* @returns Workflow run details
|
|
33
|
+
*/
|
|
34
|
+
export declare function getWorkflowRun(workflowId: string, runId: string, profileName?: string): Promise<FetchWorkflowRunResponse>;
|
|
35
|
+
/**
|
|
36
|
+
* Convenience function to search workflow runs.
|
|
37
|
+
*
|
|
38
|
+
* @param params - Search parameters (filters, pagination, sorting)
|
|
39
|
+
* @param profileName - Optional profile name
|
|
40
|
+
* @returns List of workflow runs matching search criteria
|
|
41
|
+
*/
|
|
42
|
+
export declare function searchWorkflowRuns(params: SearchParams, profileName?: string): Promise<FetchWorkflowRunListItem>;
|
|
43
|
+
/**
|
|
44
|
+
* Convenience function to stop a running workflow.
|
|
45
|
+
*
|
|
46
|
+
* @param projectId - Project ID containing the workflow
|
|
47
|
+
* @param workflowId - Workflow ID
|
|
48
|
+
* @param runId - Run ID to stop
|
|
49
|
+
* @param profileName - Optional profile name
|
|
50
|
+
*/
|
|
51
|
+
export declare function stopWorkflowRun(projectId: string, workflowId: string, runId: string, profileName?: string): Promise<void>;
|
|
52
|
+
export type { StudioProfile, StudioAuthTokens, StartWorkflowConfiguration, WorkflowStartResponse, FetchWorkflowRunResponse, FetchWorkflowRunListItem, SearchParams };
|
|
53
|
+
//# sourceMappingURL=studio-api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio-api.d.ts","sourceRoot":"","sources":["../../src/utils/studio-api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAOnE,OAAO,KAAK,EACV,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EACb,MAAM,aAAa,CAAC;AAErB;;;;;;;;;;;GAWG;AACH,wBAAsB,qBAAqB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CA+C1F;AAED;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,kBAAkB,EAAE,0BAA0B,EAC9C,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,qBAAqB,CAAC,CAGhC;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,CAAC,CAGnC;AAED;;;;;;GAMG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,wBAAwB,CAAC,CAGnC;AAED;;;;;;;GAOG;AACH,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,KAAK,EAAE,MAAM,EACb,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAGD,YAAY,EACV,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,YAAY,EACb,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Service layer imports
|
|
2
|
+
import { StudioApiClient } from '../services/studio-api-client.js';
|
|
3
|
+
import { CognitoAuthService } from '../services/cognito-auth.js';
|
|
4
|
+
// Utility imports
|
|
5
|
+
import { getAuthenticatedProfile, saveTokens } from './studio-config.js';
|
|
6
|
+
/**
|
|
7
|
+
* Creates a Studio API client with automatic token refresh handling.
|
|
8
|
+
*
|
|
9
|
+
* This factory function:
|
|
10
|
+
* 1. Loads the specified profile (or default) and validates authentication
|
|
11
|
+
* 2. Creates a StudioApiClient instance
|
|
12
|
+
* 3. Wraps API calls to handle token refresh on 401 errors
|
|
13
|
+
*
|
|
14
|
+
* @param profileName - Optional profile name (defaults to active profile)
|
|
15
|
+
* @returns StudioApiClient instance with token refresh capability
|
|
16
|
+
* @throws Error if profile not found or tokens invalid/expired
|
|
17
|
+
*/
|
|
18
|
+
export async function createStudioApiClient(profileName) {
|
|
19
|
+
const { profile, tokens } = await getAuthenticatedProfile(profileName);
|
|
20
|
+
// Create base client
|
|
21
|
+
const client = new StudioApiClient(profile, tokens);
|
|
22
|
+
// Wrap client methods to handle token refresh on 401
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
24
|
+
const originalRequest = client._makeRequest.bind(client);
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
26
|
+
client._makeRequest = async function (method, path, body, queryParams) {
|
|
27
|
+
try {
|
|
28
|
+
return await originalRequest(method, path, body, queryParams);
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
// If 401 error, attempt token refresh and retry
|
|
32
|
+
const errorWithStatus = error;
|
|
33
|
+
if (errorWithStatus.statusCode === 401) {
|
|
34
|
+
try {
|
|
35
|
+
const authService = new CognitoAuthService(profile);
|
|
36
|
+
const newTokens = await authService.refreshTokens(tokens.refreshToken);
|
|
37
|
+
// Save refreshed tokens
|
|
38
|
+
await saveTokens(profile.name, newTokens);
|
|
39
|
+
// Update client tokens
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
client.tokens = newTokens;
|
|
42
|
+
// Retry original request with new tokens
|
|
43
|
+
return await originalRequest(method, path, body, queryParams);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error(`Authentication failed and token refresh unsuccessful. Run "sembix login --profile ${profile.name}" to re-authenticate.`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
throw error;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
return client;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Convenience function to start a workflow execution.
|
|
56
|
+
*
|
|
57
|
+
* @param projectId - Project ID containing the workflow
|
|
58
|
+
* @param workflowId - Workflow ID to execute
|
|
59
|
+
* @param startConfiguration - Workflow input configuration
|
|
60
|
+
* @param profileName - Optional profile name
|
|
61
|
+
* @returns Workflow start response with run ID and task ARN
|
|
62
|
+
*/
|
|
63
|
+
export async function startWorkflow(projectId, workflowId, startConfiguration, profileName) {
|
|
64
|
+
const client = await createStudioApiClient(profileName);
|
|
65
|
+
return client.startWorkflow(projectId, workflowId, startConfiguration);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Convenience function to get workflow run details.
|
|
69
|
+
*
|
|
70
|
+
* @param workflowId - Workflow ID
|
|
71
|
+
* @param runId - Run ID to fetch
|
|
72
|
+
* @param profileName - Optional profile name
|
|
73
|
+
* @returns Workflow run details
|
|
74
|
+
*/
|
|
75
|
+
export async function getWorkflowRun(workflowId, runId, profileName) {
|
|
76
|
+
const client = await createStudioApiClient(profileName);
|
|
77
|
+
return client.getWorkflowRun(workflowId, runId);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Convenience function to search workflow runs.
|
|
81
|
+
*
|
|
82
|
+
* @param params - Search parameters (filters, pagination, sorting)
|
|
83
|
+
* @param profileName - Optional profile name
|
|
84
|
+
* @returns List of workflow runs matching search criteria
|
|
85
|
+
*/
|
|
86
|
+
export async function searchWorkflowRuns(params, profileName) {
|
|
87
|
+
const client = await createStudioApiClient(profileName);
|
|
88
|
+
return client.searchWorkflowRuns(params);
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Convenience function to stop a running workflow.
|
|
92
|
+
*
|
|
93
|
+
* @param projectId - Project ID containing the workflow
|
|
94
|
+
* @param workflowId - Workflow ID
|
|
95
|
+
* @param runId - Run ID to stop
|
|
96
|
+
* @param profileName - Optional profile name
|
|
97
|
+
*/
|
|
98
|
+
export async function stopWorkflowRun(projectId, workflowId, runId, profileName) {
|
|
99
|
+
const client = await createStudioApiClient(profileName);
|
|
100
|
+
return client.stopWorkflowRun(projectId, workflowId, runId);
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=studio-api.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio-api.js","sourceRoot":"","sources":["../../src/utils/studio-api.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
export { readProfile, writeProfile, listProfiles, getDefaultProfile, setDefaultProfile, deleteProfile, type StudioProfile, type StudioConfig } from './config-file.js';
|
|
2
|
+
import type { StudioAuthTokens } from '../types.js';
|
|
3
|
+
import type { StudioProfile } from './config-file.js';
|
|
4
|
+
/**
|
|
5
|
+
* Saves authentication tokens for a profile
|
|
6
|
+
* Tokens are stored in ~/.sembix/tokens/{profile-name}.json with 0o600 permissions
|
|
7
|
+
*
|
|
8
|
+
* @param profileName - Name of the profile
|
|
9
|
+
* @param tokens - Authentication tokens to save
|
|
10
|
+
*/
|
|
11
|
+
export declare function saveTokens(profileName: string, tokens: StudioAuthTokens): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Loads authentication tokens for a profile
|
|
14
|
+
* Returns undefined if tokens don't exist or file cannot be read
|
|
15
|
+
*
|
|
16
|
+
* @param profileName - Name of the profile
|
|
17
|
+
* @returns Authentication tokens or undefined if not found
|
|
18
|
+
*/
|
|
19
|
+
export declare function loadTokens(profileName: string): Promise<StudioAuthTokens | undefined>;
|
|
20
|
+
/**
|
|
21
|
+
* Deletes stored authentication tokens for a profile
|
|
22
|
+
*
|
|
23
|
+
* @param profileName - Name of the profile
|
|
24
|
+
*/
|
|
25
|
+
export declare function deleteTokens(profileName: string): Promise<void>;
|
|
26
|
+
/**
|
|
27
|
+
* Checks if authentication tokens are still valid based on expiration time
|
|
28
|
+
*
|
|
29
|
+
* @param tokens - Authentication tokens to validate
|
|
30
|
+
* @returns true if tokens are valid and not expired
|
|
31
|
+
*/
|
|
32
|
+
export declare function isTokenValid(tokens: StudioAuthTokens): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Lists all profiles that have stored authentication tokens
|
|
35
|
+
*
|
|
36
|
+
* @returns Array of profile names with stored tokens
|
|
37
|
+
*/
|
|
38
|
+
export declare function listTokenProfiles(): Promise<string[]>;
|
|
39
|
+
/**
|
|
40
|
+
* Gets token information for a profile without exposing the token values
|
|
41
|
+
* Useful for displaying token status to users
|
|
42
|
+
*
|
|
43
|
+
* @param profileName - Name of the profile
|
|
44
|
+
* @returns Object with token status information or undefined if no tokens exist
|
|
45
|
+
*/
|
|
46
|
+
export declare function getTokenInfo(profileName: string): Promise<{
|
|
47
|
+
expiresAt: string;
|
|
48
|
+
isValid: boolean;
|
|
49
|
+
} | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Gets the active Studio profile, using the specified profile name or falling back to default
|
|
52
|
+
* Throws an error if no profile is found
|
|
53
|
+
*
|
|
54
|
+
* @param profileName - Optional profile name to use
|
|
55
|
+
* @returns The active Studio profile
|
|
56
|
+
* @throws Error if no profile is configured
|
|
57
|
+
*/
|
|
58
|
+
export declare function getActiveProfile(profileName?: string): Promise<StudioProfile>;
|
|
59
|
+
/**
|
|
60
|
+
* Gets the active profile with valid authentication tokens
|
|
61
|
+
* Supports multiple authentication methods with priority:
|
|
62
|
+
* 1. Client credentials (CI/CD)
|
|
63
|
+
* 2. Stored tokens (file-based)
|
|
64
|
+
* 3. Interactive login (if TTY available)
|
|
65
|
+
*
|
|
66
|
+
* @param profileName - Optional profile name to use
|
|
67
|
+
* @returns Object containing the profile and valid tokens
|
|
68
|
+
* @throws Error if authentication fails
|
|
69
|
+
*/
|
|
70
|
+
export declare function getAuthenticatedProfile(profileName?: string): Promise<{
|
|
71
|
+
profile: StudioProfile;
|
|
72
|
+
tokens: StudioAuthTokens;
|
|
73
|
+
}>;
|
|
74
|
+
//# sourceMappingURL=studio-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"studio-config.d.ts","sourceRoot":"","sources":["../../src/utils/studio-config.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,KAAK,aAAa,EAClB,KAAK,YAAY,EAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAwBtD;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAK7F;AAED;;;;;;GAMG;AACH,wBAAsB,UAAU,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAW3F;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CASrE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAU9D;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAY3D;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,CAAC,CASpH;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAmBnF;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,uBAAuB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IAC3E,OAAO,EAAE,aAAa,CAAC;IACvB,MAAM,EAAE,gBAAgB,CAAC;CAC1B,CAAC,CAqED"}
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
import { homedir } from 'os';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { promises as fs } from 'fs';
|
|
4
|
+
import { existsSync } from 'fs';
|
|
5
|
+
// Re-export profile management functions from config-file
|
|
6
|
+
export { readProfile, writeProfile, listProfiles, getDefaultProfile, setDefaultProfile, deleteProfile } from './config-file.js';
|
|
7
|
+
import { readProfile, getDefaultProfile } from './config-file.js';
|
|
8
|
+
import { hasClientCredentials, isInteractive } from './environment.js';
|
|
9
|
+
import { CognitoAuthService } from '../services/cognito-auth.js';
|
|
10
|
+
// Token storage directory
|
|
11
|
+
const TOKENS_DIR = join(homedir(), '.sembix', 'tokens');
|
|
12
|
+
/**
|
|
13
|
+
* Ensures the tokens directory exists with secure permissions
|
|
14
|
+
*/
|
|
15
|
+
async function ensureTokensDirectory() {
|
|
16
|
+
if (!existsSync(TOKENS_DIR)) {
|
|
17
|
+
await fs.mkdir(TOKENS_DIR, { recursive: true, mode: 0o700 });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Gets the file path for a profile's token storage
|
|
22
|
+
*/
|
|
23
|
+
function getTokenFilePath(profileName) {
|
|
24
|
+
return join(TOKENS_DIR, `${profileName}.json`);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Saves authentication tokens for a profile
|
|
28
|
+
* Tokens are stored in ~/.sembix/tokens/{profile-name}.json with 0o600 permissions
|
|
29
|
+
*
|
|
30
|
+
* @param profileName - Name of the profile
|
|
31
|
+
* @param tokens - Authentication tokens to save
|
|
32
|
+
*/
|
|
33
|
+
export async function saveTokens(profileName, tokens) {
|
|
34
|
+
await ensureTokensDirectory();
|
|
35
|
+
const tokenFile = getTokenFilePath(profileName);
|
|
36
|
+
const content = JSON.stringify(tokens, null, 2);
|
|
37
|
+
await fs.writeFile(tokenFile, content, { mode: 0o600 });
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Loads authentication tokens for a profile
|
|
41
|
+
* Returns undefined if tokens don't exist or file cannot be read
|
|
42
|
+
*
|
|
43
|
+
* @param profileName - Name of the profile
|
|
44
|
+
* @returns Authentication tokens or undefined if not found
|
|
45
|
+
*/
|
|
46
|
+
export async function loadTokens(profileName) {
|
|
47
|
+
try {
|
|
48
|
+
const tokenFile = getTokenFilePath(profileName);
|
|
49
|
+
if (!existsSync(tokenFile)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
const content = await fs.readFile(tokenFile, 'utf-8');
|
|
53
|
+
return JSON.parse(content);
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Deletes stored authentication tokens for a profile
|
|
61
|
+
*
|
|
62
|
+
* @param profileName - Name of the profile
|
|
63
|
+
*/
|
|
64
|
+
export async function deleteTokens(profileName) {
|
|
65
|
+
try {
|
|
66
|
+
const tokenFile = getTokenFilePath(profileName);
|
|
67
|
+
if (existsSync(tokenFile)) {
|
|
68
|
+
await fs.unlink(tokenFile);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
// Ignore errors if file doesn't exist
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks if authentication tokens are still valid based on expiration time
|
|
77
|
+
*
|
|
78
|
+
* @param tokens - Authentication tokens to validate
|
|
79
|
+
* @returns true if tokens are valid and not expired
|
|
80
|
+
*/
|
|
81
|
+
export function isTokenValid(tokens) {
|
|
82
|
+
try {
|
|
83
|
+
const expiresAt = new Date(tokens.expiresAt);
|
|
84
|
+
const now = new Date();
|
|
85
|
+
// Add 5 minute buffer to account for clock skew and request time
|
|
86
|
+
const bufferMs = 5 * 60 * 1000;
|
|
87
|
+
return expiresAt.getTime() - now.getTime() > bufferMs;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Lists all profiles that have stored authentication tokens
|
|
95
|
+
*
|
|
96
|
+
* @returns Array of profile names with stored tokens
|
|
97
|
+
*/
|
|
98
|
+
export async function listTokenProfiles() {
|
|
99
|
+
try {
|
|
100
|
+
if (!existsSync(TOKENS_DIR)) {
|
|
101
|
+
return [];
|
|
102
|
+
}
|
|
103
|
+
const files = await fs.readdir(TOKENS_DIR);
|
|
104
|
+
return files
|
|
105
|
+
.filter(file => file.endsWith('.json'))
|
|
106
|
+
.map(file => file.replace('.json', ''));
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Gets token information for a profile without exposing the token values
|
|
114
|
+
* Useful for displaying token status to users
|
|
115
|
+
*
|
|
116
|
+
* @param profileName - Name of the profile
|
|
117
|
+
* @returns Object with token status information or undefined if no tokens exist
|
|
118
|
+
*/
|
|
119
|
+
export async function getTokenInfo(profileName) {
|
|
120
|
+
const tokens = await loadTokens(profileName);
|
|
121
|
+
if (!tokens) {
|
|
122
|
+
return undefined;
|
|
123
|
+
}
|
|
124
|
+
return {
|
|
125
|
+
expiresAt: tokens.expiresAt,
|
|
126
|
+
isValid: isTokenValid(tokens)
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Gets the active Studio profile, using the specified profile name or falling back to default
|
|
131
|
+
* Throws an error if no profile is found
|
|
132
|
+
*
|
|
133
|
+
* @param profileName - Optional profile name to use
|
|
134
|
+
* @returns The active Studio profile
|
|
135
|
+
* @throws Error if no profile is configured
|
|
136
|
+
*/
|
|
137
|
+
export async function getActiveProfile(profileName) {
|
|
138
|
+
// Try to get the specified profile or default profile
|
|
139
|
+
const targetProfile = profileName || await getDefaultProfile();
|
|
140
|
+
if (!targetProfile) {
|
|
141
|
+
throw new Error('No Studio profile configured. Run "sembix configure" to set up a profile.');
|
|
142
|
+
}
|
|
143
|
+
const profile = await readProfile(targetProfile);
|
|
144
|
+
if (!profile) {
|
|
145
|
+
throw new Error(`Profile "${targetProfile}" not found. Run "sembix profile list" to see available profiles.`);
|
|
146
|
+
}
|
|
147
|
+
return profile;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Gets the active profile with valid authentication tokens
|
|
151
|
+
* Supports multiple authentication methods with priority:
|
|
152
|
+
* 1. Client credentials (CI/CD)
|
|
153
|
+
* 2. Stored tokens (file-based)
|
|
154
|
+
* 3. Interactive login (if TTY available)
|
|
155
|
+
*
|
|
156
|
+
* @param profileName - Optional profile name to use
|
|
157
|
+
* @returns Object containing the profile and valid tokens
|
|
158
|
+
* @throws Error if authentication fails
|
|
159
|
+
*/
|
|
160
|
+
export async function getAuthenticatedProfile(profileName) {
|
|
161
|
+
const profile = await getActiveProfile(profileName);
|
|
162
|
+
// Priority 1: Check for client credentials (CI/CD)
|
|
163
|
+
if (hasClientCredentials()) {
|
|
164
|
+
const clientId = process.env.SEMBIX_CLIENT_ID;
|
|
165
|
+
const clientSecret = process.env.SEMBIX_CLIENT_SECRET;
|
|
166
|
+
try {
|
|
167
|
+
const authService = new CognitoAuthService(profile);
|
|
168
|
+
const tokens = await authService.authenticateWithClientCredentials(clientId, clientSecret);
|
|
169
|
+
return { profile, tokens };
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
throw new Error(`Client credentials authentication failed: ${error instanceof Error ? error.message : String(error)}\n\n` +
|
|
173
|
+
`Check that SEMBIX_CLIENT_ID and SEMBIX_CLIENT_SECRET are correct.`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// Priority 2: Load stored tokens
|
|
177
|
+
let tokens = await loadTokens(profile.name);
|
|
178
|
+
if (!tokens) {
|
|
179
|
+
// No stored tokens - guide user based on environment
|
|
180
|
+
if (isInteractive()) {
|
|
181
|
+
throw new Error(`No authentication tokens found for profile "${profile.name}".\n\n` +
|
|
182
|
+
`Run: sembix login --profile ${profile.name}`);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
throw new Error(`No authentication tokens found for profile "${profile.name}".\n\n` +
|
|
186
|
+
`For CI/CD environments, set these environment variables:\n` +
|
|
187
|
+
` SEMBIX_CLIENT_ID=<your-m2m-client-id>\n` +
|
|
188
|
+
` SEMBIX_CLIENT_SECRET=<your-m2m-client-secret>\n\n` +
|
|
189
|
+
`For interactive environments, run: sembix login --profile ${profile.name}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
// Validate token expiry
|
|
193
|
+
if (!isTokenValid(tokens)) {
|
|
194
|
+
// Try to refresh if we have a refresh token
|
|
195
|
+
if (tokens.refreshToken) {
|
|
196
|
+
try {
|
|
197
|
+
const authService = new CognitoAuthService(profile);
|
|
198
|
+
tokens = await authService.refreshTokens(tokens.refreshToken);
|
|
199
|
+
await saveTokens(profile.name, tokens);
|
|
200
|
+
return { profile, tokens };
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
// Refresh failed - need to re-authenticate
|
|
204
|
+
throw new Error(`Authentication tokens for profile "${profile.name}" have expired and could not be refreshed.\n\n` +
|
|
205
|
+
`Run: sembix login --profile ${profile.name}`);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
throw new Error(`Authentication tokens for profile "${profile.name}" have expired.\n\n` +
|
|
209
|
+
`Run: sembix login --profile ${profile.name}`);
|
|
210
|
+
}
|
|
211
|
+
return { profile, tokens };
|
|
212
|
+
}
|
|
213
|
+
//# sourceMappingURL=studio-config.js.map
|