@within-7/jetr 0.3.1 → 0.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/README.md +26 -19
- package/dist/cli.js +83 -14
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,29 +17,34 @@ npx @within-7/jetr deploy my-site ./dist
|
|
|
17
17
|
## Quick Start
|
|
18
18
|
|
|
19
19
|
```bash
|
|
20
|
-
# 1. Login
|
|
21
|
-
jetr login
|
|
22
|
-
|
|
23
|
-
#
|
|
24
|
-
|
|
20
|
+
# 1. Login
|
|
21
|
+
jetr login
|
|
22
|
+
# Username: lib
|
|
23
|
+
# Password: ****
|
|
24
|
+
# ✔ Logged in as lib
|
|
25
|
+
|
|
26
|
+
# 2. Deploy current directory
|
|
27
|
+
jetr
|
|
28
|
+
# Site name [my-blog]:
|
|
29
|
+
# ✔ Deployed!
|
|
30
|
+
# URL: https://my-blog.jetr.within-7.com
|
|
25
31
|
|
|
26
|
-
# 3.
|
|
27
|
-
jetr
|
|
32
|
+
# 3. Re-deploy (remembers site name)
|
|
33
|
+
jetr
|
|
34
|
+
# Using saved site: my-blog
|
|
28
35
|
# ✔ Deployed!
|
|
29
|
-
# URL: https://my-blog.jetr.within-7.com
|
|
30
|
-
# Uploaded: 12 files
|
|
31
|
-
# Size: 1.2 MB
|
|
32
36
|
```
|
|
33
37
|
|
|
34
38
|
## Commands
|
|
35
39
|
|
|
36
|
-
### `jetr login
|
|
40
|
+
### `jetr login [user] [password]`
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
Login with username and password. Credentials are verified against auth-gateway, and the JWT token is saved locally.
|
|
39
43
|
|
|
40
44
|
```bash
|
|
41
|
-
jetr login
|
|
42
|
-
jetr login
|
|
45
|
+
jetr login # interactive prompts
|
|
46
|
+
jetr login lib mypassword # non-interactive
|
|
47
|
+
jetr login --token <jwt> # direct token (for CI)
|
|
43
48
|
```
|
|
44
49
|
|
|
45
50
|
### `jetr create <name>`
|
|
@@ -52,16 +57,18 @@ jetr create preview-site --password secret123
|
|
|
52
57
|
jetr create temp-demo --expires 86400 # expires in 24h
|
|
53
58
|
```
|
|
54
59
|
|
|
55
|
-
### `jetr
|
|
60
|
+
### `jetr [directory] [name]`
|
|
56
61
|
|
|
57
|
-
Deploy a directory
|
|
62
|
+
Deploy a directory. This is the default command — just run `jetr` in your project.
|
|
58
63
|
|
|
59
64
|
```bash
|
|
60
|
-
jetr deploy
|
|
61
|
-
jetr
|
|
62
|
-
jetr
|
|
65
|
+
jetr # deploy current dir, name from .jetrrc or prompt
|
|
66
|
+
jetr ./dist # deploy ./dist
|
|
67
|
+
jetr ./dist my-blog # deploy ./dist as my-blog
|
|
63
68
|
```
|
|
64
69
|
|
|
70
|
+
Site is auto-created if it doesn't exist. Name is saved to `.jetrrc` for next time. Uses incremental upload (10x concurrent) — only changed files are uploaded.
|
|
71
|
+
|
|
65
72
|
### `jetr list`
|
|
66
73
|
|
|
67
74
|
List your sites.
|
package/dist/cli.js
CHANGED
|
@@ -14,6 +14,7 @@ import { homedir } from "os";
|
|
|
14
14
|
var CONFIG_DIR = join(homedir(), ".jetr");
|
|
15
15
|
var CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
16
16
|
var DEFAULT_CONFIG = {
|
|
17
|
+
authUrl: "https://api.within-7.com",
|
|
17
18
|
apiUrl: "https://jetr-api.lixilei.workers.dev"
|
|
18
19
|
};
|
|
19
20
|
function loadConfig() {
|
|
@@ -39,6 +40,20 @@ function getToken() {
|
|
|
39
40
|
}
|
|
40
41
|
return config.token;
|
|
41
42
|
}
|
|
43
|
+
async function login(user, password) {
|
|
44
|
+
const config = loadConfig();
|
|
45
|
+
const res = await fetch(`${config.authUrl}/user/login`, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: { "Content-Type": "application/json" },
|
|
48
|
+
body: JSON.stringify({ user, password })
|
|
49
|
+
});
|
|
50
|
+
const body = await res.json();
|
|
51
|
+
if (!res.ok || !body.token) {
|
|
52
|
+
throw new Error(body.error || `Login failed: ${res.status}`);
|
|
53
|
+
}
|
|
54
|
+
saveConfig({ user: body.user || user, token: body.token });
|
|
55
|
+
return { user: body.user || user, token: body.token };
|
|
56
|
+
}
|
|
42
57
|
|
|
43
58
|
// src/api.ts
|
|
44
59
|
async function request(path, options = {}) {
|
|
@@ -54,6 +69,9 @@ async function request(path, options = {}) {
|
|
|
54
69
|
async function json(path, options = {}) {
|
|
55
70
|
const res = await request(path, options);
|
|
56
71
|
const body = await res.json();
|
|
72
|
+
if (res.status === 401) {
|
|
73
|
+
throw new Error("Token expired or invalid. Run: jetr login");
|
|
74
|
+
}
|
|
57
75
|
if (!res.ok) {
|
|
58
76
|
throw new Error(body.error || `API error: ${res.status}`);
|
|
59
77
|
}
|
|
@@ -404,10 +422,7 @@ program.argument("[directory]", "Directory to deploy (default: current directory
|
|
|
404
422
|
const config = loadConfig();
|
|
405
423
|
if (!config.token) {
|
|
406
424
|
console.error(chalk2.red("Not logged in."));
|
|
407
|
-
console.error(`Run: ${chalk2.cyan("jetr login
|
|
408
|
-
console.error(
|
|
409
|
-
chalk2.dim("Get your token from auth-gateway: POST /user/login")
|
|
410
|
-
);
|
|
425
|
+
console.error(`Run: ${chalk2.cyan("jetr login")}`);
|
|
411
426
|
process.exit(1);
|
|
412
427
|
}
|
|
413
428
|
let siteName = await resolveSiteName(dir, name);
|
|
@@ -461,18 +476,72 @@ program.argument("[directory]", "Directory to deploy (default: current directory
|
|
|
461
476
|
process.exit(1);
|
|
462
477
|
}
|
|
463
478
|
});
|
|
464
|
-
program.command("login").description("
|
|
465
|
-
|
|
466
|
-
|
|
479
|
+
program.command("login").description("Login with username and password").argument("[user]", "Username").argument("[password]", "Password").option("--token <token>", "Login directly with a JWT token").action(async (user, password, opts) => {
|
|
480
|
+
if (opts?.token) {
|
|
481
|
+
saveConfig({ token: opts.token });
|
|
482
|
+
console.log(chalk2.green("\u2713 Token saved"));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
const { createInterface: createInterface2 } = await import("readline");
|
|
486
|
+
if (!user) {
|
|
487
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
488
|
+
user = await new Promise((res) => {
|
|
489
|
+
rl.question("Username: ", (a) => {
|
|
490
|
+
rl.close();
|
|
491
|
+
res(a.trim());
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
if (!password) {
|
|
496
|
+
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
497
|
+
process.stdout.write("Password: ");
|
|
498
|
+
const stdin = process.stdin;
|
|
499
|
+
const wasRaw = stdin.isRaw;
|
|
500
|
+
if (stdin.isTTY) stdin.setRawMode(true);
|
|
501
|
+
password = await new Promise((res) => {
|
|
502
|
+
let buf = "";
|
|
503
|
+
const onData = (ch) => {
|
|
504
|
+
const c = ch.toString();
|
|
505
|
+
if (c === "\n" || c === "\r" || c === "") {
|
|
506
|
+
if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
|
|
507
|
+
stdin.removeListener("data", onData);
|
|
508
|
+
process.stdout.write("\n");
|
|
509
|
+
rl.close();
|
|
510
|
+
res(buf);
|
|
511
|
+
} else if (c === "") {
|
|
512
|
+
if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
|
|
513
|
+
process.exit(1);
|
|
514
|
+
} else if (c === "\x7F" || c === "\b") {
|
|
515
|
+
buf = buf.slice(0, -1);
|
|
516
|
+
} else {
|
|
517
|
+
buf += c;
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
stdin.on("data", onData);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
if (!user || !password) {
|
|
524
|
+
console.error(chalk2.red("Username and password required"));
|
|
525
|
+
process.exit(1);
|
|
526
|
+
}
|
|
527
|
+
const spinner = ora("Logging in...").start();
|
|
528
|
+
try {
|
|
529
|
+
const result = await login(user, password);
|
|
530
|
+
spinner.succeed(`Logged in as ${chalk2.bold(result.user)}`);
|
|
531
|
+
} catch (e) {
|
|
532
|
+
spinner.fail(e.message);
|
|
533
|
+
process.exit(1);
|
|
534
|
+
}
|
|
467
535
|
});
|
|
468
|
-
program.command("whoami").description("Show current
|
|
536
|
+
program.command("whoami").description("Show current login status").action(() => {
|
|
469
537
|
const config = loadConfig();
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
);
|
|
538
|
+
if (!config.token) {
|
|
539
|
+
console.log(chalk2.red("Not logged in."));
|
|
540
|
+
console.log(`Run: ${chalk2.cyan("jetr login")}`);
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
console.log(`User: ${chalk2.bold(config.user || "unknown")}`);
|
|
544
|
+
console.log(`Token: ${config.token.slice(0, 20)}...`);
|
|
476
545
|
});
|
|
477
546
|
program.command("init").description("Create .jetrignore with default patterns").argument("[directory]", "Target directory", ".").action(async (directory) => {
|
|
478
547
|
const created = createJetrignore(resolve2(directory));
|