htmlhost-cli 2.0.0 → 2.1.1

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.0.0",
3
+ "version": "2.1.1",
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.0.0";
7
+ const VERSION = "2.1.1";
8
8
 
9
9
  const HELP = `
10
10
  ${bold("htmlhost")} ${dim(`v${VERSION}`)} — deploy HTML from the terminal
@@ -1,12 +1,8 @@
1
1
  import { readFileSync, writeFileSync, statSync, existsSync, readdirSync } from "node:fs";
2
- import { basename, resolve, dirname, join, extname, relative } from "node:path";
2
+ import { basename, resolve, dirname, join, extname } from "node:path";
3
3
  import { createInterface } from "node:readline";
4
4
  import { post } from "../api.mjs";
5
- import { ok, err, info, cyan, dim, bold, yellow, green, formatBytes } from "../ui.mjs";
6
- import { processAssets } from "../assets.mjs";
7
- import { uploadFile } from "../api.mjs";
8
- import { getApi } from "../config.mjs";
9
- import { mimeFromExt } from "../ui.mjs";
5
+ import { ok, err, info, cyan, dim, bold, yellow, green, formatBytes, mimeFromExt } from "../ui.mjs";
10
6
 
11
7
  const LINK_FILE = ".htmlhost";
12
8
 
@@ -347,66 +343,13 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
347
343
 
348
344
  console.log("");
349
345
 
350
- // --- Upload non-HTML assets first ---
351
- const api = getApi();
352
- /** @type {Map<string, string>} relativePath → hosted URL */
353
- const assetUrlMap = new Map();
354
-
355
- if (assetFiles.length > 0) {
356
- info(`Uploading ${cyan(bold(String(assetFiles.length)))} asset${assetFiles.length > 1 ? "s" : ""}…`);
357
- console.log("");
358
-
359
- for (const file of assetFiles) {
360
- const fileName = basename(file.filePath);
361
- const mime = mimeFromExt(fileName);
362
-
363
- try {
364
- const data = await uploadFile("/api/media", file.filePath, fileName, mime);
365
- const hostedUrl = `${api}${data.url}`;
366
- assetUrlMap.set(file.relativePath, hostedUrl);
367
- ok(`${cyan(file.relativePath)} ${dim(`(${formatBytes(file.size)})`)} → ${dim("uploaded")}`);
368
- } catch (e) {
369
- err(`${file.relativePath}: ${e.message}`);
370
- }
371
- }
372
-
373
- console.log("");
374
- }
375
-
376
- // --- Build page payloads (HTML files with asset URLs rewritten) ---
346
+ // --- Build page payloads (HTML files no rewriting needed) ---
377
347
  info(`Processing ${cyan(bold(String(htmlFiles.length)))} page${htmlFiles.length > 1 ? "s" : ""}…`);
378
348
 
379
349
  const pagePayloads = [];
380
350
 
381
351
  for (const file of htmlFiles) {
382
- let html = readFileSync(file.filePath, "utf8");
383
-
384
- // Rewrite local asset references to hosted URLs
385
- for (const [relPath, hostedUrl] of assetUrlMap) {
386
- // Replace both quoted forms: "path" and 'path'
387
- // Handle relative paths from the HTML file's perspective
388
- const htmlDir = dirname(file.relativePath);
389
- const assetFromHtml = htmlDir === "." ? relPath : relative(htmlDir, relPath);
390
-
391
- // Replace the original reference and the relative-from-html reference
392
- html = replaceAll(html, `"${relPath}"`, `"${hostedUrl}"`);
393
- html = replaceAll(html, `'${relPath}'`, `'${hostedUrl}'`);
394
- html = replaceAll(html, `"${assetFromHtml}"`, `"${hostedUrl}"`);
395
- html = replaceAll(html, `'${assetFromHtml}'`, `'${hostedUrl}'`);
396
-
397
- // Also handle ./ prefix
398
- html = replaceAll(html, `"./${relPath}"`, `"${hostedUrl}"`);
399
- html = replaceAll(html, `'./${relPath}'`, `'${hostedUrl}'`);
400
- if (assetFromHtml !== relPath) {
401
- html = replaceAll(html, `"./${assetFromHtml}"`, `"${hostedUrl}"`);
402
- html = replaceAll(html, `'./${assetFromHtml}'`, `'${hostedUrl}'`);
403
- }
404
-
405
- // Handle url() in CSS
406
- html = replaceAll(html, `url(${relPath})`, `url(${hostedUrl})`);
407
- html = replaceAll(html, `url(${assetFromHtml})`, `url(${hostedUrl})`);
408
- html = replaceAll(html, `url(./${relPath})`, `url(${hostedUrl})`);
409
- }
352
+ const html = readFileSync(file.filePath, "utf8");
410
353
 
411
354
  // Derive page path
412
355
  let pagePath;
@@ -423,11 +366,32 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
423
366
  ok(`${cyan(file.relativePath)} → ${cyan(pagePath)}`);
424
367
  }
425
368
 
369
+ // --- Build asset payloads (non-HTML files as base64) ---
370
+ if (assetFiles.length > 0) {
371
+ console.log("");
372
+ 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)})`)}`);
388
+ }
389
+
426
390
  // --- Deploy ---
427
391
  console.log("");
428
392
  info(existingSlug ? `Deploying to ${cyan(existingSlug)}…` : "Deploying new site…");
429
393
 
430
- const body = { pages: pagePayloads };
394
+ const body = { pages: pagePayloads, assets: assetPayloads };
431
395
  if (ttl) body.ttl = ttl;
432
396
  if (existingSlug) body.slug = existingSlug;
433
397
  if (title) body.title = title;
@@ -452,7 +416,7 @@ async function deployDirectory(dirPath, { ttl, title, slug: explicitSlug, forceN
452
416
  console.log("");
453
417
  console.log(` ${green("━".repeat(40))}`);
454
418
  ok(`${bold("Live")} at ${cyan(`https://${data.url}`)}`);
455
- console.log(` ${dim(`${data.pageCount || pagePayloads.length} pages · ${data.ttl} TTL`)}`);
419
+ console.log(` ${dim(`${data.pageCount || pagePayloads.length} pages · ${assetPayloads.length} assets · ${data.ttl} TTL`)}`);
456
420
  console.log("");
457
421
 
458
422
  for (const { path: pagePath } of pagePayloads) {
@@ -514,13 +478,6 @@ function findAllFiles(baseDir, currentDir) {
514
478
  return results;
515
479
  }
516
480
 
517
- /**
518
- * Replace all occurrences of `search` in `str` with `replacement`.
519
- */
520
- function replaceAll(str, search, replacement) {
521
- return str.split(search).join(replacement);
522
- }
523
-
524
481
  function getFlag(args, flag) {
525
482
  const idx = args.indexOf(flag);
526
483
  if (idx === -1 || idx >= args.length - 1) return null;