@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.
Files changed (3) hide show
  1. package/README.md +26 -19
  2. package/dist/cli.js +83 -14
  3. 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 with your JWT token (from auth-gateway)
21
- jetr login <token>
22
-
23
- # 2. Create a site
24
- jetr create my-blog
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. Deploy
27
- jetr deploy my-blog ./dist
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 <token>`
40
+ ### `jetr login [user] [password]`
37
41
 
38
- Save JWT token for authentication. Token is stored in `~/.jetr/config.json`.
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 eyJhbGciOiJIUzI1NiJ9...
42
- jetr login <token> --api-url https://custom-api.example.com
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 deploy <name> [directory]`
60
+ ### `jetr [directory] [name]`
56
61
 
57
- Deploy a directory to a site. Uses incremental upload only changed files are uploaded.
62
+ Deploy a directory. This is the default commandjust run `jetr` in your project.
58
63
 
59
64
  ```bash
60
- jetr deploy my-blog ./dist
61
- jetr deploy my-blog . # deploy current directory
62
- jetr deploy my-blog # defaults to current directory
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 <token>")}`);
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("Save JWT token for authentication").argument("<token>", "JWT token from auth-gateway login").option("--api-url <url>", "API base URL").action((token, opts) => {
465
- saveConfig({ token, ...opts.apiUrl ? { apiUrl: opts.apiUrl } : {} });
466
- console.log(chalk2.green("\u2713 Token saved to ~/.jetr/config.json"));
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 config").action(() => {
536
+ program.command("whoami").description("Show current login status").action(() => {
469
537
  const config = loadConfig();
470
- console.log(
471
- `API: ${config.apiUrl}`
472
- );
473
- console.log(
474
- `Token: ${config.token ? config.token.slice(0, 20) + "..." : chalk2.red("not set")}`
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));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@within-7/jetr",
3
- "version": "0.3.1",
3
+ "version": "0.4.1",
4
4
  "description": "CLI for Jetr static site hosting",
5
5
  "type": "module",
6
6
  "bin": {