@constructive-io/cli 6.0.4 → 6.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/commands/auth.d.ts +6 -0
- package/commands/auth.js +207 -0
- package/commands/codegen.js +3 -0
- package/commands/context.d.ts +7 -0
- package/commands/context.js +233 -0
- package/commands/execute.d.ts +6 -0
- package/commands/execute.js +136 -0
- package/commands.js +6 -0
- package/config/config-manager.d.ts +72 -0
- package/config/config-manager.js +280 -0
- package/config/index.d.ts +5 -0
- package/config/index.js +21 -0
- package/config/types.d.ts +46 -0
- package/config/types.js +10 -0
- package/esm/commands/auth.js +202 -0
- package/esm/commands/codegen.js +3 -0
- package/esm/commands/context.js +228 -0
- package/esm/commands/execute.js +98 -0
- package/esm/commands.js +6 -0
- package/esm/config/config-manager.js +229 -0
- package/esm/config/index.js +5 -0
- package/esm/config/types.js +7 -0
- package/esm/sdk/client.js +66 -0
- package/esm/sdk/executor.js +44 -0
- package/esm/sdk/index.js +5 -0
- package/esm/utils/display.js +10 -0
- package/package.json +6 -5
- package/sdk/client.d.ts +33 -0
- package/sdk/client.js +70 -0
- package/sdk/executor.d.ts +21 -0
- package/sdk/executor.js +48 -0
- package/sdk/index.d.ts +5 -0
- package/sdk/index.js +21 -0
- package/utils/display.d.ts +1 -1
- package/utils/display.js +10 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration manager for the CNC execution engine
|
|
3
|
+
* Uses appstash for directory resolution
|
|
4
|
+
*/
|
|
5
|
+
import type { ContextConfig, GlobalSettings, Credentials, ContextCredentials } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Get the appstash directories for cnc
|
|
8
|
+
*/
|
|
9
|
+
export declare function getAppDirs(): import("appstash").AppStashResult;
|
|
10
|
+
/**
|
|
11
|
+
* Load global settings
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadSettings(): GlobalSettings;
|
|
14
|
+
/**
|
|
15
|
+
* Save global settings
|
|
16
|
+
*/
|
|
17
|
+
export declare function saveSettings(settings: GlobalSettings): void;
|
|
18
|
+
/**
|
|
19
|
+
* Load credentials
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadCredentials(): Credentials;
|
|
22
|
+
/**
|
|
23
|
+
* Save credentials
|
|
24
|
+
*/
|
|
25
|
+
export declare function saveCredentials(credentials: Credentials): void;
|
|
26
|
+
/**
|
|
27
|
+
* Load a context configuration
|
|
28
|
+
*/
|
|
29
|
+
export declare function loadContext(contextName: string): ContextConfig | null;
|
|
30
|
+
/**
|
|
31
|
+
* Save a context configuration
|
|
32
|
+
*/
|
|
33
|
+
export declare function saveContext(context: ContextConfig): void;
|
|
34
|
+
/**
|
|
35
|
+
* Delete a context configuration
|
|
36
|
+
*/
|
|
37
|
+
export declare function deleteContext(contextName: string): boolean;
|
|
38
|
+
/**
|
|
39
|
+
* List all context configurations
|
|
40
|
+
*/
|
|
41
|
+
export declare function listContexts(): ContextConfig[];
|
|
42
|
+
/**
|
|
43
|
+
* Get the current active context
|
|
44
|
+
*/
|
|
45
|
+
export declare function getCurrentContext(): ContextConfig | null;
|
|
46
|
+
/**
|
|
47
|
+
* Set the current active context
|
|
48
|
+
*/
|
|
49
|
+
export declare function setCurrentContext(contextName: string): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Create a new context configuration
|
|
52
|
+
*/
|
|
53
|
+
export declare function createContext(name: string, endpoint: string): ContextConfig;
|
|
54
|
+
/**
|
|
55
|
+
* Get credentials for a context
|
|
56
|
+
*/
|
|
57
|
+
export declare function getContextCredentials(contextName: string): ContextCredentials | null;
|
|
58
|
+
/**
|
|
59
|
+
* Set credentials for a context
|
|
60
|
+
*/
|
|
61
|
+
export declare function setContextCredentials(contextName: string, token: string, options?: {
|
|
62
|
+
expiresAt?: string;
|
|
63
|
+
refreshToken?: string;
|
|
64
|
+
}): void;
|
|
65
|
+
/**
|
|
66
|
+
* Remove credentials for a context
|
|
67
|
+
*/
|
|
68
|
+
export declare function removeContextCredentials(contextName: string): boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Check if a context has valid credentials
|
|
71
|
+
*/
|
|
72
|
+
export declare function hasValidCredentials(contextName: string): boolean;
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration manager for the CNC execution engine
|
|
4
|
+
* Uses appstash for directory resolution
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
18
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
19
|
+
}) : function(o, v) {
|
|
20
|
+
o["default"] = v;
|
|
21
|
+
});
|
|
22
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
23
|
+
var ownKeys = function(o) {
|
|
24
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
25
|
+
var ar = [];
|
|
26
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
27
|
+
return ar;
|
|
28
|
+
};
|
|
29
|
+
return ownKeys(o);
|
|
30
|
+
};
|
|
31
|
+
return function (mod) {
|
|
32
|
+
if (mod && mod.__esModule) return mod;
|
|
33
|
+
var result = {};
|
|
34
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
35
|
+
__setModuleDefault(result, mod);
|
|
36
|
+
return result;
|
|
37
|
+
};
|
|
38
|
+
})();
|
|
39
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
40
|
+
exports.getAppDirs = getAppDirs;
|
|
41
|
+
exports.loadSettings = loadSettings;
|
|
42
|
+
exports.saveSettings = saveSettings;
|
|
43
|
+
exports.loadCredentials = loadCredentials;
|
|
44
|
+
exports.saveCredentials = saveCredentials;
|
|
45
|
+
exports.loadContext = loadContext;
|
|
46
|
+
exports.saveContext = saveContext;
|
|
47
|
+
exports.deleteContext = deleteContext;
|
|
48
|
+
exports.listContexts = listContexts;
|
|
49
|
+
exports.getCurrentContext = getCurrentContext;
|
|
50
|
+
exports.setCurrentContext = setCurrentContext;
|
|
51
|
+
exports.createContext = createContext;
|
|
52
|
+
exports.getContextCredentials = getContextCredentials;
|
|
53
|
+
exports.setContextCredentials = setContextCredentials;
|
|
54
|
+
exports.removeContextCredentials = removeContextCredentials;
|
|
55
|
+
exports.hasValidCredentials = hasValidCredentials;
|
|
56
|
+
const fs = __importStar(require("fs"));
|
|
57
|
+
const path = __importStar(require("path"));
|
|
58
|
+
const appstash_1 = require("appstash");
|
|
59
|
+
const types_1 = require("./types");
|
|
60
|
+
const TOOL_NAME = 'cnc';
|
|
61
|
+
/**
|
|
62
|
+
* Get the appstash directories for cnc
|
|
63
|
+
*/
|
|
64
|
+
function getAppDirs() {
|
|
65
|
+
return (0, appstash_1.appstash)(TOOL_NAME, { ensure: true });
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get path to a config file
|
|
69
|
+
*/
|
|
70
|
+
function getConfigPath(filename) {
|
|
71
|
+
const dirs = getAppDirs();
|
|
72
|
+
return (0, appstash_1.resolve)(dirs, 'config', filename);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get path to a context config file
|
|
76
|
+
*/
|
|
77
|
+
function getContextConfigPath(contextName) {
|
|
78
|
+
const dirs = getAppDirs();
|
|
79
|
+
const contextsDir = (0, appstash_1.resolve)(dirs, 'config', 'contexts');
|
|
80
|
+
if (!fs.existsSync(contextsDir)) {
|
|
81
|
+
fs.mkdirSync(contextsDir, { recursive: true });
|
|
82
|
+
}
|
|
83
|
+
return path.join(contextsDir, `${contextName}.json`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Load global settings
|
|
87
|
+
*/
|
|
88
|
+
function loadSettings() {
|
|
89
|
+
const settingsPath = getConfigPath('settings.json');
|
|
90
|
+
if (fs.existsSync(settingsPath)) {
|
|
91
|
+
try {
|
|
92
|
+
const content = fs.readFileSync(settingsPath, 'utf8');
|
|
93
|
+
return { ...types_1.DEFAULT_SETTINGS, ...JSON.parse(content) };
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return types_1.DEFAULT_SETTINGS;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return types_1.DEFAULT_SETTINGS;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Save global settings
|
|
103
|
+
*/
|
|
104
|
+
function saveSettings(settings) {
|
|
105
|
+
const settingsPath = getConfigPath('settings.json');
|
|
106
|
+
const configDir = path.dirname(settingsPath);
|
|
107
|
+
if (!fs.existsSync(configDir)) {
|
|
108
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
109
|
+
}
|
|
110
|
+
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Load credentials
|
|
114
|
+
*/
|
|
115
|
+
function loadCredentials() {
|
|
116
|
+
const credentialsPath = getConfigPath('credentials.json');
|
|
117
|
+
if (fs.existsSync(credentialsPath)) {
|
|
118
|
+
try {
|
|
119
|
+
const content = fs.readFileSync(credentialsPath, 'utf8');
|
|
120
|
+
return JSON.parse(content);
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return { tokens: {} };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return { tokens: {} };
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Save credentials
|
|
130
|
+
*/
|
|
131
|
+
function saveCredentials(credentials) {
|
|
132
|
+
const credentialsPath = getConfigPath('credentials.json');
|
|
133
|
+
const configDir = path.dirname(credentialsPath);
|
|
134
|
+
if (!fs.existsSync(configDir)) {
|
|
135
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
136
|
+
}
|
|
137
|
+
fs.writeFileSync(credentialsPath, JSON.stringify(credentials, null, 2), {
|
|
138
|
+
mode: 0o600, // Read/write for owner only
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Load a context configuration
|
|
143
|
+
*/
|
|
144
|
+
function loadContext(contextName) {
|
|
145
|
+
const contextPath = getContextConfigPath(contextName);
|
|
146
|
+
if (fs.existsSync(contextPath)) {
|
|
147
|
+
try {
|
|
148
|
+
const content = fs.readFileSync(contextPath, 'utf8');
|
|
149
|
+
return JSON.parse(content);
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Save a context configuration
|
|
159
|
+
*/
|
|
160
|
+
function saveContext(context) {
|
|
161
|
+
const contextPath = getContextConfigPath(context.name);
|
|
162
|
+
fs.writeFileSync(contextPath, JSON.stringify(context, null, 2));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Delete a context configuration
|
|
166
|
+
*/
|
|
167
|
+
function deleteContext(contextName) {
|
|
168
|
+
const contextPath = getContextConfigPath(contextName);
|
|
169
|
+
if (fs.existsSync(contextPath)) {
|
|
170
|
+
fs.unlinkSync(contextPath);
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* List all context configurations
|
|
177
|
+
*/
|
|
178
|
+
function listContexts() {
|
|
179
|
+
const dirs = getAppDirs();
|
|
180
|
+
const contextsDir = (0, appstash_1.resolve)(dirs, 'config', 'contexts');
|
|
181
|
+
if (!fs.existsSync(contextsDir)) {
|
|
182
|
+
return [];
|
|
183
|
+
}
|
|
184
|
+
const files = fs.readdirSync(contextsDir).filter(f => f.endsWith('.json'));
|
|
185
|
+
const contexts = [];
|
|
186
|
+
for (const file of files) {
|
|
187
|
+
try {
|
|
188
|
+
const content = fs.readFileSync(path.join(contextsDir, file), 'utf8');
|
|
189
|
+
contexts.push(JSON.parse(content));
|
|
190
|
+
}
|
|
191
|
+
catch {
|
|
192
|
+
// Skip invalid files
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
return contexts;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Get the current active context
|
|
199
|
+
*/
|
|
200
|
+
function getCurrentContext() {
|
|
201
|
+
const settings = loadSettings();
|
|
202
|
+
if (settings.currentContext) {
|
|
203
|
+
return loadContext(settings.currentContext);
|
|
204
|
+
}
|
|
205
|
+
return null;
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Set the current active context
|
|
209
|
+
*/
|
|
210
|
+
function setCurrentContext(contextName) {
|
|
211
|
+
const context = loadContext(contextName);
|
|
212
|
+
if (!context) {
|
|
213
|
+
return false;
|
|
214
|
+
}
|
|
215
|
+
const settings = loadSettings();
|
|
216
|
+
settings.currentContext = contextName;
|
|
217
|
+
saveSettings(settings);
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Create a new context configuration
|
|
222
|
+
*/
|
|
223
|
+
function createContext(name, endpoint) {
|
|
224
|
+
const now = new Date().toISOString();
|
|
225
|
+
const context = {
|
|
226
|
+
name,
|
|
227
|
+
endpoint,
|
|
228
|
+
createdAt: now,
|
|
229
|
+
updatedAt: now,
|
|
230
|
+
};
|
|
231
|
+
saveContext(context);
|
|
232
|
+
return context;
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Get credentials for a context
|
|
236
|
+
*/
|
|
237
|
+
function getContextCredentials(contextName) {
|
|
238
|
+
const credentials = loadCredentials();
|
|
239
|
+
return credentials.tokens[contextName] || null;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Set credentials for a context
|
|
243
|
+
*/
|
|
244
|
+
function setContextCredentials(contextName, token, options) {
|
|
245
|
+
const credentials = loadCredentials();
|
|
246
|
+
credentials.tokens[contextName] = {
|
|
247
|
+
token,
|
|
248
|
+
expiresAt: options?.expiresAt,
|
|
249
|
+
refreshToken: options?.refreshToken,
|
|
250
|
+
};
|
|
251
|
+
saveCredentials(credentials);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Remove credentials for a context
|
|
255
|
+
*/
|
|
256
|
+
function removeContextCredentials(contextName) {
|
|
257
|
+
const credentials = loadCredentials();
|
|
258
|
+
if (credentials.tokens[contextName]) {
|
|
259
|
+
delete credentials.tokens[contextName];
|
|
260
|
+
saveCredentials(credentials);
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
return false;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Check if a context has valid credentials
|
|
267
|
+
*/
|
|
268
|
+
function hasValidCredentials(contextName) {
|
|
269
|
+
const creds = getContextCredentials(contextName);
|
|
270
|
+
if (!creds || !creds.token) {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
if (creds.expiresAt) {
|
|
274
|
+
const expiresAt = new Date(creds.expiresAt);
|
|
275
|
+
if (expiresAt <= new Date()) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return true;
|
|
280
|
+
}
|
package/config/index.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Config module exports
|
|
4
|
+
*/
|
|
5
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
9
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
10
|
+
}
|
|
11
|
+
Object.defineProperty(o, k2, desc);
|
|
12
|
+
}) : (function(o, m, k, k2) {
|
|
13
|
+
if (k2 === undefined) k2 = k;
|
|
14
|
+
o[k2] = m[k];
|
|
15
|
+
}));
|
|
16
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
17
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
18
|
+
};
|
|
19
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
20
|
+
__exportStar(require("./types"), exports);
|
|
21
|
+
__exportStar(require("./config-manager"), exports);
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration types for the CNC execution engine
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Context configuration stored in ~/.cnc/config/contexts/{name}.json
|
|
6
|
+
* Similar to kubectl contexts - bundles endpoint + credentials
|
|
7
|
+
*/
|
|
8
|
+
export interface ContextConfig {
|
|
9
|
+
/** Context name (used as identifier) */
|
|
10
|
+
name: string;
|
|
11
|
+
/** GraphQL endpoint URL */
|
|
12
|
+
endpoint: string;
|
|
13
|
+
/** Created timestamp */
|
|
14
|
+
createdAt: string;
|
|
15
|
+
/** Last updated timestamp */
|
|
16
|
+
updatedAt: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Global settings stored in ~/.cnc/config/settings.json
|
|
20
|
+
*/
|
|
21
|
+
export interface GlobalSettings {
|
|
22
|
+
/** Currently active context name */
|
|
23
|
+
currentContext?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Credentials stored in ~/.cnc/config/credentials.json
|
|
27
|
+
*/
|
|
28
|
+
export interface Credentials {
|
|
29
|
+
/** API tokens per context */
|
|
30
|
+
tokens: Record<string, ContextCredentials>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Per-context credentials
|
|
34
|
+
*/
|
|
35
|
+
export interface ContextCredentials {
|
|
36
|
+
/** Bearer token for API authentication */
|
|
37
|
+
token: string;
|
|
38
|
+
/** Token expiration timestamp (ISO string) */
|
|
39
|
+
expiresAt?: string;
|
|
40
|
+
/** Refresh token if available */
|
|
41
|
+
refreshToken?: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Default global settings
|
|
45
|
+
*/
|
|
46
|
+
export declare const DEFAULT_SETTINGS: GlobalSettings;
|
package/config/types.js
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication commands for the CNC execution engine
|
|
3
|
+
*/
|
|
4
|
+
import { extractFirst } from 'inquirerer';
|
|
5
|
+
import chalk from 'yanse';
|
|
6
|
+
import { getCurrentContext, loadContext, listContexts, getContextCredentials, setContextCredentials, removeContextCredentials, hasValidCredentials, loadSettings, } from '../config';
|
|
7
|
+
const usage = `
|
|
8
|
+
Constructive Authentication:
|
|
9
|
+
|
|
10
|
+
cnc auth <command> [OPTIONS]
|
|
11
|
+
|
|
12
|
+
Commands:
|
|
13
|
+
set-token <token> Set API token for the current context
|
|
14
|
+
status Show authentication status
|
|
15
|
+
logout Remove credentials for the current context
|
|
16
|
+
|
|
17
|
+
Options:
|
|
18
|
+
--context <name> Specify context (defaults to current context)
|
|
19
|
+
--expires <date> Token expiration date (ISO format)
|
|
20
|
+
|
|
21
|
+
Examples:
|
|
22
|
+
cnc auth set-token eyJhbGciOiJIUzI1NiIs...
|
|
23
|
+
cnc auth status
|
|
24
|
+
cnc auth logout
|
|
25
|
+
cnc auth set-token <token> --context my-api
|
|
26
|
+
|
|
27
|
+
--help, -h Show this help message
|
|
28
|
+
`;
|
|
29
|
+
export default async (argv, prompter, _options) => {
|
|
30
|
+
if (argv.help || argv.h) {
|
|
31
|
+
console.log(usage);
|
|
32
|
+
process.exit(0);
|
|
33
|
+
}
|
|
34
|
+
const { first: subcommand, newArgv } = extractFirst(argv);
|
|
35
|
+
if (!subcommand) {
|
|
36
|
+
const answer = await prompter.prompt(argv, [
|
|
37
|
+
{
|
|
38
|
+
type: 'autocomplete',
|
|
39
|
+
name: 'subcommand',
|
|
40
|
+
message: 'What do you want to do?',
|
|
41
|
+
options: ['set-token', 'status', 'logout'],
|
|
42
|
+
},
|
|
43
|
+
]);
|
|
44
|
+
return handleSubcommand(answer.subcommand, newArgv, prompter);
|
|
45
|
+
}
|
|
46
|
+
return handleSubcommand(subcommand, newArgv, prompter);
|
|
47
|
+
};
|
|
48
|
+
async function handleSubcommand(subcommand, argv, prompter) {
|
|
49
|
+
switch (subcommand) {
|
|
50
|
+
case 'set-token':
|
|
51
|
+
return handleSetToken(argv, prompter);
|
|
52
|
+
case 'status':
|
|
53
|
+
return handleStatus(argv);
|
|
54
|
+
case 'logout':
|
|
55
|
+
return handleLogout(argv, prompter);
|
|
56
|
+
default:
|
|
57
|
+
console.log(usage);
|
|
58
|
+
console.error(chalk.red(`Unknown subcommand: ${subcommand}`));
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function getTargetContext(argv, prompter) {
|
|
63
|
+
if (argv.context && typeof argv.context === 'string') {
|
|
64
|
+
const context = loadContext(argv.context);
|
|
65
|
+
if (!context) {
|
|
66
|
+
console.error(chalk.red(`Context "${argv.context}" not found.`));
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
return argv.context;
|
|
70
|
+
}
|
|
71
|
+
const current = getCurrentContext();
|
|
72
|
+
if (current) {
|
|
73
|
+
return current.name;
|
|
74
|
+
}
|
|
75
|
+
const contexts = listContexts();
|
|
76
|
+
if (contexts.length === 0) {
|
|
77
|
+
console.error(chalk.red('No contexts configured.'));
|
|
78
|
+
console.log(chalk.gray('Run "cnc context create <name>" to create one first.'));
|
|
79
|
+
process.exit(1);
|
|
80
|
+
}
|
|
81
|
+
const answer = await prompter.prompt(argv, [
|
|
82
|
+
{
|
|
83
|
+
type: 'autocomplete',
|
|
84
|
+
name: 'context',
|
|
85
|
+
message: 'Select context',
|
|
86
|
+
options: contexts.map(c => c.name),
|
|
87
|
+
},
|
|
88
|
+
]);
|
|
89
|
+
return answer.context;
|
|
90
|
+
}
|
|
91
|
+
async function handleSetToken(argv, prompter) {
|
|
92
|
+
const contextName = await getTargetContext(argv, prompter);
|
|
93
|
+
const { first: token, newArgv } = extractFirst(argv);
|
|
94
|
+
let tokenValue = token;
|
|
95
|
+
if (!tokenValue) {
|
|
96
|
+
const answer = await prompter.prompt(newArgv, [
|
|
97
|
+
{
|
|
98
|
+
type: 'password',
|
|
99
|
+
name: 'token',
|
|
100
|
+
message: 'API Token',
|
|
101
|
+
required: true,
|
|
102
|
+
},
|
|
103
|
+
]);
|
|
104
|
+
tokenValue = answer.token;
|
|
105
|
+
}
|
|
106
|
+
if (!tokenValue || tokenValue.trim() === '') {
|
|
107
|
+
console.error(chalk.red('Token cannot be empty.'));
|
|
108
|
+
process.exit(1);
|
|
109
|
+
}
|
|
110
|
+
const expiresAt = argv.expires;
|
|
111
|
+
setContextCredentials(contextName, tokenValue.trim(), { expiresAt });
|
|
112
|
+
console.log(chalk.green(`Token saved for context: ${contextName}`));
|
|
113
|
+
if (expiresAt) {
|
|
114
|
+
console.log(chalk.gray(`Expires: ${expiresAt}`));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function handleStatus(argv) {
|
|
118
|
+
const settings = loadSettings();
|
|
119
|
+
const contexts = listContexts();
|
|
120
|
+
if (contexts.length === 0) {
|
|
121
|
+
console.log(chalk.gray('No contexts configured.'));
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (argv.context && typeof argv.context === 'string') {
|
|
125
|
+
const context = loadContext(argv.context);
|
|
126
|
+
if (!context) {
|
|
127
|
+
console.error(chalk.red(`Context "${argv.context}" not found.`));
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
showContextAuthStatus(context.name, settings.currentContext === context.name);
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
console.log(chalk.bold('Authentication Status:'));
|
|
134
|
+
console.log();
|
|
135
|
+
for (const context of contexts) {
|
|
136
|
+
const isCurrent = context.name === settings.currentContext;
|
|
137
|
+
showContextAuthStatus(context.name, isCurrent);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function showContextAuthStatus(contextName, isCurrent) {
|
|
141
|
+
const creds = getContextCredentials(contextName);
|
|
142
|
+
const hasAuth = hasValidCredentials(contextName);
|
|
143
|
+
const marker = isCurrent ? chalk.green('*') : ' ';
|
|
144
|
+
console.log(`${marker} ${chalk.bold(contextName)}`);
|
|
145
|
+
if (hasAuth && creds) {
|
|
146
|
+
console.log(` Status: ${chalk.green('Authenticated')}`);
|
|
147
|
+
console.log(` Token: ${maskToken(creds.token)}`);
|
|
148
|
+
if (creds.expiresAt) {
|
|
149
|
+
const expiresAt = new Date(creds.expiresAt);
|
|
150
|
+
const now = new Date();
|
|
151
|
+
if (expiresAt <= now) {
|
|
152
|
+
console.log(` Expires: ${chalk.red(creds.expiresAt + ' (expired)')}`);
|
|
153
|
+
}
|
|
154
|
+
else {
|
|
155
|
+
console.log(` Expires: ${creds.expiresAt}`);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else if (creds && creds.token) {
|
|
160
|
+
console.log(` Status: ${chalk.red('Expired')}`);
|
|
161
|
+
console.log(` Token: ${maskToken(creds.token)}`);
|
|
162
|
+
if (creds.expiresAt) {
|
|
163
|
+
console.log(` Expired: ${creds.expiresAt}`);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
else {
|
|
167
|
+
console.log(` Status: ${chalk.yellow('Not authenticated')}`);
|
|
168
|
+
}
|
|
169
|
+
console.log();
|
|
170
|
+
}
|
|
171
|
+
function maskToken(token) {
|
|
172
|
+
if (token.length <= 10) {
|
|
173
|
+
return '****';
|
|
174
|
+
}
|
|
175
|
+
return token.substring(0, 6) + '...' + token.substring(token.length - 4);
|
|
176
|
+
}
|
|
177
|
+
async function handleLogout(argv, prompter) {
|
|
178
|
+
const contextName = await getTargetContext(argv, prompter);
|
|
179
|
+
const creds = getContextCredentials(contextName);
|
|
180
|
+
if (!creds) {
|
|
181
|
+
console.log(chalk.gray(`No credentials found for context: ${contextName}`));
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const confirm = await prompter.prompt(argv, [
|
|
185
|
+
{
|
|
186
|
+
type: 'confirm',
|
|
187
|
+
name: 'confirm',
|
|
188
|
+
message: `Remove credentials for context "${contextName}"?`,
|
|
189
|
+
default: false,
|
|
190
|
+
},
|
|
191
|
+
]);
|
|
192
|
+
if (!confirm.confirm) {
|
|
193
|
+
console.log(chalk.gray('Cancelled.'));
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (removeContextCredentials(contextName)) {
|
|
197
|
+
console.log(chalk.green(`Credentials removed for context: ${contextName}`));
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
console.log(chalk.gray(`No credentials found for context: ${contextName}`));
|
|
201
|
+
}
|
|
202
|
+
}
|
package/esm/commands/codegen.js
CHANGED
|
@@ -18,6 +18,8 @@ Generator Options:
|
|
|
18
18
|
--orm Generate ORM client
|
|
19
19
|
--output <dir> Output directory (default: codegen)
|
|
20
20
|
--authorization <token> Authorization header value
|
|
21
|
+
--browserCompatible Generate browser-compatible code (default: true)
|
|
22
|
+
Set to false for Node.js with localhost DNS fix
|
|
21
23
|
--dryRun Preview without writing files
|
|
22
24
|
--verbose Verbose output
|
|
23
25
|
|
|
@@ -51,6 +53,7 @@ export default async (argv, prompter, _options) => {
|
|
|
51
53
|
authorization: answers.authorization,
|
|
52
54
|
reactQuery: answers.reactQuery,
|
|
53
55
|
orm: answers.orm,
|
|
56
|
+
browserCompatible: answers.browserCompatible,
|
|
54
57
|
dryRun: answers.dryRun,
|
|
55
58
|
verbose: answers.verbose,
|
|
56
59
|
});
|