feat: integrate XSLT Tools with toolbox portal
This commit is contained in:
151
scripts/smoke-static-build.mjs
Normal file
151
scripts/smoke-static-build.mjs
Normal file
@@ -0,0 +1,151 @@
|
||||
import { createServer } from 'node:http';
|
||||
import { readFile, stat } from 'node:fs/promises';
|
||||
import { dirname, extname, join, resolve, sep } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
const repositoryRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const distDirectory = join(repositoryRoot, 'dist');
|
||||
const nestedPath = '/deep/nested/app/';
|
||||
const mimeTypes = {
|
||||
'.css': 'text/css',
|
||||
'.html': 'text/html',
|
||||
'.ico': 'image/x-icon',
|
||||
'.js': 'text/javascript',
|
||||
'.json': 'application/json',
|
||||
'.png': 'image/png',
|
||||
'.svg': 'image/svg+xml',
|
||||
};
|
||||
|
||||
const server = createServer(async (request, response) => {
|
||||
try {
|
||||
const requestUrl = new URL(request.url ?? '/', 'http://localhost');
|
||||
|
||||
if (requestUrl.pathname === '/toolbox.catalog.json') {
|
||||
response.setHeader('content-type', 'application/json');
|
||||
response.end(
|
||||
JSON.stringify({
|
||||
schemaVersion: 1,
|
||||
id: 'nested-smoke-test',
|
||||
name: 'Nested smoke test',
|
||||
home: './',
|
||||
theme: {
|
||||
mode: 'system',
|
||||
brand: 'Nested smoke test',
|
||||
},
|
||||
apps: [
|
||||
{
|
||||
manifest: `${nestedPath}toolbox-app.json`,
|
||||
enabled: true,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!requestUrl.pathname.startsWith(nestedPath)) {
|
||||
response.writeHead(404).end();
|
||||
return;
|
||||
}
|
||||
|
||||
const requestedPath = decodeURIComponent(
|
||||
requestUrl.pathname.slice(nestedPath.length)
|
||||
);
|
||||
const filePath = resolve(
|
||||
distDirectory,
|
||||
requestedPath === '' ? 'index.html' : requestedPath
|
||||
);
|
||||
|
||||
if (
|
||||
filePath !== distDirectory &&
|
||||
!filePath.startsWith(`${distDirectory}${sep}`)
|
||||
) {
|
||||
response.writeHead(403).end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(await stat(filePath)).isFile()) {
|
||||
response.writeHead(404).end();
|
||||
return;
|
||||
}
|
||||
|
||||
response.setHeader(
|
||||
'content-type',
|
||||
mimeTypes[extname(filePath)] ?? 'application/octet-stream'
|
||||
);
|
||||
response.end(await readFile(filePath));
|
||||
} catch {
|
||||
response.writeHead(404).end();
|
||||
}
|
||||
});
|
||||
|
||||
await new Promise((resolveListening) => {
|
||||
server.listen(0, '127.0.0.1', resolveListening);
|
||||
});
|
||||
|
||||
try {
|
||||
const address = server.address();
|
||||
if (!address || typeof address === 'string') {
|
||||
throw new Error('Static smoke server did not expose a TCP port.');
|
||||
}
|
||||
|
||||
const appUrl = `http://127.0.0.1:${address.port}${nestedPath}`;
|
||||
const standaloneHtml = await fetchText(appUrl);
|
||||
const toolboxHtml = await fetchText(
|
||||
`${appUrl}?toolbox=${encodeURIComponent('/toolbox.catalog.json')}`
|
||||
);
|
||||
|
||||
if (toolboxHtml !== standaloneHtml) {
|
||||
throw new Error('Toolbox mode did not serve the same static app artifact.');
|
||||
}
|
||||
|
||||
const assetReferences = Array.from(
|
||||
standaloneHtml.matchAll(/(?:href|src)="([^"]+)"/g),
|
||||
(match) => match[1]
|
||||
).filter(
|
||||
(reference) =>
|
||||
!reference.startsWith('#') &&
|
||||
!reference.startsWith('data:') &&
|
||||
!reference.startsWith('http:') &&
|
||||
!reference.startsWith('https:')
|
||||
);
|
||||
|
||||
for (const reference of assetReferences) {
|
||||
const resolved = new URL(reference, appUrl);
|
||||
if (!resolved.pathname.startsWith(nestedPath)) {
|
||||
throw new Error(
|
||||
`Built asset escaped the nested app path: ${reference} -> ${resolved.pathname}`
|
||||
);
|
||||
}
|
||||
await fetchOk(resolved);
|
||||
}
|
||||
|
||||
const manifestUrl = new URL('toolbox-app.json', appUrl);
|
||||
const manifest = JSON.parse(await fetchText(manifestUrl));
|
||||
await fetchOk(new URL(manifest.entry, appUrl));
|
||||
await fetchOk(new URL(manifest.icon, manifestUrl));
|
||||
await fetchOk(new URL('vendor/saxon/SaxonJS2.js', appUrl));
|
||||
await fetchOk(`http://127.0.0.1:${address.port}/toolbox.catalog.json`);
|
||||
|
||||
console.log(
|
||||
`Static smoke test passed at ${nestedPath} in standalone and toolbox modes.`
|
||||
);
|
||||
} finally {
|
||||
await new Promise((resolveClosed, reject) => {
|
||||
server.close((error) => (error ? reject(error) : resolveClosed()));
|
||||
});
|
||||
}
|
||||
|
||||
async function fetchOk(url) {
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Expected ${url} to be available, received HTTP ${response.status}.`
|
||||
);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
async function fetchText(url) {
|
||||
return (await fetchOk(url)).text();
|
||||
}
|
||||
Reference in New Issue
Block a user