Skip to content

Commit 2a08901

Browse files
committed
✨ Require --public-link flag for private project previews
Private projects now require the --public-link flag when uploading previews. This ensures users explicitly acknowledge that preview URLs grant access to anyone with the link (until expiration). Without the flag, private project previews will fail with a clear error message explaining the access model and how to proceed.
1 parent 6af0114 commit 2a08901

2 files changed

Lines changed: 35 additions & 0 deletions

File tree

src/cli.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,10 @@ program
582582
.option('--base <path>', 'Override auto-detected base path')
583583
.option('--open', 'Open preview URL in browser after upload')
584584
.option('--dry-run', 'Show what would be uploaded without uploading')
585+
.option(
586+
'--public-link',
587+
'Acknowledge that preview URL grants access to anyone with the link (required for private projects)'
588+
)
585589
.option(
586590
'-x, --exclude <pattern>',
587591
'Exclude files/dirs (repeatable, e.g. -x "*.log" -x "temp/")',

src/commands/preview.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import { join, resolve } from 'node:path';
1414
import { promisify } from 'node:util';
1515
import {
1616
createApiClient as defaultCreateApiClient,
17+
getBuild as defaultGetBuild,
1718
uploadPreviewZip as defaultUploadPreviewZip,
1819
} from '../api/index.js';
1920
import { openBrowser as defaultOpenBrowser } from '../utils/browser.js';
@@ -336,6 +337,7 @@ export async function previewCommand(
336337
let {
337338
loadConfig = defaultLoadConfig,
338339
createApiClient = defaultCreateApiClient,
340+
getBuild = defaultGetBuild,
339341
uploadPreviewZip = defaultUploadPreviewZip,
340342
readSession = defaultReadSession,
341343
formatSessionAge = defaultFormatSessionAge,
@@ -436,6 +438,35 @@ export async function previewCommand(
436438
return { success: false, reason: 'no-build' };
437439
}
438440

441+
// Check project visibility for private projects (skip for dry-run)
442+
if (!options.dryRun) {
443+
let client = createApiClient({
444+
baseUrl: config.apiUrl,
445+
token: config.apiKey,
446+
command: 'preview',
447+
});
448+
449+
let build = await getBuild(client, buildId);
450+
451+
// Check if project is private and user hasn't acknowledged public link access
452+
if (build.project && !build.project.isPublic && !options.publicLink) {
453+
output.error('This project is private.');
454+
output.blank();
455+
output.print(
456+
' Preview URLs grant access to anyone with the link (until expiration).'
457+
);
458+
output.blank();
459+
output.print(' To proceed, acknowledge this by using:');
460+
output.blank();
461+
output.print(' vizzly preview ./dist --public-link');
462+
output.blank();
463+
output.print(' Or set your project to public in Vizzly settings.');
464+
output.blank();
465+
exit(1);
466+
return { success: false, reason: 'private-project-no-flag' };
467+
}
468+
}
469+
439470
// Check for zip command availability (skip for dry-run)
440471
if (!options.dryRun) {
441472
let zipInfo = getZipCommand();

0 commit comments

Comments
 (0)