htmlhost-cli 2.1.2 → 2.1.4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "htmlhost-cli",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "description": "Deploy HTML files from the terminal — htmlhost.co CLI",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.mjs CHANGED
@@ -4,7 +4,7 @@
4
4
  import { bold, dim, cyan, err } from "./ui.mjs";
5
5
  import { ApiError } from "./api.mjs";
6
6
 
7
- const VERSION = "2.1.2";
7
+ const VERSION = "2.1.3";
8
8
 
9
9
  const HELP = `
10
10
  ${bold("htmlhost")} ${dim(`v${VERSION}`)} — deploy HTML from the terminal
@@ -43,6 +43,9 @@ const HELP = `
43
43
  ${dim("$")} htmlhost deploy --json ${dim("# JSON output for CI/CD")}
44
44
  ${dim("$")} htmlhost delete old-project --force
45
45
 
46
+ ${bold("Update:")}
47
+ npm update -g htmlhost-cli
48
+
46
49
  ${dim(`Docs: https://htmlhost.co/docs`)}
47
50
  `;
48
51
 
@@ -291,7 +291,7 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
291
291
 
292
292
  // Read existing link data
293
293
  const link = readLink(dirPath);
294
- const existingSlug = explicitSlug || (!forceNew && link?.multipage?.slug) || null;
294
+ let existingSlug = explicitSlug || (!forceNew && link?.multipage?.slug) || null;
295
295
 
296
296
  // Calculate total size
297
297
  const totalSize = allFiles.reduce((sum, f) => sum + f.size, 0);
@@ -366,25 +366,65 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
366
366
  ok(`${cyan(file.relativePath)} → ${cyan(pagePath)}`);
367
367
  }
368
368
 
369
- // --- Build asset payloads (non-HTML files as base64) ---
369
+ // --- Build asset payloads (presigned URL flow) ---
370
+ const assetPayloads = [];
371
+
370
372
  if (assetFiles.length > 0) {
371
373
  console.log("");
372
374
  info(`Packaging ${cyan(bold(String(assetFiles.length)))} asset${assetFiles.length > 1 ? "s" : ""}…`);
373
- }
374
-
375
- const assetPayloads = [];
376
-
377
- for (const file of assetFiles) {
378
- const content = readFileSync(file.filePath);
379
- const base64 = content.toString("base64");
380
- const mime = mimeFromExt(basename(file.filePath));
381
-
382
- assetPayloads.push({
383
- path: file.relativePath,
384
- content: base64,
385
- mimeType: mime,
386
- });
387
- ok(`${cyan(file.relativePath)} ${dim(`(${formatBytes(file.size)})`)}`);
375
+
376
+ const uploadUrlReqBody = {
377
+ slug: existingSlug || undefined,
378
+ isNewSite: !existingSlug,
379
+ html: pagePayloads[0]?.html || "",
380
+ assets: assetFiles.map(f => ({
381
+ path: f.relativePath,
382
+ sizeBytes: f.size,
383
+ mimeType: mimeFromExt(basename(f.filePath))
384
+ }))
385
+ };
386
+
387
+ let urlData;
388
+ try {
389
+ urlData = await post("/api/sites/upload-url", uploadUrlReqBody);
390
+ } catch (e) {
391
+ err(`Failed to get upload URLs: ${e.message}`);
392
+ process.exit(1);
393
+ }
394
+
395
+ const { slug: generatedSlug, uploadUrls } = urlData;
396
+
397
+ console.log("");
398
+ info(`Uploading ${cyan(bold(String(assetFiles.length)))} asset${assetFiles.length > 1 ? "s" : ""}…`);
399
+
400
+ for (const u of uploadUrls) {
401
+ const file = assetFiles.find(f => f.relativePath === u.path);
402
+ const buffer = readFileSync(file.filePath);
403
+
404
+ const res = await fetch(u.uploadUrl, {
405
+ method: "PUT",
406
+ headers: { "Content-Type": u.mimeType },
407
+ body: buffer
408
+ });
409
+
410
+ if (!res.ok) {
411
+ err(`Failed to upload ${u.path}`);
412
+ process.exit(1);
413
+ }
414
+
415
+ assetPayloads.push({
416
+ path: u.path,
417
+ mimeType: u.mimeType,
418
+ sizeBytes: u.sizeBytes,
419
+ storageKey: u.storageKey
420
+ });
421
+
422
+ ok(`✓ Uploaded ${cyan(u.path)} ${dim(`(${formatBytes(file.size)})`)}`);
423
+ }
424
+
425
+ if (!existingSlug) {
426
+ existingSlug = generatedSlug;
427
+ }
388
428
  }
389
429
 
390
430
  // --- Deploy ---
@@ -393,7 +433,13 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
393
433
 
394
434
  const body = { pages: pagePayloads, assets: assetPayloads };
395
435
  if (ttl) body.ttl = ttl;
396
- if (existingSlug) body.slug = existingSlug;
436
+ if (existingSlug) {
437
+ body.slug = existingSlug;
438
+ // We pass isNewSite only if the generated slug wasn't originally provided
439
+ if (!explicitSlug && !(!forceNew && link?.multipage?.slug)) {
440
+ body.isNewSite = true;
441
+ }
442
+ }
397
443
  if (title) body.title = title;
398
444
 
399
445
  try {