@within-7/jetr 0.7.1 → 0.7.3

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 (2) hide show
  1. package/dist/cli.js +52 -23
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -147,6 +147,10 @@ var api = {
147
147
  async listDomains(name) {
148
148
  return json(`/sites/${name}/domains`);
149
149
  },
150
+ async lookupDomain(hostname) {
151
+ const data = await json(`/domains/lookup?hostname=${encodeURIComponent(hostname)}`);
152
+ return data.site;
153
+ },
150
154
  async addDomain(name, hostname) {
151
155
  return json(`/sites/${name}/domains`, {
152
156
  method: "POST",
@@ -469,8 +473,22 @@ async function promptSelection(options) {
469
473
 
470
474
  // src/cli.ts
471
475
  var program = new Command();
472
- program.name("jetr").description("Deploy static sites instantly").version("0.2.0");
473
- program.argument("[paths...]", "Files or directory to deploy").action(async (paths) => {
476
+ program.name("jetr").description(`Deploy static sites instantly to {name}.jetr.within-7.com
477
+
478
+ Just run "jetr" in any directory to deploy. First time? Run "jetr login" first.
479
+
480
+ The name can be a simple name (gets .jetr.within-7.com subdomain) or a full
481
+ domain like docs.within-7.com or blog.example.com for custom domain hosting.
482
+
483
+ Examples:
484
+ $ jetr Deploy current directory (random name or from .jetrrc)
485
+ $ jetr ./dist Deploy the ./dist directory
486
+ $ jetr ./dist my-blog Deploy as my-blog.jetr.within-7.com
487
+ $ jetr ./dist docs.within-7.com Deploy to custom domain (auto-configures route)
488
+ $ jetr ./dist blog.example.com Deploy to external domain (shows DNS setup)
489
+ $ jetr index.html Deploy a single file
490
+ $ jetr *.html *.css my-site Deploy multiple files to a named site`).version("0.7.1");
491
+ program.argument("[paths...]", "directory, file(s), and/or site name to deploy").action(async (paths) => {
474
492
  const config = loadConfig();
475
493
  if (!config.token) {
476
494
  console.error(chalk2.red("Not logged in."));
@@ -487,21 +505,32 @@ program.argument("[paths...]", "Files or directory to deploy").action(async (pat
487
505
  console.log(chalk2.dim(`File mode: ${files.map((f) => basename2(f)).join(", ")}`));
488
506
  }
489
507
  const isCustomDomain = rawName.includes(".");
490
- const siteName = isCustomDomain ? sanitizeName(rawName.replace(/\./g, "-")) || generateName() : sanitizeName(rawName) || generateName();
491
508
  const customHostname = isCustomDomain ? rawName.toLowerCase().trim() : null;
509
+ let siteName;
492
510
  const spinner = ora("").start();
493
511
  try {
494
- await ensureSiteExists(spinner, siteName);
495
512
  if (customHostname) {
496
- spinner.text = `Binding domain ${customHostname}...`;
497
- try {
498
- const domainResult = await api.addDomain(siteName, customHostname);
499
- if (domainResult.route_registered) {
500
- spinner.text = `Route registered for ${customHostname}`;
513
+ spinner.text = `Resolving ${customHostname}...`;
514
+ const existingSite = await api.lookupDomain(customHostname);
515
+ if (existingSite) {
516
+ siteName = existingSite;
517
+ } else {
518
+ if (customHostname.endsWith(".within-7.com")) {
519
+ siteName = customHostname.split(".")[0];
520
+ } else {
521
+ siteName = sanitizeName(customHostname.replace(/\./g, "-")) || generateName();
522
+ }
523
+ await ensureSiteExists(spinner, siteName);
524
+ spinner.text = `Binding ${customHostname}...`;
525
+ try {
526
+ await api.addDomain(siteName, customHostname);
527
+ } catch (e) {
528
+ if (!e.message.includes("already in use")) throw e;
501
529
  }
502
- } catch (e) {
503
- if (!e.message.includes("already in use")) throw e;
504
530
  }
531
+ } else {
532
+ siteName = sanitizeName(rawName) || generateName();
533
+ await ensureSiteExists(spinner, siteName);
505
534
  }
506
535
  const result = mode === "directory" ? await deploy(siteName, dir, (msg) => {
507
536
  spinner.text = msg;
@@ -539,7 +568,7 @@ program.argument("[paths...]", "Files or directory to deploy").action(async (pat
539
568
  process.exit(1);
540
569
  }
541
570
  });
542
- 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) => {
571
+ program.command("login").description("Authenticate with auth-gateway (interactive prompts if args omitted)").argument("[user]", "your username").argument("[password]", "your password (hidden input if omitted)").option("--token <token>", "skip login, use a JWT token directly (for CI/scripts)").action(async (user, password, opts) => {
543
572
  if (opts?.token) {
544
573
  saveConfig({ token: opts.token });
545
574
  console.log(chalk2.green("\u2713 Token saved"));
@@ -571,7 +600,7 @@ program.command("login").description("Login with username and password").argumen
571
600
  process.exit(1);
572
601
  }
573
602
  });
574
- program.command("whoami").description("Show current login status").action(() => {
603
+ program.command("whoami").description("Show who is logged in").action(() => {
575
604
  const config = loadConfig();
576
605
  if (!config.token) {
577
606
  console.log(chalk2.red("Not logged in."));
@@ -581,11 +610,11 @@ program.command("whoami").description("Show current login status").action(() =>
581
610
  console.log(`User: ${chalk2.bold(config.user || "unknown")}`);
582
611
  console.log(`Token: ${config.token.slice(0, 20)}...`);
583
612
  });
584
- program.command("logout").description("Clear saved login credentials").action(() => {
613
+ program.command("logout").description("Clear saved credentials (~/.jetr/config.json)").action(() => {
585
614
  saveConfig({ user: void 0, token: void 0 });
586
615
  console.log(chalk2.green("\u2713 Logged out"));
587
616
  });
588
- program.command("init").description("Create .jetrignore with default patterns").argument("[directory]", "Target directory", ".").action(async (directory) => {
617
+ program.command("init").description("Generate .jetrignore with sensible defaults (node_modules, .env, .git, etc)").argument("[directory]", "target directory", ".").action(async (directory) => {
589
618
  const created = createJetrignore(resolve2(directory));
590
619
  if (created) {
591
620
  console.log(chalk2.green("\u2713 Created .jetrignore with default patterns"));
@@ -593,7 +622,7 @@ program.command("init").description("Create .jetrignore with default patterns").
593
622
  console.log(chalk2.yellow(".jetrignore already exists"));
594
623
  }
595
624
  });
596
- program.command("create").description("Create a new site").argument("<name>", "Site name").option("-p, --password <password>", "Set access password").option("-e, --expires <seconds>", "Expire after N seconds", parseInt).action(async (name, opts) => {
625
+ program.command("create").description("Create an empty site without deploying files").argument("<name>", "site name (e.g. my-blog) or domain (e.g. docs.example.com)").option("-p, --password <password>", "require password to view the site").option("-e, --expires <seconds>", "auto-delete after N seconds (e.g. 86400 = 1 day)", parseInt).action(async (name, opts) => {
597
626
  const spinner = ora("Creating site...").start();
598
627
  try {
599
628
  const site = await api.createSite(name, {
@@ -613,7 +642,7 @@ program.command("create").description("Create a new site").argument("<name>", "S
613
642
  process.exit(1);
614
643
  }
615
644
  });
616
- program.command("list").alias("ls").description("List your sites").action(async () => {
645
+ program.command("list").alias("ls").description("List all your deployed sites").action(async () => {
617
646
  try {
618
647
  const { sites } = await api.listSites();
619
648
  if (sites.length === 0) {
@@ -638,7 +667,7 @@ program.command("list").alias("ls").description("List your sites").action(async
638
667
  process.exit(1);
639
668
  }
640
669
  });
641
- program.command("info").description("Show site details").argument("<name>", "Site name").action(async (name) => {
670
+ program.command("info").description("Show site details: files, tokens, config").argument("<name>", "site name").action(async (name) => {
642
671
  try {
643
672
  const site = await api.getSite(name);
644
673
  console.log(`${chalk2.bold(site.name)}`);
@@ -677,7 +706,7 @@ program.command("info").description("Show site details").argument("<name>", "Sit
677
706
  process.exit(1);
678
707
  }
679
708
  });
680
- program.command("delete").alias("rm").description("Delete a site and all its files").argument("<name>", "Site name").action(async (name) => {
709
+ program.command("delete").alias("rm").description("Permanently delete a site, all its files, and custom domains").argument("<name>", "site name").action(async (name) => {
681
710
  const spinner = ora(`Deleting ${name}...`).start();
682
711
  try {
683
712
  await api.deleteSite(name);
@@ -687,7 +716,7 @@ program.command("delete").alias("rm").description("Delete a site and all its fil
687
716
  process.exit(1);
688
717
  }
689
718
  });
690
- program.command("password").description("Set or remove site password").argument("<name>", "Site name").argument("[password]", "New password (omit to remove)").action(async (name, password) => {
719
+ program.command("password").description("Set a visitor password, or remove it (omit password to remove)").argument("<name>", "site name").argument("[password]", "new password (omit to make site public)").action(async (name, password) => {
691
720
  try {
692
721
  const site = await api.updateSite(name, { password: password ?? null });
693
722
  if (site.password_protected) {
@@ -700,8 +729,8 @@ program.command("password").description("Set or remove site password").argument(
700
729
  process.exit(1);
701
730
  }
702
731
  });
703
- var tokenCmd = program.command("token").description("Manage share tokens");
704
- tokenCmd.command("create").description("Create a share token").argument("<site>", "Site name").option("-n, --note <note>", "Token note").option("-e, --expires <seconds>", "Expire after N seconds", parseInt).action(
732
+ var tokenCmd = program.command("token").description("Generate or revoke share links for password-protected sites");
733
+ tokenCmd.command("create").description("Generate a share URL that bypasses password (e.g. for QA team)").argument("<site>", "site name").option("-n, --note <note>", "label for this token (e.g. 'QA team')").option("-e, --expires <seconds>", "auto-expire after N seconds", parseInt).action(
705
734
  async (site, opts) => {
706
735
  try {
707
736
  const token = await api.createToken(site, {
@@ -722,7 +751,7 @@ tokenCmd.command("create").description("Create a share token").argument("<site>"
722
751
  }
723
752
  }
724
753
  );
725
- tokenCmd.command("revoke").description("Revoke a share token").argument("<site>", "Site name").argument("<id>", "Token ID").action(async (site, id) => {
754
+ tokenCmd.command("revoke").description("Revoke a share link (get ID from `jetr info <site>`)").argument("<site>", "site name").argument("<id>", "token ID").action(async (site, id) => {
726
755
  try {
727
756
  await api.revokeToken(site, id);
728
757
  console.log(chalk2.green(`\u2713 Token ${id} revoked`));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@within-7/jetr",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "CLI for Jetr static site hosting",
5
5
  "type": "module",
6
6
  "bin": {