@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 +86 -0
- package/bin/cli.js +5 -0
- package/dist/commands/login.d.ts +7 -0
- package/dist/commands/login.d.ts.map +1 -0
- package/dist/commands/login.js +115 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/publish.d.ts +18 -0
- package/dist/commands/publish.d.ts.map +1 -0
- package/dist/commands/publish.js +300 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/whoami.d.ts +2 -0
- package/dist/commands/whoami.d.ts.map +1 -0
- package/dist/commands/whoami.js +30 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/api.d.ts +11 -0
- package/dist/lib/api.d.ts.map +1 -0
- package/dist/lib/api.js +104 -0
- package/dist/lib/api.js.map +1 -0
- package/dist/lib/config.d.ts +7 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +36 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/detect.d.ts +9 -0
- package/dist/lib/detect.d.ts.map +1 -0
- package/dist/lib/detect.js +112 -0
- package/dist/lib/detect.js.map +1 -0
- package/dist/lib/files.d.ts +11 -0
- package/dist/lib/files.d.ts.map +1 -0
- package/dist/lib/files.js +118 -0
- package/dist/lib/files.js.map +1 -0
- package/dist/lib/output.d.ts +10 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +37 -0
- package/dist/lib/output.js.map +1 -0
- package/package.json +23 -0
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 @@
|
|
|
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":"AAAA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAC/D,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AA2B3C,MAAM,CAAC,KAAK,UAAU,KAAK,CAAC,IAAgB;IAC1C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC;IAE5C,2CAA2C;IAC3C,IAAI,IAAI,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC7B,MAAM,cAAc,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QACzC,OAAO;IACT,CAAC;IAED,0DAA0D;IAC1D,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IAClC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,CAAC,WAAW,EAAE,wCAAwC,EAAE,wCAAwC,CAAC,CAAC;QACvG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,gBAAgB,CAAC,MAAM,CAAC,CAAC;AACjC,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,MAAc;IACzD,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IACrB,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,KAAK,CAAC,eAAe,EAAE,oBAAoB,EAAE,wCAAwC,CAAC,CAAC;QACvF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAErC,IAAI,EAAc,CAAC;IACnB,IAAI,CAAC;QACH,EAAE,GAAG,MAAM,UAAU,CAAa,UAAU,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;IACrE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,eAAe,EAAE,4BAA4B,CAAC,CAAC,OAAO,EAAE,EAAE,wCAAwC,CAAC,CAAC;QAC5G,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,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9B,cAAc,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,qBAAqB,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;AAC5F,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,MAAc;IAC5C,MAAM,YAAY,GAAG,EAAE,MAAM,EAAE,CAAC;IAEhC,IAAI,OAA2B,CAAC;IAChC,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,UAAU,CAAqB,YAAY,EAAE,MAAM,EAAE,kBAAkB,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,eAAe,EAAE,kCAAkC,CAAC,CAAC,OAAO,EAAE,EAAE,iCAAiC,CAAC,CAAC;QAC3G,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,WAAW,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAE7C,IAAI,CAAC,yBAAyB,CAAC,CAAC;IAChC,IAAI,CAAC,4BAA4B,CAAC,CAAC;IACnC,IAAI,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC;IACtC,IAAI,CAAC,cAAc,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;IACvC,IAAI,CAAC,8BAA8B,CAAC,CAAC;IAErC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC;IACvD,MAAM,UAAU,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAE3C,OAAO,IAAI,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC;QAExB,IAAI,UAAoC,CAAC;QACzC,IAAI,CAAC;YACH,UAAU,GAAG,MAAM,UAAU,CAC3B,YAAY,EACZ,KAAK,EACL,oBAAoB,OAAO,CAAC,UAAU,EAAE,CACzC,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;YACjC,SAAS;QACX,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACpC,SAAS;QACX,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;YACvC,MAAM,KAAK,GAAG,UAAU,CAAC,KAAM,CAAC;YAChC,UAAU,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,KAAK,CAAC;YACrC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC;YAC3E,OAAO;QACT,CAAC;QAED,IAAI,UAAU,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YACpC,KAAK,CAAC,eAAe,EAAE,wBAAwB,EAAE,gCAAgC,CAAC,CAAC;YACnF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,KAAK,CAAC,eAAe,EAAE,0BAA0B,EAAE,gCAAgC,CAAC,CAAC;IACrF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,SAAS,WAAW,CAAC,GAAW;IAC9B,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QAClC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YAC1B,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACpE,CAAC;aAAM,IAAI,QAAQ,KAAK,OAAO,EAAE,CAAC;YAChC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACtF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,UAAU,EAAE,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,CAAC;QACxE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,KAAK,CAAC,EAAU;IACvB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AACzD,CAAC"}
|
|
@@ -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 @@
|
|
|
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"}
|
package/dist/index.d.ts
ADDED
|
@@ -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"}
|