vslides 1.0.9 → 1.0.11

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 +116 -26
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -3126,8 +3126,8 @@ function clearCLIAuth() {
3126
3126
  if ((0, import_node_fs.existsSync)(AUTH_FILE)) {
3127
3127
  try {
3128
3128
  (0, import_node_fs.writeFileSync)(AUTH_FILE, "{}");
3129
- const { unlinkSync } = require("node:fs");
3130
- unlinkSync(AUTH_FILE);
3129
+ const { unlinkSync: unlinkSync2 } = require("node:fs");
3130
+ unlinkSync2(AUTH_FILE);
3131
3131
  } catch {
3132
3132
  }
3133
3133
  }
@@ -3204,6 +3204,18 @@ async function getShare(slug, token) {
3204
3204
  async function getJoin(code) {
3205
3205
  return request(`/api/share/${code}`);
3206
3206
  }
3207
+ async function authenticateToShare(code, cliAuthToken) {
3208
+ return request(`/api/share/${code}/authenticate`, {
3209
+ method: "POST",
3210
+ headers: {
3211
+ "X-CLI-Auth-Token": cliAuthToken,
3212
+ "Content-Type": "application/json"
3213
+ },
3214
+ body: JSON.stringify({}),
3215
+ skipAuthCheck: true
3216
+ // Don't clear auth on failure (might be session issue, not auth issue)
3217
+ });
3218
+ }
3207
3219
  async function getSlides(slug, token) {
3208
3220
  return request("/api/slides", {
3209
3221
  headers: {
@@ -3354,10 +3366,13 @@ async function reconnectSession(slug, cliAuthToken) {
3354
3366
  // src/lib/config.ts
3355
3367
  var import_node_fs2 = require("node:fs");
3356
3368
  var import_node_path2 = require("node:path");
3369
+ var import_node_os2 = require("node:os");
3357
3370
  var CONFIG_FILE = ".vslides.json";
3358
3371
  var GUIDE_FILE = ".vslides-guide.md";
3359
3372
  var SLIDES_FILE = "slides.md";
3360
3373
  var UPSTREAM_FILE = "upstream.md";
3374
+ var VSLIDES_DIR = (0, import_node_path2.join)((0, import_node_os2.homedir)(), ".vslides");
3375
+ var PENDING_LOGIN_FILE = (0, import_node_path2.join)(VSLIDES_DIR, "pending-login.json");
3361
3376
  var GUIDE_CACHE_TTL = 24 * 60 * 60 * 1e3;
3362
3377
  function getConfigPath() {
3363
3378
  return (0, import_node_path2.join)(process.cwd(), CONFIG_FILE);
@@ -3452,6 +3467,34 @@ function requireToken() {
3452
3467
  }
3453
3468
  return { config, token: config.token };
3454
3469
  }
3470
+ function ensureVslidesDir() {
3471
+ if (!(0, import_node_fs2.existsSync)(VSLIDES_DIR)) {
3472
+ (0, import_node_fs2.mkdirSync)(VSLIDES_DIR, { mode: 448 });
3473
+ }
3474
+ }
3475
+ function readPendingLogin() {
3476
+ if (!(0, import_node_fs2.existsSync)(PENDING_LOGIN_FILE)) {
3477
+ return null;
3478
+ }
3479
+ try {
3480
+ const content = (0, import_node_fs2.readFileSync)(PENDING_LOGIN_FILE, "utf-8");
3481
+ return JSON.parse(content);
3482
+ } catch {
3483
+ return null;
3484
+ }
3485
+ }
3486
+ function writePendingLogin(pending) {
3487
+ ensureVslidesDir();
3488
+ (0, import_node_fs2.writeFileSync)(PENDING_LOGIN_FILE, JSON.stringify(pending, null, 2) + "\n");
3489
+ }
3490
+ function clearPendingLogin() {
3491
+ if ((0, import_node_fs2.existsSync)(PENDING_LOGIN_FILE)) {
3492
+ try {
3493
+ (0, import_node_fs2.unlinkSync)(PENDING_LOGIN_FILE);
3494
+ } catch {
3495
+ }
3496
+ }
3497
+ }
3455
3498
 
3456
3499
  // src/lib/output.ts
3457
3500
  function success(message) {
@@ -3663,6 +3706,29 @@ async function join3(urlOrCode) {
3663
3706
  code = match[1];
3664
3707
  }
3665
3708
  }
3709
+ const cachedAuth = getCachedAuth();
3710
+ if (cachedAuth && isAuthValid(cachedAuth)) {
3711
+ const authResult = await authenticateToShare(code, cachedAuth.token);
3712
+ if (authResult.ok) {
3713
+ const { slug: slug2, pollSecret: pollSecret2, token, previewUrl, email } = authResult.data;
3714
+ writeConfig({
3715
+ slug: slug2,
3716
+ pollSecret: pollSecret2,
3717
+ token,
3718
+ previewUrl: previewUrl || `${getBaseUrl()}/slides/${slug2}`
3719
+ });
3720
+ success(`Joined session: ${slug2}`);
3721
+ url("USER", email);
3722
+ url("PREVIEW_URL", previewUrl || `${getBaseUrl()}/slides/${slug2}`);
3723
+ newline();
3724
+ info("You are authenticated. Run: vslides get");
3725
+ return;
3726
+ }
3727
+ if (authResult.status !== 400 && authResult.status !== 401 && authResult.status !== 403) {
3728
+ error(`Failed to join session: ${JSON.stringify(authResult.data)}`);
3729
+ process.exit(ExitCode.NetworkError);
3730
+ }
3731
+ }
3666
3732
  const result = await getJoin(code);
3667
3733
  if (!result.ok) {
3668
3734
  error(`Failed to join session: ${JSON.stringify(result.data)}`);
@@ -3674,12 +3740,12 @@ async function join3(urlOrCode) {
3674
3740
  pollSecret,
3675
3741
  previewUrl: `${getBaseUrl()}/slides/${slug}`
3676
3742
  });
3677
- url("AUTH_URL", joinUrl);
3678
- instructions([
3679
- "Run in background: vslides check --wait &",
3680
- "Open the AUTH_URL to authenticate",
3681
- "Then run: vslides get"
3682
- ]);
3743
+ success(`Joined session: ${slug}`);
3744
+ url("VERIFY_URL", joinUrl);
3745
+ newline();
3746
+ info("ACTION_REQUIRED: Open the URL above in your browser to sign in");
3747
+ info("After signing in, run: vslides check --wait");
3748
+ info("Then run: vslides get");
3683
3749
  }
3684
3750
 
3685
3751
  // src/commands/share.ts
@@ -3690,14 +3756,14 @@ async function share() {
3690
3756
  error(`Failed to get share info: ${JSON.stringify(result.data)}`);
3691
3757
  process.exit(ExitCode.NetworkError);
3692
3758
  }
3693
- const { joinUrl } = result.data;
3694
- url("JOIN_URL", joinUrl);
3759
+ const { joinUrl, code } = result.data;
3760
+ info("Share with your co-editor:");
3695
3761
  newline();
3696
- info("Share this URL with your collaborator. They will:");
3697
- info("1. Run: vslides join <url>");
3698
- info("2. Run in background: vslides check --wait &");
3699
- info("3. Visit the URL and authenticate with @vercel.com account");
3700
- info("4. Run: vslides get");
3762
+ url("LINK", joinUrl);
3763
+ newline();
3764
+ info("OR if they use Claude Code, tell them to paste this:");
3765
+ newline();
3766
+ info(` /vslides join ${code}`);
3701
3767
  }
3702
3768
 
3703
3769
  // src/commands/list.ts
@@ -4159,11 +4225,15 @@ async function upload(file) {
4159
4225
  error(`Failed to upload: ${JSON.stringify(result.data)}`);
4160
4226
  process.exit(ExitCode.NetworkError);
4161
4227
  }
4162
- info(`UPLOADED: ${result.data.filename}`);
4228
+ success(`Uploaded: ${result.data.filename}`);
4163
4229
  info(`PATH: ${result.data.path}`);
4164
4230
  newline();
4165
- info("Use in slides as:");
4231
+ info("Use in slides frontmatter:");
4166
4232
  info(` image: ${result.data.path}`);
4233
+ info(` grayscale: 0 # for full color (default is grayscale)`);
4234
+ newline();
4235
+ info("For avatar images in 1-title layout:");
4236
+ info(` subtitle1Image: ${result.data.path}`);
4167
4237
  }
4168
4238
 
4169
4239
  // src/commands/export.ts
@@ -4251,7 +4321,7 @@ var POLL_TIMEOUT2 = 12e4;
4251
4321
  function sleep3(ms) {
4252
4322
  return new Promise((resolve) => setTimeout(resolve, ms));
4253
4323
  }
4254
- async function login() {
4324
+ async function login(options = {}) {
4255
4325
  const cachedAuth = getCachedAuth();
4256
4326
  if (cachedAuth && isAuthValid(cachedAuth)) {
4257
4327
  const daysLeft = Math.ceil((cachedAuth.expiresAt - Date.now()) / (24 * 60 * 60 * 1e3));
@@ -4259,6 +4329,11 @@ async function login() {
4259
4329
  info("Run `vslides logout` to sign out first.");
4260
4330
  return;
4261
4331
  }
4332
+ const pendingLogin = readPendingLogin();
4333
+ if (pendingLogin && options.wait) {
4334
+ await pollForAuth(pendingLogin.slug, pendingLogin.pollSecret);
4335
+ return;
4336
+ }
4262
4337
  const createResult = await createSession();
4263
4338
  if (!createResult.ok) {
4264
4339
  error(`Failed to create session: ${JSON.stringify(createResult.data)}`);
@@ -4266,11 +4341,22 @@ async function login() {
4266
4341
  }
4267
4342
  const { slug, pollSecret, verifyUrl } = createResult.data;
4268
4343
  const authUrl = `${verifyUrl}?cliAuth=true`;
4269
- info("Please authenticate in your browser:");
4270
- url("AUTH_URL", authUrl);
4344
+ writePendingLogin({ slug, pollSecret, authUrl });
4345
+ url("VERIFY_URL", authUrl);
4271
4346
  newline();
4272
- info("Waiting for authentication...");
4347
+ info("ACTION_REQUIRED: Open the URL above in your browser to sign in");
4348
+ if (options.wait) {
4349
+ info("Waiting for authentication (2 minute timeout)...");
4350
+ newline();
4351
+ await pollForAuth(slug, pollSecret);
4352
+ } else {
4353
+ newline();
4354
+ info("Run `vslides login --wait` to wait for authentication to complete");
4355
+ }
4356
+ }
4357
+ async function pollForAuth(slug, pollSecret) {
4273
4358
  const startTime = Date.now();
4359
+ let pollCount = 0;
4274
4360
  while (true) {
4275
4361
  const result = await getSession(slug, pollSecret);
4276
4362
  if (!result.ok) {
@@ -4282,21 +4368,25 @@ async function login() {
4282
4368
  const validateResult = await validateCLIAuth(cliAuthToken);
4283
4369
  if (validateResult.ok && validateResult.data.valid && validateResult.data.email && validateResult.data.expiresAt) {
4284
4370
  saveCLIAuth(cliAuthToken, validateResult.data.email, validateResult.data.expiresAt);
4285
- newline();
4371
+ clearPendingLogin();
4286
4372
  success(`Logged in as ${validateResult.data.email} (valid for 7 days)`);
4287
4373
  process.exit(ExitCode.Success);
4288
4374
  }
4289
4375
  }
4290
4376
  if (Date.now() - startTime > POLL_TIMEOUT2) {
4291
- newline();
4292
4377
  error("Timeout waiting for authentication");
4293
4378
  instructions([
4294
- "Open the AUTH_URL in your browser",
4379
+ "Open the VERIFY_URL in your browser",
4295
4380
  "Sign in with your @vercel.com account",
4296
- "Run `vslides login` again"
4381
+ "Run `vslides login --wait` again"
4297
4382
  ]);
4298
4383
  process.exit(ExitCode.Conflict);
4299
4384
  }
4385
+ pollCount++;
4386
+ if (pollCount % 10 === 0) {
4387
+ const secondsLeft = Math.ceil((POLL_TIMEOUT2 - (Date.now() - startTime)) / 1e3);
4388
+ info(`Still waiting... (${secondsLeft}s remaining)`);
4389
+ }
4300
4390
  await sleep3(POLL_INTERVAL2);
4301
4391
  }
4302
4392
  }
@@ -4361,7 +4451,7 @@ function wrapCommand(fn) {
4361
4451
  };
4362
4452
  }
4363
4453
  program.name("vslides").description("CLI for Vercel Slides API").version("1.0.0");
4364
- program.command("login").description("Authenticate with Vercel (valid for 7 days)").action(wrapCommand(login));
4454
+ program.command("login").description("Authenticate with Vercel (valid for 7 days)").option("--wait", "Wait for authentication to complete (2 min timeout)").action(wrapCommand((options) => login(options)));
4365
4455
  program.command("logout").description("Sign out and revoke credentials").action(wrapCommand(logout));
4366
4456
  program.command("whoami").description("Show current authentication status").option("--validate", "Validate token with server").action(wrapCommand((options) => whoami(options)));
4367
4457
  program.command("init").description("Create a new session").action(wrapCommand(init));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vslides",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "CLI for Vercel Slides API",
5
5
  "license": "MIT",
6
6
  "author": "Vercel",