@within-7/jetr 0.3.0 → 0.4.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/README.md +26 -19
- package/dist/cli.js +74 -17
- 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
|
}
|
|
@@ -279,12 +297,19 @@ async function deploy(siteName, directory, onProgress) {
|
|
|
279
297
|
`Upload: ${diff.upload.length}, Delete: ${diff.delete.length}, Unchanged: ${diff.unchanged.length}`
|
|
280
298
|
);
|
|
281
299
|
if (diff.upload.length > 0) {
|
|
282
|
-
|
|
283
|
-
|
|
300
|
+
const CONCURRENCY = 10;
|
|
301
|
+
let completed = 0;
|
|
302
|
+
const total = diff.upload.length;
|
|
303
|
+
const uploadOne = async (fp) => {
|
|
284
304
|
const absPath = join3(absDir, fp);
|
|
285
305
|
const content = readFileSync3(absPath);
|
|
286
|
-
onProgress?.(`Uploading (${i + 1}/${diff.upload.length}) ${fp}`);
|
|
287
306
|
await api.uploadFile(siteName, fp, content, diff.deploy_id, manifest[fp].hash);
|
|
307
|
+
completed++;
|
|
308
|
+
onProgress?.(`Uploading (${completed}/${total}) ${fp}`);
|
|
309
|
+
};
|
|
310
|
+
for (let i = 0; i < total; i += CONCURRENCY) {
|
|
311
|
+
const batch = diff.upload.slice(i, i + CONCURRENCY);
|
|
312
|
+
await Promise.all(batch.map(uploadOne));
|
|
288
313
|
}
|
|
289
314
|
}
|
|
290
315
|
onProgress?.("Finalizing...");
|
|
@@ -397,10 +422,7 @@ program.argument("[directory]", "Directory to deploy (default: current directory
|
|
|
397
422
|
const config = loadConfig();
|
|
398
423
|
if (!config.token) {
|
|
399
424
|
console.error(chalk2.red("Not logged in."));
|
|
400
|
-
console.error(`Run: ${chalk2.cyan("jetr login
|
|
401
|
-
console.error(
|
|
402
|
-
chalk2.dim("Get your token from auth-gateway: POST /user/login")
|
|
403
|
-
);
|
|
425
|
+
console.error(`Run: ${chalk2.cyan("jetr login")}`);
|
|
404
426
|
process.exit(1);
|
|
405
427
|
}
|
|
406
428
|
let siteName = await resolveSiteName(dir, name);
|
|
@@ -454,18 +476,53 @@ program.argument("[directory]", "Directory to deploy (default: current directory
|
|
|
454
476
|
process.exit(1);
|
|
455
477
|
}
|
|
456
478
|
});
|
|
457
|
-
program.command("login").description("
|
|
458
|
-
|
|
459
|
-
|
|
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
|
+
password = await new Promise((res) => {
|
|
498
|
+
rl.question("Password: ", (a) => {
|
|
499
|
+
rl.close();
|
|
500
|
+
res(a.trim());
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
if (!user || !password) {
|
|
505
|
+
console.error(chalk2.red("Username and password required"));
|
|
506
|
+
process.exit(1);
|
|
507
|
+
}
|
|
508
|
+
const spinner = ora("Logging in...").start();
|
|
509
|
+
try {
|
|
510
|
+
const result = await login(user, password);
|
|
511
|
+
spinner.succeed(`Logged in as ${chalk2.bold(result.user)}`);
|
|
512
|
+
} catch (e) {
|
|
513
|
+
spinner.fail(e.message);
|
|
514
|
+
process.exit(1);
|
|
515
|
+
}
|
|
460
516
|
});
|
|
461
|
-
program.command("whoami").description("Show current
|
|
517
|
+
program.command("whoami").description("Show current login status").action(() => {
|
|
462
518
|
const config = loadConfig();
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
);
|
|
519
|
+
if (!config.token) {
|
|
520
|
+
console.log(chalk2.red("Not logged in."));
|
|
521
|
+
console.log(`Run: ${chalk2.cyan("jetr login")}`);
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
console.log(`User: ${chalk2.bold(config.user || "unknown")}`);
|
|
525
|
+
console.log(`Token: ${config.token.slice(0, 20)}...`);
|
|
469
526
|
});
|
|
470
527
|
program.command("init").description("Create .jetrignore with default patterns").argument("[directory]", "Target directory", ".").action(async (directory) => {
|
|
471
528
|
const created = createJetrignore(resolve2(directory));
|