@42ws/cli 0.0.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/README.md ADDED
@@ -0,0 +1,86 @@
1
+ # 42ws
2
+
3
+ Publish static sites in one command.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ npx 42ws@latest login --token ws_xxx
9
+ npx 42ws@latest publish --site my-site --dir dist
10
+ ```
11
+
12
+ ## Commands
13
+
14
+ ### `42ws login`
15
+
16
+ Authenticate with your 42ws token.
17
+
18
+ ```
19
+ 42ws login --token ws_xxx
20
+ 42ws login --token ws_xxx --api-url https://api.dev.42ws.com
21
+ ```
22
+
23
+ If `--token` is omitted, you will be prompted to paste your token interactively.
24
+
25
+ ### `42ws publish`
26
+
27
+ Publish a static site.
28
+
29
+ ```
30
+ 42ws publish --site my-site --dir dist
31
+ 42ws publish --site my-site --build "npm run build"
32
+ 42ws publish --site my-site --message "Release v1.0"
33
+ 42ws publish --site my-site --json
34
+ ```
35
+
36
+ Options:
37
+ - `--site <name>` — Site name (required, or set in `42ws.json`)
38
+ - `--dir <path>` — Output directory (default: `dist`)
39
+ - `--build <cmd>` — Build command to run before publishing
40
+ - `--no-build` — Skip the build step
41
+ - `--message <text>` — Deployment message
42
+ - `--yes` — Skip confirmation prompts
43
+ - `--json` — Output results as JSON
44
+
45
+ ### `42ws whoami`
46
+
47
+ Show the currently logged-in user.
48
+
49
+ ```
50
+ 42ws whoami
51
+ ```
52
+
53
+ ## Configuration file
54
+
55
+ Place a `42ws.json` in your project root:
56
+
57
+ ```json
58
+ {
59
+ "site": "my-site",
60
+ "build": "npm run build",
61
+ "output": "dist"
62
+ }
63
+ ```
64
+
65
+ CLI arguments take precedence over the configuration file.
66
+
67
+ ## Environment variables
68
+
69
+ | Variable | Description |
70
+ |---|---|
71
+ | `FORTYTWO_WS_TOKEN` | Override the stored auth token |
72
+ | `FORTYTWO_WS_API_URL` | Override the API URL |
73
+
74
+ ## JSON output mode
75
+
76
+ Use `--json` for machine-readable output (useful in CI):
77
+
78
+ **Success:**
79
+ ```json
80
+ {"ok":true,"status":"published","url":"https://my-site.dev.42ws.com","site":"my-site","version":"pub_xxx"}
81
+ ```
82
+
83
+ **Failure:**
84
+ ```json
85
+ {"ok":false,"error":{"code":"NOT_LOGGED_IN","message":"You are not logged in.","suggestedFix":"Run `42ws login --token <your-token>` to authenticate."}}
86
+ ```
package/bin/cli.js ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import('../dist/index.js').then(m => m.main()).catch(e => {
3
+ console.error(e?.message || e);
4
+ process.exit(1);
5
+ });
@@ -0,0 +1,7 @@
1
+ interface ParsedArgs {
2
+ token?: string;
3
+ apiUrl?: string;
4
+ }
5
+ export declare function login(args: ParsedArgs): Promise<void>;
6
+ export {};
7
+ //# sourceMappingURL=login.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAUA,UAAU,UAAU;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAiBD,wBAAsB,KAAK,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkB3D"}
@@ -0,0 +1,115 @@
1
+ import { loadConfig, saveConfig } from '../lib/config.js';
2
+ import { apiRequest, ApiError } from '../lib/api.js';
3
+ import { info, successMessage, error } from '../lib/output.js';
4
+ import { spawn } from 'node:child_process';
5
+ export async function login(args) {
6
+ const config = loadConfig();
7
+ const apiUrl = args.apiUrl ?? config.apiUrl;
8
+ // --token flag: legacy / direct token flow
9
+ if (args.token !== undefined) {
10
+ await loginWithToken(args.token, apiUrl);
11
+ return;
12
+ }
13
+ // No --token: device code flow (requires interactive TTY)
14
+ const isTTY = process.stdin.isTTY;
15
+ if (!isTTY) {
16
+ error('NOT_A_TTY', 'Stdin is not a TTY; please use --token', 'Run `42ws login --token <your-token>`.');
17
+ process.exit(1);
18
+ }
19
+ await loginWithBrowser(apiUrl);
20
+ }
21
+ async function loginWithToken(token, apiUrl) {
22
+ token = token.trim();
23
+ if (!token) {
24
+ error('INVALID_TOKEN', 'No token provided.', 'Run `42ws login --token <your-token>`.');
25
+ process.exit(1);
26
+ }
27
+ const testConfig = { token, apiUrl };
28
+ let me;
29
+ try {
30
+ me = await apiRequest(testConfig, 'GET', '/v1/whoami');
31
+ }
32
+ catch (e) {
33
+ if (e instanceof ApiError) {
34
+ error('INVALID_TOKEN', `Token validation failed: ${e.message}`, 'Get a valid token from your dashboard.');
35
+ }
36
+ else {
37
+ error('NETWORK_ERROR', `Could not reach API: ${String(e)}`, 'Check your internet connection.');
38
+ }
39
+ process.exit(1);
40
+ }
41
+ saveConfig({ token, apiUrl });
42
+ successMessage(me.email ? `Logged in as ${me.email}` : `Logged in (userId ${me.userId})`);
43
+ }
44
+ async function loginWithBrowser(apiUrl) {
45
+ const noAuthConfig = { apiUrl };
46
+ let session;
47
+ try {
48
+ session = await apiRequest(noAuthConfig, 'POST', '/v1/cli/sessions', {});
49
+ }
50
+ catch (e) {
51
+ if (e instanceof ApiError) {
52
+ error('NETWORK_ERROR', `Failed to start login session: ${e.message}`, 'Check your internet connection.');
53
+ }
54
+ else {
55
+ error('NETWORK_ERROR', `Could not reach API: ${String(e)}`, 'Check your internet connection.');
56
+ }
57
+ process.exit(1);
58
+ }
59
+ openBrowser(session.verificationUrlComplete);
60
+ info('Opening your browser...');
61
+ info('If it didn\'t open, visit:');
62
+ info(session.verificationUrlComplete);
63
+ info(`User code: ${session.userCode}`);
64
+ info('Waiting for authorization...');
65
+ const deadline = Date.now() + session.expiresIn * 1000;
66
+ const intervalMs = session.interval * 1000;
67
+ while (Date.now() < deadline) {
68
+ await sleep(intervalMs);
69
+ let statusResp;
70
+ try {
71
+ statusResp = await apiRequest(noAuthConfig, 'GET', `/v1/cli/sessions/${session.deviceCode}`);
72
+ }
73
+ catch {
74
+ // transient error — keep polling
75
+ continue;
76
+ }
77
+ if (statusResp.status === 'pending') {
78
+ continue;
79
+ }
80
+ if (statusResp.status === 'authorized') {
81
+ const token = statusResp.token;
82
+ saveConfig({ token, apiUrl });
83
+ const email = statusResp.user?.email;
84
+ successMessage(email ? `Logged in as ${email}` : 'Logged in successfully');
85
+ return;
86
+ }
87
+ if (statusResp.status === 'expired') {
88
+ error('LOGIN_EXPIRED', 'Login session expired.', 'Run `42ws login` to try again.');
89
+ process.exit(1);
90
+ }
91
+ }
92
+ error('LOGIN_EXPIRED', 'Login session timed out.', 'Run `42ws login` to try again.');
93
+ process.exit(1);
94
+ }
95
+ function openBrowser(url) {
96
+ try {
97
+ const platform = process.platform;
98
+ if (platform === 'darwin') {
99
+ spawn('open', [url], { detached: true, stdio: 'ignore' }).unref();
100
+ }
101
+ else if (platform === 'win32') {
102
+ spawn('cmd', ['/c', 'start', '', url], { detached: true, stdio: 'ignore' }).unref();
103
+ }
104
+ else {
105
+ spawn('xdg-open', [url], { detached: true, stdio: 'ignore' }).unref();
106
+ }
107
+ }
108
+ catch {
109
+ // ignore — user will use the printed URL
110
+ }
111
+ }
112
+ function sleep(ms) {
113
+ return new Promise(resolve => setTimeout(resolve, ms));
114
+ }
115
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ export interface ProjectConfig {
2
+ site?: string;
3
+ build?: string;
4
+ output?: string;
5
+ spa?: boolean;
6
+ ignore?: string[];
7
+ }
8
+ export interface PublishArgs {
9
+ site?: string;
10
+ dir?: string;
11
+ message?: string;
12
+ yes?: boolean;
13
+ json?: boolean;
14
+ build?: string;
15
+ noBuild?: boolean;
16
+ }
17
+ export declare function publish(args: PublishArgs): Promise<void>;
18
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AA6BD,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AA+FD,wBAAsB,OAAO,CAAC,IAAI,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA2M9D"}
@@ -0,0 +1,300 @@
1
+ import { loadConfig } from '../lib/config.js';
2
+ import { detectFramework } from '../lib/detect.js';
3
+ import { apiRequest, uploadFile, ApiError } from '../lib/api.js';
4
+ import { info, success, successMessage, error, isJsonMode } from '../lib/output.js';
5
+ import { collectFiles, formatBytes } from '../lib/files.js';
6
+ import { existsSync, readFileSync } from 'node:fs';
7
+ import { join, resolve, basename } from 'node:path';
8
+ import { spawn } from 'node:child_process';
9
+ import { createInterface } from 'node:readline';
10
+ // ---------------------------------------------------------------------------
11
+ // Helpers
12
+ // ---------------------------------------------------------------------------
13
+ function loadProjectConfig(cwd) {
14
+ const configPath = join(cwd, '42ws.json');
15
+ if (!existsSync(configPath))
16
+ return {};
17
+ try {
18
+ return JSON.parse(readFileSync(configPath, 'utf-8'));
19
+ }
20
+ catch {
21
+ if (!isJsonMode()) {
22
+ process.stderr.write('Warning: Failed to parse 42ws.json, ignoring.\n');
23
+ }
24
+ return {};
25
+ }
26
+ }
27
+ function slugify(name) {
28
+ return name
29
+ .toLowerCase()
30
+ .replace(/[^a-z0-9-]+/g, '-')
31
+ .replace(/^-+|-+$/g, '');
32
+ }
33
+ function prompt(question) {
34
+ return new Promise(resolve => {
35
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
36
+ rl.question(question, answer => {
37
+ rl.close();
38
+ resolve(answer.trim());
39
+ });
40
+ });
41
+ }
42
+ function isTTY() {
43
+ return !!process.stdin.isTTY;
44
+ }
45
+ function frameworkLabel(framework) {
46
+ const labels = {
47
+ vite: 'Vite',
48
+ astro: 'Astro',
49
+ 'next-static': 'Next.js (static export)',
50
+ 'sveltekit-static': 'SvelteKit (static adapter)',
51
+ 'plain-html': 'plain HTML',
52
+ unknown: 'unknown',
53
+ };
54
+ return labels[framework] ?? framework;
55
+ }
56
+ function runBuild(cmd) {
57
+ return new Promise((res, rej) => {
58
+ const child = spawn(cmd, { shell: true, stdio: 'inherit' });
59
+ child.on('close', code => {
60
+ if (code === 0) {
61
+ res();
62
+ }
63
+ else {
64
+ rej(new ApiError('BUILD_FAILED', `Build command exited with code ${code}`, 'Fix the build errors shown above and try again.'));
65
+ }
66
+ });
67
+ child.on('error', err => {
68
+ rej(new ApiError('BUILD_FAILED', `Failed to run build command: ${err.message}`, 'Fix the build errors shown above and try again.'));
69
+ });
70
+ });
71
+ }
72
+ async function ensureSiteExists(config, siteName) {
73
+ let sites = [];
74
+ try {
75
+ const result = await apiRequest(config, 'GET', '/v1/sites');
76
+ sites = result.sites ?? [];
77
+ }
78
+ catch {
79
+ // if listing fails, try to create anyway
80
+ }
81
+ const exists = sites.some(s => s.site === siteName || s.name === siteName);
82
+ if (exists)
83
+ return;
84
+ try {
85
+ await apiRequest(config, 'POST', '/v1/sites', { site: siteName });
86
+ }
87
+ catch (e) {
88
+ if (e instanceof ApiError) {
89
+ if (e.code === 'CONFLICT')
90
+ return;
91
+ throw e;
92
+ }
93
+ throw e;
94
+ }
95
+ }
96
+ // ---------------------------------------------------------------------------
97
+ // Main
98
+ // ---------------------------------------------------------------------------
99
+ export async function publish(args) {
100
+ const cwd = process.cwd();
101
+ const projectConfig = loadProjectConfig(cwd);
102
+ const detection = detectFramework(cwd);
103
+ // ---- Resolve site name -----------------------------------------------
104
+ let siteName = args.site ?? projectConfig.site;
105
+ if (!siteName) {
106
+ const candidate = slugify(basename(cwd));
107
+ if (args.yes) {
108
+ siteName = candidate;
109
+ }
110
+ else if (isTTY()) {
111
+ const answer = await prompt(`Site name [${candidate}]: `);
112
+ siteName = answer.length > 0 ? answer : candidate;
113
+ }
114
+ else {
115
+ error('INVALID_SITE_NAME', 'Site name is required.', 'Use --site <name>, add "site" to 42ws.json, or run with --yes to use the directory name.');
116
+ process.exit(1);
117
+ }
118
+ }
119
+ // ---- Resolve build command -------------------------------------------
120
+ const buildFromDetect = detection.build !== undefined && !args.noBuild && !args.build && !projectConfig.build;
121
+ const buildCmd = args.noBuild
122
+ ? undefined
123
+ : (args.build ?? projectConfig.build ?? detection.build);
124
+ // ---- Resolve output dir ----------------------------------------------
125
+ const outputRaw = args.dir ?? projectConfig.output ?? detection.output ?? 'dist';
126
+ const outputDir = resolve(cwd, outputRaw);
127
+ // ---- Show detection info (non-JSON mode) -----------------------------
128
+ if (!isJsonMode() && detection.framework !== 'unknown') {
129
+ info(`Detected ${frameworkLabel(detection.framework)} project.`);
130
+ if (buildFromDetect && buildCmd) {
131
+ info(` Build command: ${buildCmd}`);
132
+ }
133
+ if (detection.output && !args.dir && !projectConfig.output) {
134
+ info(` Output directory: ${detection.output}`);
135
+ }
136
+ }
137
+ // ---- Interactive confirmation (non-JSON, non-yes, TTY) ---------------
138
+ if (!isJsonMode() && !args.yes && isTTY() && detection.framework !== 'unknown') {
139
+ const answer = await prompt('Continue? [Y/n]: ');
140
+ if (answer.toLowerCase() === 'n') {
141
+ error('PUBLISH_CANCELLED', 'Publish cancelled by user.', '');
142
+ process.exit(1);
143
+ }
144
+ }
145
+ // ---- Check login -----------------------------------------------------
146
+ const config = loadConfig();
147
+ if (!config.token) {
148
+ error('NOT_LOGGED_IN', 'You are not logged in.', 'Run `42ws login --token <your-token>` to authenticate.');
149
+ process.exit(1);
150
+ }
151
+ // ---- Run build if needed ---------------------------------------------
152
+ if (buildCmd) {
153
+ // Skip build if output dir already exists and build was not explicitly requested
154
+ const shouldSkipBuild = !args.build && existsSync(outputDir);
155
+ if (!shouldSkipBuild) {
156
+ info(`Building... (${buildCmd})`);
157
+ try {
158
+ await runBuild(buildCmd);
159
+ }
160
+ catch (e) {
161
+ if (e instanceof ApiError) {
162
+ error(e.code, e.message, e.suggestedFix);
163
+ }
164
+ else {
165
+ error('BUILD_FAILED', String(e), 'Fix the build errors shown above and try again.');
166
+ }
167
+ process.exit(1);
168
+ }
169
+ }
170
+ }
171
+ // ---- Check output directory ------------------------------------------
172
+ if (!existsSync(outputDir)) {
173
+ if (detection.framework === 'unknown' && !args.dir && !projectConfig.output) {
174
+ error('OUTPUT_DIR_NOT_FOUND', `Cannot detect framework. Specify --dir <path> with the directory to publish (or add a 42ws.json).`, '');
175
+ }
176
+ else {
177
+ error('OUTPUT_DIR_NOT_FOUND', `Output directory not found: ${outputDir}`, 'Run your build command first, or specify the correct directory with --dir.');
178
+ }
179
+ process.exit(1);
180
+ }
181
+ // ---- Collect files ---------------------------------------------------
182
+ info('Collecting files...');
183
+ let files;
184
+ try {
185
+ files = collectFiles(outputDir);
186
+ }
187
+ catch (e) {
188
+ if (e instanceof ApiError) {
189
+ error(e.code, e.message, e.suggestedFix);
190
+ }
191
+ else {
192
+ error('PUBLISH_FAILED', String(e), 'Try again.');
193
+ }
194
+ process.exit(1);
195
+ }
196
+ if (files.length === 0) {
197
+ error('NO_FILES_FOUND', `No files found in: ${outputDir}`, 'Make sure your output directory contains files to publish.');
198
+ process.exit(1);
199
+ }
200
+ const totalSize = files.reduce((acc, f) => acc + f.size, 0);
201
+ info(`Collecting files... (${files.length} files, ${formatBytes(totalSize)})`);
202
+ // ---- Ensure site exists ----------------------------------------------
203
+ try {
204
+ await ensureSiteExists(config, siteName);
205
+ }
206
+ catch (e) {
207
+ if (e instanceof ApiError) {
208
+ error(e.code, e.message, e.suggestedFix);
209
+ }
210
+ else {
211
+ error('PUBLISH_FAILED', String(e), 'Try again.');
212
+ }
213
+ process.exit(1);
214
+ }
215
+ // ---- Create publish request ------------------------------------------
216
+ info('Uploading...');
217
+ const fileRequests = files.map(f => ({
218
+ path: f.path,
219
+ contentType: f.contentType,
220
+ size: f.size,
221
+ sha256: f.sha256,
222
+ }));
223
+ let publishResponse;
224
+ try {
225
+ publishResponse = await apiRequest(config, 'POST', '/v1/publishes', {
226
+ site: siteName,
227
+ message: args.message,
228
+ files: fileRequests,
229
+ });
230
+ }
231
+ catch (e) {
232
+ if (e instanceof ApiError) {
233
+ error(e.code, e.message, e.suggestedFix);
234
+ }
235
+ else {
236
+ error('PUBLISH_FAILED', String(e), 'Try again.');
237
+ }
238
+ process.exit(1);
239
+ }
240
+ // ---- Upload files in parallel (concurrency 8) ------------------------
241
+ const { publishId, uploads } = publishResponse;
242
+ const fileMap = new Map(files.map(f => [f.path, f]));
243
+ const uploadQueue = [...uploads];
244
+ const CONCURRENCY = 8;
245
+ async function uploadWorker() {
246
+ while (uploadQueue.length > 0) {
247
+ const instruction = uploadQueue.pop();
248
+ if (!instruction)
249
+ break;
250
+ const file = fileMap.get(instruction.path);
251
+ if (!file)
252
+ continue;
253
+ try {
254
+ await uploadFile(instruction.url, file.content, file.contentType);
255
+ }
256
+ catch (e) {
257
+ if (e instanceof ApiError)
258
+ throw e;
259
+ throw new ApiError('UPLOAD_FAILED', `Failed to upload ${instruction.path}`, 'Try running publish again.');
260
+ }
261
+ }
262
+ }
263
+ try {
264
+ await Promise.all(Array.from({ length: CONCURRENCY }, uploadWorker));
265
+ }
266
+ catch (e) {
267
+ if (e instanceof ApiError) {
268
+ error(e.code, e.message, e.suggestedFix);
269
+ }
270
+ else {
271
+ error('UPLOAD_FAILED', String(e), 'Try running publish again.');
272
+ }
273
+ process.exit(1);
274
+ }
275
+ // ---- Complete publish ------------------------------------------------
276
+ info('Publishing...');
277
+ let completeResponse;
278
+ try {
279
+ completeResponse = await apiRequest(config, 'POST', `/v1/publishes/${publishId}/complete`);
280
+ }
281
+ catch (e) {
282
+ if (e instanceof ApiError) {
283
+ error(e.code, e.message, e.suggestedFix);
284
+ }
285
+ else {
286
+ error('PUBLISH_FAILED', String(e), 'Try again.');
287
+ }
288
+ process.exit(1);
289
+ }
290
+ // ---- Show result -----------------------------------------------------
291
+ const url = completeResponse.url ?? `https://${siteName}.dev.42ws.com`;
292
+ const version = completeResponse.version ?? publishId;
293
+ if (isJsonMode()) {
294
+ success({ status: 'published', url, site: siteName, version });
295
+ }
296
+ else {
297
+ successMessage(`Published:\n${url}`);
298
+ }
299
+ }
300
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/commands/publish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function whoami(): Promise<void>;
2
+ //# sourceMappingURL=whoami.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.d.ts","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AASA,wBAAsB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CA6B5C"}
@@ -0,0 +1,30 @@
1
+ import { loadConfig } from '../lib/config.js';
2
+ import { apiRequest, ApiError } from '../lib/api.js';
3
+ import { successMessage, error } from '../lib/output.js';
4
+ export async function whoami() {
5
+ const config = loadConfig();
6
+ if (!config.token) {
7
+ error('NOT_LOGGED_IN', 'You are not logged in.', 'Run `42ws login --token <your-token>` to authenticate.');
8
+ process.exit(1);
9
+ }
10
+ let me;
11
+ try {
12
+ me = await apiRequest(config, 'GET', '/v1/whoami');
13
+ }
14
+ catch (e) {
15
+ if (e instanceof ApiError) {
16
+ if (e.code === 'LOGIN_EXPIRED' || e.code === 'FORBIDDEN') {
17
+ error('LOGIN_EXPIRED', 'Your session has expired.', 'Run `42ws login` to re-authenticate.');
18
+ }
19
+ else {
20
+ error(e.code, e.message, e.suggestedFix);
21
+ }
22
+ }
23
+ else {
24
+ error('NETWORK_ERROR', `Could not reach API: ${String(e)}`, 'Check your internet connection.');
25
+ }
26
+ process.exit(1);
27
+ }
28
+ successMessage(me.email ?? me.userId);
29
+ }
30
+ //# sourceMappingURL=whoami.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAOzD,MAAM,CAAC,KAAK,UAAU,MAAM;IAC1B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAE5B,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClB,KAAK,CACH,eAAe,EACf,wBAAwB,EACxB,wDAAwD,CACzD,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,EAAc,CAAC;IACnB,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,UAAU,CAAa,MAAM,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IACjE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;YAC1B,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;gBACzD,KAAK,CAAC,eAAe,EAAE,2BAA2B,EAAE,sCAAsC,CAAC,CAAC;YAC9F,CAAC;iBAAM,CAAC;gBACN,KAAK,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,YAAY,CAAC,CAAC;YAC3C,CAAC;QACH,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,eAAe,EAAE,wBAAwB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,iCAAiC,CAAC,CAAC;QACjG,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,cAAc,CAAC,EAAE,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;AACxC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function main(): Promise<void>;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAwEA,wBAAsB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAyD1C"}