// @ts-check
/**
* PromptJS v1.0.0 — Adapter: Static Export
* ============================================================================
*
* Enhances the default `pjs build` output for production CDN deployment.
*
* Adds:
* - Asset hashing (prompt.a1b2c3.js) for cache busting
* - tags (og:title, og:description, canonical) from config
* - sitemap.xml auto-generation from route list
* - 404.html fallback for SPA routes
*
* Zero-dependency. Uses Node.js crypto for content hashing.
*/
'use strict';
const crypto = require('crypto');
const path = require('path');
const fs = require('fs');
const { isInsideRoot } = require('../../utils/path-guard');
/**
* Generate a short content hash from a string.
*
* @param {string} content - Content to hash
* @param {number} [len=8] - Hash length
* @returns {string} Hex hash
*/
function contentHash(content, len) {
len = len || 8;
return crypto.createHash('md5').update(content).digest('hex').slice(0, len);
}
/**
* Hash a filename: prompt.js → prompt.a1b2c3.js
*
* @param {string} filename - Original filename (e.g. "prompt.js")
* @param {string} content - File content for hashing
* @returns {string} Hashed filename
*/
function hashFilename(filename, content) {
const ext = path.extname(filename);
const base = filename.slice(0, -ext.length);
const hash = contentHash(content, 8);
return base + '.' + hash + ext;
}
/**
* Enhance HTML with tags from config.
*
* @param {string} html - Original HTML
* @param {Object} meta - Meta config { title, description, ogImage, ... }
* @param {Object} [opts] - Options
* @param {string} [opts.siteUrl] - Base URL for canonical
* @param {string} [opts.route] - Current page route (for canonical)
* @returns {string} HTML with meta tags injected
*/
function injectMetaTags(html, meta, opts) {
opts = opts || {};
const tags = [];
if (meta && meta.title) {
tags.push(' ');
}
if (meta && meta.description) {
tags.push(' ');
tags.push(' ');
}
if (meta && meta.ogImage) {
tags.push(' ');
}
if (meta && meta.ogType) {
tags.push(' ');
}
if (opts.siteUrl && opts.route) {
const canonical = opts.siteUrl.replace(/\/$/, '') + opts.route;
tags.push(' ');
}
if (tags.length === 0) return html;
const metaBlock = tags.join('\n') + '\n';
return html.replace('', metaBlock + '');
}
/**
* Generate sitemap.xml from route list.
*
* @param {string[]} routes - Array of route paths (e.g. ["/", "/about"])
* @param {string} siteUrl - Base URL (e.g. "https://example.com")
* @returns {string} sitemap.xml content
*/
function generateSitemap(routes, siteUrl) {
const urls = routes
.map(function (route) {
return (
'
Halaman tidak ditemukan.
\n' + ' Kembali ke beranda\n' + '\n' + '\n' ); } /** * Generate a cryptographically random nonce for CSP. * * @param {number} [len=24] - Nonce length in bytes (48 hex chars) * @returns {string} Base64-encoded nonce */ function generateNonce(len) { len = len || 24; return crypto.randomBytes(len).toString('base64'); } /** * Inject CSP meta tag and nonce attributes into HTML. * * Adds: * - tag * - nonce="..." to