htmlhost-cli 2.1.6 → 2.1.8

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.6",
3
+ "version": "2.1.8",
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.6";
7
+ const VERSION = "2.1.7";
8
8
 
9
9
  const HELP = `
10
10
  ${bold("htmlhost")} ${dim(`v${VERSION}`)} — deploy HTML from the terminal
@@ -1,6 +1,7 @@
1
- import { readFileSync, writeFileSync, statSync, existsSync, readdirSync } from "node:fs";
1
+ import { readFileSync, writeFileSync, statSync, existsSync, readdirSync, mkdirSync } from "node:fs";
2
2
  import { basename, resolve, dirname, join, extname } from "node:path";
3
3
  import { createInterface } from "node:readline";
4
+ import { createHash } from "node:crypto";
4
5
  import { post } from "../api.mjs";
5
6
  import { ok, err, info, cyan, dim, bold, yellow, green, formatBytes, mimeFromExt } from "../ui.mjs";
6
7
 
@@ -384,11 +385,18 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
384
385
  slug: existingSlug || undefined,
385
386
  isNewSite: !existingSlug,
386
387
  html: pagePayloads[0]?.html || "",
387
- assets: assetFiles.map(f => ({
388
- path: f.relativePath,
389
- sizeBytes: f.size,
390
- mimeType: mimeFromExt(basename(f.filePath))
391
- }))
388
+ assets: assetFiles.map(f => {
389
+ const buffer = readFileSync(f.filePath);
390
+ const hash = createHash('sha256').update(buffer).digest('hex');
391
+ // Store buffer on file object to avoid reading again
392
+ f.buffer = buffer;
393
+ return {
394
+ path: f.relativePath,
395
+ sizeBytes: f.size,
396
+ mimeType: mimeFromExt(basename(f.filePath)),
397
+ hash
398
+ };
399
+ })
392
400
  };
393
401
 
394
402
  let urlData;
@@ -404,29 +412,37 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
404
412
  console.log("");
405
413
  info(`Uploading ${cyan(bold(String(assetFiles.length)))} asset${assetFiles.length > 1 ? "s" : ""}…`);
406
414
 
415
+ let uploadedCount = 0;
416
+ let skippedCount = 0;
417
+
407
418
  for (const u of uploadUrls) {
408
419
  const file = assetFiles.find(f => f.relativePath === u.path);
409
- const buffer = readFileSync(file.filePath);
410
-
411
- const res = await fetch(u.uploadUrl, {
412
- method: "PUT",
413
- headers: { "Content-Type": u.mimeType },
414
- body: buffer
415
- });
416
420
 
417
- if (!res.ok) {
418
- err(`Failed to upload ${u.path}`);
419
- process.exit(1);
421
+ if (u.uploadUrl) {
422
+ const res = await fetch(u.uploadUrl, {
423
+ method: "PUT",
424
+ headers: { "Content-Type": u.mimeType },
425
+ body: file.buffer
426
+ });
427
+
428
+ if (!res.ok) {
429
+ err(`Failed to upload ${u.path}`);
430
+ process.exit(1);
431
+ }
432
+ ok(`✓ Uploaded ${cyan(u.path)} ${dim(`(${formatBytes(file.size)})`)}`);
433
+ uploadedCount++;
434
+ } else {
435
+ ok(`● Skipped (unchanged) ${cyan(u.path)} ${dim(`(${formatBytes(file.size)})`)}`);
436
+ skippedCount++;
420
437
  }
421
438
 
422
439
  assetPayloads.push({
423
440
  path: u.path,
424
441
  mimeType: u.mimeType,
425
442
  sizeBytes: u.sizeBytes,
426
- storageKey: u.storageKey
443
+ storageKey: u.storageKey,
444
+ hash: u.hash
427
445
  });
428
-
429
- ok(`✓ Uploaded ${cyan(u.path)} ${dim(`(${formatBytes(file.size)})`)}`);
430
446
  }
431
447
 
432
448
  if (!existingSlug) {