@within-7/jetr 0.1.2 → 0.3.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.
Files changed (2) hide show
  1. package/dist/cli.js +361 -75
  2. package/package.json +3 -2
package/dist/cli.js CHANGED
@@ -1,8 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
+ import { resolve as resolve2, basename } from "path";
5
+ import { existsSync as existsSync4, statSync as statSync2 } from "fs";
4
6
  import { Command } from "commander";
5
- import chalk from "chalk";
7
+ import chalk2 from "chalk";
6
8
  import ora from "ora";
7
9
 
8
10
  // src/config.ts
@@ -128,34 +130,149 @@ var api = {
128
130
 
129
131
  // src/deploy.ts
130
132
  import { createHash } from "crypto";
131
- import { readFileSync as readFileSync2, statSync } from "fs";
132
- import { resolve, join as join2, posix } from "path";
133
+ import { readFileSync as readFileSync3, statSync } from "fs";
134
+ import { resolve, join as join3, posix } from "path";
133
135
  import { glob } from "glob";
136
+
137
+ // src/ignore.ts
138
+ import ignore from "ignore";
139
+ import { existsSync as existsSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
140
+ import { join as join2 } from "path";
141
+ var DEFAULT_JETRIGNORE = `# Dependencies
142
+ node_modules/
143
+ .pnp
144
+ .pnp.js
145
+
146
+ # Build outputs
147
+ dist/
148
+ build/
149
+ out/
150
+ .next/
151
+ .nuxt/
152
+ .output/
153
+ .cache/
154
+
155
+ # Logs
156
+ *.log
157
+ npm-debug.log*
158
+ yarn-debug.log*
159
+ yarn-error.log*
160
+ pnpm-debug.log*
161
+
162
+ # Environment
163
+ .env
164
+ .env.*
165
+ .env.local
166
+ .env.*.local
167
+
168
+ # IDE & Editor
169
+ .vscode/
170
+ .idea/
171
+ *.swp
172
+ *.swo
173
+ *~
174
+ .project
175
+ .classpath
176
+ .settings/
177
+
178
+ # OS files
179
+ .DS_Store
180
+ Thumbs.db
181
+ desktop.ini
182
+
183
+ # Git
184
+ .git/
185
+ .gitignore
186
+
187
+ # Testing
188
+ coverage/
189
+ .nyc_output/
190
+
191
+ # Package managers
192
+ package-lock.json
193
+ yarn.lock
194
+ pnpm-lock.yaml
195
+
196
+ # Misc
197
+ *.zip
198
+ *.tar.gz
199
+ `;
200
+ var ALWAYS_IGNORE = [".jetrignore", ".jetrkeep", ".jetrrc"];
201
+ function loadIgnore(dir) {
202
+ const ig = ignore();
203
+ ig.add(ALWAYS_IGNORE);
204
+ const ignorePath = join2(dir, ".jetrignore");
205
+ if (existsSync2(ignorePath)) {
206
+ const content = readFileSync2(ignorePath, "utf-8");
207
+ ig.add(content);
208
+ } else {
209
+ ig.add(DEFAULT_JETRIGNORE);
210
+ }
211
+ return ig;
212
+ }
213
+ function loadKeep(dir) {
214
+ const keepPath = join2(dir, ".jetrkeep");
215
+ if (!existsSync2(keepPath)) return null;
216
+ const keep = ignore();
217
+ keep.add(readFileSync2(keepPath, "utf-8"));
218
+ return keep;
219
+ }
220
+ function shouldInclude(relativePath, ig, keep) {
221
+ if (ig.ignores(relativePath) || ig.ignores(relativePath + "/")) {
222
+ if (keep && keep.ignores(relativePath)) {
223
+ return true;
224
+ }
225
+ return false;
226
+ }
227
+ return true;
228
+ }
229
+ function createJetrignore(dir) {
230
+ const ignorePath = join2(dir, ".jetrignore");
231
+ if (existsSync2(ignorePath)) return false;
232
+ writeFileSync2(ignorePath, DEFAULT_JETRIGNORE);
233
+ return true;
234
+ }
235
+
236
+ // src/deploy.ts
134
237
  function hashFile(filePath) {
135
- const content = readFileSync2(filePath);
238
+ const content = readFileSync3(filePath);
136
239
  const hash = createHash("sha256").update(content).digest("hex");
137
240
  return `sha256:${hash}`;
138
241
  }
139
242
  async function deploy(siteName, directory, onProgress) {
140
243
  const absDir = resolve(directory);
244
+ const ig = loadIgnore(absDir);
245
+ const keep = loadKeep(absDir);
141
246
  onProgress?.("Scanning files...");
142
- const filePaths = await glob("**/*", {
247
+ const allFiles = await glob("**/*", {
143
248
  cwd: absDir,
144
249
  nodir: true,
145
- dot: false
250
+ dot: true
146
251
  });
252
+ let ignoredCount = 0;
253
+ const filePaths = [];
254
+ for (const fp of allFiles) {
255
+ const normalizedPath = fp.split("/").join(posix.sep);
256
+ if (shouldInclude(normalizedPath, ig, keep)) {
257
+ filePaths.push(fp);
258
+ } else {
259
+ ignoredCount++;
260
+ }
261
+ }
147
262
  if (filePaths.length === 0) {
148
- throw new Error(`No files found in ${directory}`);
263
+ throw new Error(
264
+ `No files to deploy in ${directory} (${allFiles.length} files found, all ignored)`
265
+ );
149
266
  }
267
+ onProgress?.(`Found ${filePaths.length} files (${ignoredCount} ignored)`);
150
268
  const manifest = {};
151
269
  for (const fp of filePaths) {
152
- const absPath = join2(absDir, fp);
270
+ const absPath = join3(absDir, fp);
153
271
  const hash = hashFile(absPath);
154
272
  const size = statSync(absPath).size;
155
273
  const normalizedPath = fp.split("/").join(posix.sep);
156
274
  manifest[normalizedPath] = { hash, size };
157
275
  }
158
- onProgress?.(`Found ${filePaths.length} files`);
159
276
  onProgress?.("Computing diff...");
160
277
  const diff = await api.deployDiff(siteName, manifest);
161
278
  onProgress?.(
@@ -164,8 +281,8 @@ async function deploy(siteName, directory, onProgress) {
164
281
  if (diff.upload.length > 0) {
165
282
  for (let i = 0; i < diff.upload.length; i++) {
166
283
  const fp = diff.upload[i];
167
- const absPath = join2(absDir, fp);
168
- const content = readFileSync2(absPath);
284
+ const absPath = join3(absDir, fp);
285
+ const content = readFileSync3(absPath);
169
286
  onProgress?.(`Uploading (${i + 1}/${diff.upload.length}) ${fp}`);
170
287
  await api.uploadFile(siteName, fp, content, diff.deploy_id, manifest[fp].hash);
171
288
  }
@@ -177,50 +294,202 @@ async function deploy(siteName, directory, onProgress) {
177
294
  filesUploaded: result.files_uploaded,
178
295
  filesDeleted: result.files_deleted,
179
296
  filesUnchanged: diff.unchanged.length,
297
+ filesIgnored: ignoredCount,
180
298
  totalSize: result.total_size
181
299
  };
182
300
  }
183
301
 
302
+ // src/rc.ts
303
+ import { existsSync as existsSync3, readFileSync as readFileSync4, writeFileSync as writeFileSync3 } from "fs";
304
+ import { join as join4 } from "path";
305
+ import { createInterface } from "readline";
306
+ import chalk from "chalk";
307
+ var RC_FILE = ".jetrrc";
308
+ function loadRc(dir) {
309
+ const rcPath = join4(dir, RC_FILE);
310
+ if (!existsSync3(rcPath)) return {};
311
+ try {
312
+ return JSON.parse(readFileSync4(rcPath, "utf-8"));
313
+ } catch {
314
+ return {};
315
+ }
316
+ }
317
+ function saveRc(dir, config) {
318
+ writeFileSync3(join4(dir, RC_FILE), JSON.stringify(config, null, 2) + "\n");
319
+ }
320
+ function updateRc(config, siteName) {
321
+ if (!config.directory) {
322
+ config.directory = { default: siteName, history: [siteName] };
323
+ } else {
324
+ config.directory.default = siteName;
325
+ if (!config.directory.history.includes(siteName)) {
326
+ config.directory.history.push(siteName);
327
+ }
328
+ }
329
+ return config;
330
+ }
331
+ async function resolveSiteName(dir, explicitName) {
332
+ if (explicitName) return explicitName;
333
+ const rc = loadRc(dir);
334
+ const saved = rc.directory;
335
+ if (!saved) return null;
336
+ const history = saved.history || [saved.default];
337
+ const options = [
338
+ saved.default,
339
+ ...history.filter((h) => h !== saved.default)
340
+ ];
341
+ if (options.length === 1) {
342
+ console.log(chalk.dim(`Using saved site: ${options[0]}`));
343
+ return options[0];
344
+ }
345
+ return promptSelection(options);
346
+ }
347
+ async function promptSelection(options) {
348
+ const rl = createInterface({
349
+ input: process.stdin,
350
+ output: process.stdout
351
+ });
352
+ console.log();
353
+ console.log(chalk.bold("Previous deployments:"));
354
+ for (let i = 0; i < options.length; i++) {
355
+ const marker = i === 0 ? chalk.green(" (default)") : "";
356
+ console.log(` ${chalk.cyan(String(i + 1))}) ${options[i]}${marker}`);
357
+ }
358
+ console.log(
359
+ ` ${chalk.cyan(String(options.length + 1))}) ${chalk.dim("Enter new site name")}`
360
+ );
361
+ console.log();
362
+ return new Promise((resolve3) => {
363
+ rl.question(chalk.bold("Select [1]: "), (answer) => {
364
+ rl.close();
365
+ const num = parseInt(answer, 10);
366
+ if (!answer || isNaN(num) || num < 1 || num > options.length + 1) {
367
+ resolve3(options[0]);
368
+ } else if (num <= options.length) {
369
+ resolve3(options[num - 1]);
370
+ } else {
371
+ const rl2 = createInterface({
372
+ input: process.stdin,
373
+ output: process.stdout
374
+ });
375
+ rl2.question(chalk.bold("Site name: "), (name) => {
376
+ rl2.close();
377
+ resolve3(name.trim());
378
+ });
379
+ }
380
+ });
381
+ });
382
+ }
383
+
184
384
  // src/cli.ts
185
385
  var program = new Command();
186
- program.name("jetr").description("CLI for Jetr static site hosting").version("0.1.0");
386
+ program.name("jetr").description("Deploy static sites instantly").version("0.2.0");
387
+ program.argument("[directory]", "Directory to deploy (default: current directory)").argument("[name]", "Site name (reads from .jetrrc if omitted)").option("--no-ignore", "Skip .jetrignore rules").action(async (directory, name) => {
388
+ const dir = resolve2(directory || ".");
389
+ if (!existsSync4(dir)) {
390
+ console.error(chalk2.red(`Path not found: ${dir}`));
391
+ process.exit(1);
392
+ }
393
+ if (!statSync2(dir).isDirectory()) {
394
+ console.error(chalk2.red(`Not a directory: ${dir}`));
395
+ process.exit(1);
396
+ }
397
+ const config = loadConfig();
398
+ if (!config.token) {
399
+ console.error(chalk2.red("Not logged in."));
400
+ console.error(`Run: ${chalk2.cyan("jetr login <token>")}`);
401
+ console.error(
402
+ chalk2.dim("Get your token from auth-gateway: POST /user/login")
403
+ );
404
+ process.exit(1);
405
+ }
406
+ let siteName = await resolveSiteName(dir, name);
407
+ if (!siteName) {
408
+ const dirName = basename(resolve2(dir));
409
+ const { createInterface: createInterface2 } = await import("readline");
410
+ const rl = createInterface2({
411
+ input: process.stdin,
412
+ output: process.stdout
413
+ });
414
+ siteName = await new Promise((res) => {
415
+ rl.question(
416
+ chalk2.bold(`Site name [${dirName}]: `),
417
+ (answer) => {
418
+ rl.close();
419
+ res(answer.trim() || dirName);
420
+ }
421
+ );
422
+ });
423
+ }
424
+ siteName = siteName.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+|-+$/g, "").replace(/-+/g, "-");
425
+ if (!siteName) {
426
+ console.error(chalk2.red("Invalid site name"));
427
+ process.exit(1);
428
+ }
429
+ const spinner = ora("").start();
430
+ try {
431
+ spinner.text = "Checking site...";
432
+ try {
433
+ await api.getSite(siteName);
434
+ } catch {
435
+ spinner.text = `Creating site ${siteName}...`;
436
+ await api.createSite(siteName);
437
+ }
438
+ const result = await deploy(siteName, dir, (msg) => {
439
+ spinner.text = msg;
440
+ });
441
+ spinner.succeed("Deployed!");
442
+ console.log();
443
+ console.log(` ${chalk2.bold("Site:")} ${chalk2.cyan(siteName)}`);
444
+ console.log(` ${chalk2.bold("URL:")} ${chalk2.green(result.url)}`);
445
+ console.log(
446
+ ` ${chalk2.bold("Files:")} ${result.filesUploaded} uploaded` + (result.filesDeleted > 0 ? `, ${result.filesDeleted} deleted` : "") + (result.filesUnchanged > 0 ? `, ${result.filesUnchanged} unchanged` : "") + (result.filesIgnored > 0 ? chalk2.dim(` (${result.filesIgnored} ignored)`) : "")
447
+ );
448
+ console.log(` ${chalk2.bold("Size:")} ${formatBytes(result.totalSize)}`);
449
+ console.log();
450
+ const rc = loadRc(dir);
451
+ saveRc(dir, updateRc(rc, siteName));
452
+ } catch (e) {
453
+ spinner.fail(e.message);
454
+ process.exit(1);
455
+ }
456
+ });
187
457
  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) => {
188
458
  saveConfig({ token, ...opts.apiUrl ? { apiUrl: opts.apiUrl } : {} });
189
- console.log(chalk.green("\u2713 Token saved to ~/.jetr/config.json"));
459
+ console.log(chalk2.green("\u2713 Token saved to ~/.jetr/config.json"));
190
460
  });
191
461
  program.command("whoami").description("Show current config").action(() => {
192
462
  const config = loadConfig();
193
- console.log(`API: ${config.apiUrl}`);
194
- console.log(`Token: ${config.token ? config.token.slice(0, 20) + "..." : chalk.red("not set")}`);
463
+ console.log(
464
+ `API: ${config.apiUrl}`
465
+ );
466
+ console.log(
467
+ `Token: ${config.token ? config.token.slice(0, 20) + "..." : chalk2.red("not set")}`
468
+ );
195
469
  });
196
- program.command("create").description("Create a new site").argument("<name>", "Site name (becomes {name}.jetr.within-7.com)").option("-p, --password <password>", "Set access password").option("-e, --expires <seconds>", "Expire after N seconds", parseInt).action(async (name, opts) => {
470
+ program.command("init").description("Create .jetrignore with default patterns").argument("[directory]", "Target directory", ".").action(async (directory) => {
471
+ const created = createJetrignore(resolve2(directory));
472
+ if (created) {
473
+ console.log(chalk2.green("\u2713 Created .jetrignore with default patterns"));
474
+ } else {
475
+ console.log(chalk2.yellow(".jetrignore already exists"));
476
+ }
477
+ });
478
+ 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) => {
197
479
  const spinner = ora("Creating site...").start();
198
480
  try {
199
481
  const site = await api.createSite(name, {
200
482
  password: opts.password,
201
483
  expires_in: opts.expires
202
484
  });
203
- spinner.succeed(`Created ${chalk.bold(site.name)}`);
204
- console.log(` URL: ${chalk.cyan(site.url)}`);
205
- if (site.password_protected) console.log(` Password: ${chalk.yellow("enabled")}`);
206
- if (site.expires_at) console.log(` Expires: ${new Date(site.expires_at * 1e3).toISOString()}`);
207
- } catch (e) {
208
- spinner.fail(e.message);
209
- process.exit(1);
210
- }
211
- });
212
- program.command("deploy").description("Deploy a directory to a site").argument("<name>", "Site name").argument("[directory]", "Directory to deploy", ".").action(async (name, directory) => {
213
- const spinner = ora("").start();
214
- try {
215
- const result = await deploy(name, directory, (msg) => {
216
- spinner.text = msg;
217
- });
218
- spinner.succeed("Deployed!");
219
- console.log(` URL: ${chalk.cyan(result.url)}`);
220
- console.log(` Uploaded: ${result.filesUploaded} files`);
221
- if (result.filesDeleted > 0) console.log(` Deleted: ${result.filesDeleted} files`);
222
- if (result.filesUnchanged > 0) console.log(` Unchanged: ${result.filesUnchanged} files`);
223
- console.log(` Size: ${formatBytes(result.totalSize)}`);
485
+ spinner.succeed(`Created ${chalk2.bold(site.name)}`);
486
+ console.log(` URL: ${chalk2.cyan(site.url)}`);
487
+ if (site.password_protected)
488
+ console.log(` Password: ${chalk2.yellow("enabled")}`);
489
+ if (site.expires_at)
490
+ console.log(
491
+ ` Expires: ${new Date(site.expires_at * 1e3).toISOString()}`
492
+ );
224
493
  } catch (e) {
225
494
  spinner.fail(e.message);
226
495
  process.exit(1);
@@ -230,51 +499,63 @@ program.command("list").alias("ls").description("List your sites").action(async
230
499
  try {
231
500
  const { sites } = await api.listSites();
232
501
  if (sites.length === 0) {
233
- console.log(chalk.dim("No sites yet. Create one: jetr create <name>"));
502
+ console.log(
503
+ chalk2.dim("No sites yet. Run: jetr <directory> to deploy")
504
+ );
234
505
  return;
235
506
  }
236
507
  for (const s of sites) {
237
- const lock = s.password_protected ? chalk.yellow(" \u{1F512}") : "";
238
- const expire = s.expires_at ? chalk.dim(` expires ${new Date(s.expires_at * 1e3).toLocaleDateString()}`) : "";
508
+ const lock = s.password_protected ? chalk2.yellow(" \u{1F512}") : "";
509
+ const expire = s.expires_at ? chalk2.dim(
510
+ ` expires ${new Date(s.expires_at * 1e3).toLocaleDateString()}`
511
+ ) : "";
239
512
  console.log(
240
- ` ${chalk.bold(s.name)}${lock}${expire} ${chalk.dim(formatBytes(s.total_size))} ${chalk.cyan(s.url)}`
513
+ ` ${chalk2.bold(s.name)}${lock}${expire} ${chalk2.dim(formatBytes(s.total_size))} ${chalk2.cyan(s.url)}`
241
514
  );
242
515
  }
243
- console.log(chalk.dim(`
516
+ console.log(chalk2.dim(`
244
517
  ${sites.length} site(s)`));
245
518
  } catch (e) {
246
- console.error(chalk.red(e.message));
519
+ console.error(chalk2.red(e.message));
247
520
  process.exit(1);
248
521
  }
249
522
  });
250
523
  program.command("info").description("Show site details").argument("<name>", "Site name").action(async (name) => {
251
524
  try {
252
525
  const site = await api.getSite(name);
253
- console.log(`${chalk.bold(site.name)}`);
254
- console.log(` URL: ${chalk.cyan(site.url)}`);
255
- console.log(` Password: ${site.password_protected ? chalk.yellow("yes") : "no"}`);
256
- console.log(` Expires: ${site.expires_at ? new Date(site.expires_at * 1e3).toISOString() : "never"}`);
526
+ console.log(`${chalk2.bold(site.name)}`);
527
+ console.log(` URL: ${chalk2.cyan(site.url)}`);
528
+ console.log(
529
+ ` Password: ${site.password_protected ? chalk2.yellow("yes") : "no"}`
530
+ );
531
+ console.log(
532
+ ` Expires: ${site.expires_at ? new Date(site.expires_at * 1e3).toISOString() : "never"}`
533
+ );
257
534
  console.log(` Files: ${site.files.length}`);
258
- console.log(` Created: ${new Date(site.created_at * 1e3).toISOString()}`);
259
- console.log(` Updated: ${new Date(site.updated_at * 1e3).toISOString()}`);
535
+ console.log(
536
+ ` Created: ${new Date(site.created_at * 1e3).toISOString()}`
537
+ );
538
+ console.log(
539
+ ` Updated: ${new Date(site.updated_at * 1e3).toISOString()}`
540
+ );
260
541
  if (site.files.length > 0) {
261
542
  console.log(`
262
- ${chalk.dim("Files:")}`);
543
+ ${chalk2.dim("Files:")}`);
263
544
  for (const f of site.files) {
264
- console.log(` ${f.path} ${chalk.dim(formatBytes(f.size))}`);
545
+ console.log(` ${f.path} ${chalk2.dim(formatBytes(f.size))}`);
265
546
  }
266
547
  }
267
548
  if (site.tokens.length > 0) {
268
549
  console.log(`
269
- ${chalk.dim("Tokens:")}`);
550
+ ${chalk2.dim("Tokens:")}`);
270
551
  for (const t of site.tokens) {
271
552
  const note = t.note ? ` (${t.note})` : "";
272
553
  const exp = t.expires_at ? ` expires ${new Date(t.expires_at * 1e3).toLocaleDateString()}` : "";
273
- console.log(` ${t.id}${note}${chalk.dim(exp)}`);
554
+ console.log(` ${t.id}${note}${chalk2.dim(exp)}`);
274
555
  }
275
556
  }
276
557
  } catch (e) {
277
- console.error(chalk.red(e.message));
558
+ console.error(chalk2.red(e.message));
278
559
  process.exit(1);
279
560
  }
280
561
  });
@@ -282,7 +563,7 @@ program.command("delete").alias("rm").description("Delete a site and all its fil
282
563
  const spinner = ora(`Deleting ${name}...`).start();
283
564
  try {
284
565
  await api.deleteSite(name);
285
- spinner.succeed(`Deleted ${chalk.bold(name)}`);
566
+ spinner.succeed(`Deleted ${chalk2.bold(name)}`);
286
567
  } catch (e) {
287
568
  spinner.fail(e.message);
288
569
  process.exit(1);
@@ -292,38 +573,43 @@ program.command("password").description("Set or remove site password").argument(
292
573
  try {
293
574
  const site = await api.updateSite(name, { password: password ?? null });
294
575
  if (site.password_protected) {
295
- console.log(chalk.green(`\u2713 Password set for ${chalk.bold(name)}`));
576
+ console.log(chalk2.green(`\u2713 Password set for ${chalk2.bold(name)}`));
296
577
  } else {
297
- console.log(chalk.green(`\u2713 Password removed from ${chalk.bold(name)}`));
578
+ console.log(chalk2.green(`\u2713 Password removed from ${chalk2.bold(name)}`));
298
579
  }
299
580
  } catch (e) {
300
- console.error(chalk.red(e.message));
581
+ console.error(chalk2.red(e.message));
301
582
  process.exit(1);
302
583
  }
303
584
  });
304
585
  var tokenCmd = program.command("token").description("Manage share tokens");
305
- 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(async (site, opts) => {
306
- try {
307
- const token = await api.createToken(site, {
308
- note: opts.note,
309
- expires_in: opts.expires
310
- });
311
- console.log(chalk.green("\u2713 Token created"));
312
- console.log(` ID: ${token.id}`);
313
- console.log(` URL: ${chalk.cyan(token.url)}`);
314
- if (token.note) console.log(` Note: ${token.note}`);
315
- if (token.expires_at) console.log(` Expires: ${new Date(token.expires_at * 1e3).toISOString()}`);
316
- } catch (e) {
317
- console.error(chalk.red(e.message));
318
- process.exit(1);
586
+ 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(
587
+ async (site, opts) => {
588
+ try {
589
+ const token = await api.createToken(site, {
590
+ note: opts.note,
591
+ expires_in: opts.expires
592
+ });
593
+ console.log(chalk2.green("\u2713 Token created"));
594
+ console.log(` ID: ${token.id}`);
595
+ console.log(` URL: ${chalk2.cyan(token.url)}`);
596
+ if (token.note) console.log(` Note: ${token.note}`);
597
+ if (token.expires_at)
598
+ console.log(
599
+ ` Expires: ${new Date(token.expires_at * 1e3).toISOString()}`
600
+ );
601
+ } catch (e) {
602
+ console.error(chalk2.red(e.message));
603
+ process.exit(1);
604
+ }
319
605
  }
320
- });
606
+ );
321
607
  tokenCmd.command("revoke").description("Revoke a share token").argument("<site>", "Site name").argument("<id>", "Token ID").action(async (site, id) => {
322
608
  try {
323
609
  await api.revokeToken(site, id);
324
- console.log(chalk.green(`\u2713 Token ${id} revoked`));
610
+ console.log(chalk2.green(`\u2713 Token ${id} revoked`));
325
611
  } catch (e) {
326
- console.error(chalk.red(e.message));
612
+ console.error(chalk2.red(e.message));
327
613
  process.exit(1);
328
614
  }
329
615
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@within-7/jetr",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for Jetr static site hosting",
5
5
  "type": "module",
6
6
  "bin": {
@@ -16,7 +16,8 @@
16
16
  "commander": "^13",
17
17
  "chalk": "^5",
18
18
  "ora": "^8",
19
- "glob": "^11"
19
+ "glob": "^11",
20
+ "ignore": "^6"
20
21
  },
21
22
  "devDependencies": {
22
23
  "tsup": "^8",