/** Install packed @seihouse/elemental-title in a clean consumer; typecheck, bundle, and run browser gates. */
import { spawnSync } from 'node:child_process';
import { copyFileSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { build } from './node_modules/esbuild/lib/main.js';
import { npm } from './package_tools.mjs';
const root = dirname(dirname(fileURLToPath(import.meta.url)));
const tools = join(root, 'display/node_modules');
const release = JSON.parse(
readFileSync(join(root, 'packages/elemental-title/releases/release.json'), 'utf8')
);
const temporary = mkdtempSync(join(tmpdir(), 'elemental-title-consumer-'));
if (
dirname(resolve(temporary)) !== resolve(tmpdir()) ||
!temporary.startsWith(join(tmpdir(), 'elemental-title-consumer-'))
) {
throw new Error('Invalid consumer temporary directory');
}
function run(cmd, args) {
const r = spawnSync(cmd, args, { cwd: temporary, encoding: 'utf8' });
if (r.status !== 0) {
throw new Error(r.stdout + r.stderr + (r.error?.message || ''));
}
return r.stdout;
}
try {
writeFileSync(
join(temporary, 'package.json'),
JSON.stringify({ name: 'elemental-title-packed-consumer', private: true, type: 'module' })
);
npm(
[
'install',
'--ignore-scripts',
'--legacy-peer-deps',
'--no-audit',
'--no-fund',
join(root, 'packages/elemental-title/releases', release.filename),
],
temporary
);
// Verify manifest & Next.js "use client" directive
const installedPkg = JSON.parse(
readFileSync(join(temporary, 'node_modules/@seihouse/elemental-title/package.json'), 'utf8')
);
if (installedPkg.dependencies) {
throw new Error('Unexpected mandatory dependencies in @seihouse/elemental-title');
}
const installedJs = readFileSync(
join(temporary, 'node_modules/@seihouse/elemental-title/dist/index.js'),
'utf8'
);
if (!installedJs.startsWith('"use client";')) {
throw new Error('Packed dist/index.js is missing leading "use client"; directive');
}
// Strict TypeScript consumer check
writeFileSync(
join(temporary, 'consumer.tsx'),
`import { ElementalTitle, type ElementalTitleMoment, type ElementalTitleSignature } from '@seihouse/elemental-title';\n` +
`const sigs: readonly ElementalTitleSignature[] = ['quill/stormwrit', 'quill/true-north'];\n` +
`export const view = (\n` +
` void m.id}\n` +
` >\n` +
` Kept Reading\n` +
` \n` +
`);\n`
);
writeFileSync(
join(temporary, 'tsconfig.json'),
JSON.stringify({
compilerOptions: {
target: 'ES2022',
module: 'NodeNext',
moduleResolution: 'NodeNext',
strict: true,
noEmit: true,
jsx: 'react-jsx',
lib: ['ES2022', 'DOM'],
paths: {
react: [join(tools, '@types/react/index.d.ts')],
'react/jsx-runtime': [join(tools, '@types/react/jsx-runtime.d.ts')],
},
},
include: ['consumer.tsx'],
})
);
run(process.execPath, [join(tools, 'typescript/bin/tsc'), '--project', 'tsconfig.json']);
// Bundle React 19 browser test app
copyFileSync(
join(temporary, 'node_modules/@seihouse/elemental-title/dist/styles.css'),
join(temporary, 'elemental-title.css')
);
const browserEntry = `
import React, { useState } from 'react';
import { createRoot } from 'react-dom/client';
import { ElementalTitle } from '@seihouse/elemental-title';
window.moments = [];
let nextKey = 0;
function App() {
const [moment, setMoment] = useState(undefined);
window.playStrike = () => setMoment({ id: 'strike', key: ++nextKey });
window.playSignature = (signature) => setMoment({ id: 'signature', key: ++nextKey, signature });
return React.createElement(
'div',
{ style: { padding: '32px', background: '#0b1018', color: '#f6cf7f', colorScheme: 'dark' } },
React.createElement(
'div',
{ id: 'lightning' },
React.createElement(
ElementalTitle,
{
as: 'h2',
element: 'lightning',
intensity: 'legendary',
color: '#f6cf7f',
signatures: ['quill/stormwrit', 'quill/true-north'],
playMoment: moment,
onMoment: (m) => window.moments.push(m),
style: { fontSize: '32px' },
},
'Kept Reading'
)
),
React.createElement(
'div',
{ id: 'water', style: { marginTop: '24px' } },
React.createElement(
ElementalTitle,
{
as: 'h2',
element: 'water',
intensity: 'legendary',
color: '#86e3ae',
style: { fontSize: '28px' },
},
'Still Waters'
)
)
);
}
const root = createRoot(document.getElementById('root'));
root.render(React.createElement(React.StrictMode, null, React.createElement(App)));
window.unmount = () => root.unmount();
`;
await build({
stdin: { contents: browserEntry, resolveDir: temporary, loader: 'js' },
bundle: true,
format: 'esm',
platform: 'browser',
nodePaths: [tools],
outfile: join(temporary, 'consumer.js'),
});
writeFileSync(
join(temporary, 'index.html'),
'' +
'' +
'
'
);
const python =
process.platform === 'win32' ? join(root, '.venv/Scripts/python.exe') : 'python';
console.log(run(python, [join(root, 'display/verify_elemental_browser.py'), temporary]));
mkdirSync(join(root, 'dist'), { recursive: true });
writeFileSync(
join(root, 'dist/elemental-package-consumer.json'),
JSON.stringify(
{
artifact: release.filename,
sha256: release.sha256,
checks: [
'clean archive install',
'zero mandatory runtime dependencies',
'Next.js use client directive',
'strict public TypeScript',
'React 19 browser bundle',
'Lightning/Water stage, strike, Quill Stormwrit signature, reduced motion & disposal gates',
],
flags: [],
},
null,
2
) + '\n',
'utf8'
);
console.log(
'Elemental Title packed consumer: install, types, React bundle and browser lifecycle passed'
);
} finally {
rmSync(temporary, { recursive: true, force: true });
}