Updates and add examples host
CI / Build & Test (push) Successful in 8m7s

This commit is contained in:
Raven Scott
2026-07-26 23:50:17 -04:00
parent bb3b46a987
commit 83af298eb5
24 changed files with 678 additions and 39 deletions
+210
View File
@@ -0,0 +1,210 @@
/**
* Local static HTTP server for BridgeSwarm examples (127.0.0.1).
* Started/stopped via native messaging (examplesServer.start / stop / status).
*/
const http = require('bare-http1');
const fs = require('bare-fs');
const path = require('bare-path');
const DEFAULT_HOST = '127.0.0.1';
const DEFAULT_PORT = 4173;
const MIME = {
'.html': 'text/html; charset=utf-8',
'.js': 'text/javascript; charset=utf-8',
'.mjs': 'text/javascript; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.json': 'application/json; charset=utf-8',
'.svg': 'image/svg+xml',
'.png': 'image/png',
'.jpg': 'image/jpeg',
'.jpeg': 'image/jpeg',
'.gif': 'image/gif',
'.webp': 'image/webp',
'.ico': 'image/x-icon',
'.woff': 'font/woff',
'.woff2': 'font/woff2',
'.map': 'application/json',
'.txt': 'text/plain; charset=utf-8',
'.md': 'text/markdown; charset=utf-8',
};
/** @type {import('bare-http1').Server | null} */
let server = null;
let boundHost = DEFAULT_HOST;
let boundPort = DEFAULT_PORT;
let examplesRoot = null;
function exists(p) {
try {
return fs.existsSync(p);
} catch (_) {
return false;
}
}
function resolveExamplesRoot() {
if (process.env.BRIDGESWARM_EXAMPLES_DIR) {
return path.resolve(process.env.BRIDGESWARM_EXAMPLES_DIR);
}
const candidates = [];
if (process.env.BRIDGE_SWARM_STORAGE) {
candidates.push(path.join(path.dirname(process.env.BRIDGE_SWARM_STORAGE), 'examples'));
}
candidates.push(path.join(process.cwd(), 'examples'));
candidates.push(path.join(__dirname, 'examples'));
candidates.push(path.join(__dirname, '..', 'examples'));
for (const dir of candidates) {
if (exists(path.join(dir, 'index.html'))) return dir;
}
return null;
}
function safeJoin(root, urlPath) {
const decoded = decodeURIComponent((urlPath || '/').split('?')[0]);
const cleaned = path.normalize(decoded).replace(/^(\.\.[/\\])+/, '');
const full = path.join(root, cleaned);
const rootNorm = path.resolve(root);
const fullNorm = path.resolve(full);
if (fullNorm !== rootNorm && !fullNorm.startsWith(rootNorm + path.sep)) return null;
return fullNorm;
}
function contentType(filePath) {
const ext = path.extname(filePath).toLowerCase();
return MIME[ext] || 'application/octet-stream';
}
function send(res, status, body, headers = {}) {
const buf = typeof body === 'string' ? Buffer.from(body) : body;
res.statusCode = status;
res.setHeader('Cache-Control', 'no-store');
for (const [name, value] of Object.entries(headers)) {
res.setHeader(name, value);
}
res.end(buf);
}
function handleRequest(req, res) {
const root = examplesRoot;
if (!root) {
send(res, 503, 'Examples not found on disk');
return;
}
let urlPath = req.url || '/';
if (urlPath === '/') urlPath = '/index.html';
const filePath = safeJoin(root, urlPath);
if (!filePath) {
send(res, 403, 'Forbidden');
return;
}
let st;
try {
st = fs.statSync(filePath);
} catch (_) {
send(res, 404, 'Not found');
return;
}
let target = filePath;
if (st.isDirectory()) {
target = path.join(filePath, 'index.html');
if (!exists(target)) {
send(res, 404, 'Not found');
return;
}
}
try {
const data = fs.readFileSync(target);
send(res, 200, data, { 'Content-Type': contentType(target) });
} catch (_) {
send(res, 404, 'Not found');
}
}
function status() {
const root = examplesRoot || resolveExamplesRoot();
const url = server ? `http://${boundHost}:${boundPort}/` : null;
return {
ok: true,
running: !!server,
url,
host: boundHost,
port: boundPort,
root: root || null,
rootFound: !!(root && exists(path.join(root, 'index.html'))),
};
}
function start(opts = {}) {
if (server) {
return { ...status(), ok: true };
}
const root = resolveExamplesRoot();
if (!root) {
return {
ok: false,
error:
'Examples directory not found. Reinstall BridgeSwarm or set BRIDGESWARM_EXAMPLES_DIR.',
running: false,
url: null,
root: null,
rootFound: false,
};
}
examplesRoot = root;
boundHost = typeof opts.host === 'string' && opts.host ? opts.host : DEFAULT_HOST;
boundPort = typeof opts.port === 'number' && opts.port > 0 ? opts.port : DEFAULT_PORT;
return new Promise((resolve) => {
const s = http.createServer(handleRequest);
const onError = (err) => {
s.removeListener('listening', onListening);
server = null;
resolve({
ok: false,
error: err.message || String(err),
running: false,
url: null,
host: boundHost,
port: boundPort,
root: examplesRoot,
rootFound: true,
});
};
const onListening = () => {
s.removeListener('error', onError);
server = s;
resolve({ ...status(), ok: true });
};
s.once('error', onError);
s.once('listening', onListening);
s.listen(boundPort, boundHost);
});
}
function stop() {
if (!server) {
return Promise.resolve({ ...status(), ok: true, running: false, url: null });
}
const s = server;
server = null;
return new Promise((resolve) => {
try {
s.close(() => resolve({ ...status(), ok: true, running: false, url: null }));
} catch (_) {
resolve({ ...status(), ok: true, running: false, url: null });
}
});
}
module.exports = { start, stop, status, resolveExamplesRoot, DEFAULT_HOST, DEFAULT_PORT };