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 +1 -1
- package/src/cli.mjs +1 -1
- package/src/commands/deploy.mjs +27 -70
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
package/src/commands/deploy.mjs
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, statSync, existsSync, readdirSync } from "node:fs";
|
|
2
|
-
import { basename, resolve, dirname, join, extname
|
|
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
|
-
// ---
|
|
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
|
-
|
|
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;
|