generator-white-label 10.0.0 → 10.0.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.
@@ -34,4 +34,4 @@ Yarn's package-age security gate is left enabled for ordinary dependencies. The
34
34
 
35
35
  The committed `package-lock.json` remains the generator repository's canonical dependency lockfile and npm remains the maintenance/audit path used by primary CI. Compatibility CI packs the real generator artifact and verifies its API and CLI under npm, Yarn, and pnpm. Alternate lockfiles are not committed merely for compatibility testing.
36
36
 
37
- Generator 10 depends on `white-label-view@7`. View 7's implementation is merged but not yet published, so coordinated CI temporarily builds and injects the exact merged View 7 revision for integration testing. The release lockfile remains registry-based; do not replace it with a Git dependency or treat the temporary packed artifact as a published dependency. Normal registry installation remains a release gate until View 7 is published.
37
+ Generator 10 pins the published runtime line exactly, including `white-label-view@7.0.0`, and the committed lockfile resolves those dependencies from the npm registry. The security workflow also substitutes a fixed packed View 7 source revision in coordinated integration jobs; that is an additional cross-repository compatibility check, not a workaround for an unpublished View release. Keep the release lockfile registry-based rather than replacing runtime dependencies with Git or local package references.
package/README.md CHANGED
@@ -273,7 +273,7 @@ Tests are part of the documentation. Executable project source is held to 100% s
273
273
 
274
274
  ## Coordinated runtime release
275
275
 
276
- Generator 10 targets the published White Label runtime line: `white-label-mediator@5.0.0`, `white-label-model@7.0.1`, `white-label-router@6.1.0`, and `white-label-view@7.0.0`. Release and CI verification use those registry packages directly.
276
+ Generator 10 targets the published White Label runtime line: `white-label-mediator@5.0.1`, `white-label-model@7.0.2`, `white-label-router@6.1.1`, and `white-label-view@7.0.1`. The release and install baseline is registry-backed; CI additionally substitutes a fixed packed View 7 source revision in coordinated integration jobs.
277
277
 
278
278
  ## White Label ecosystem
279
279
 
@@ -6,11 +6,11 @@ const packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '
6
6
  const nodeFileSystem = {
7
7
  async copy(source, destination) {
8
8
  await mkdir(path.dirname(destination), { recursive: true });
9
- await cp(source, destination, { recursive: true });
9
+ await cp(source, destination, { recursive: true, force: false, errorOnExist: true });
10
10
  },
11
11
  async writeJSON(destination, value) {
12
12
  await mkdir(path.dirname(destination), { recursive: true });
13
- await writeFile(destination, `${JSON.stringify(value, null, 2)}\n`);
13
+ await writeFile(destination, `${JSON.stringify(value, null, 2)}\n`, { flag: 'wx' });
14
14
  }
15
15
  };
16
16
  /** Refuse to layer a generated project over existing user files. */
@@ -60,10 +60,10 @@ export function createSiteManifest() {
60
60
  'typescript': '7.0.2'
61
61
  },
62
62
  dependencies: {
63
- 'white-label-mediator': '5.0.0',
64
- 'white-label-model': '7.0.1',
65
- 'white-label-router': '6.1.0',
66
- 'white-label-view': '7.0.0'
63
+ 'white-label-mediator': '5.0.1',
64
+ 'white-label-model': '7.0.2',
65
+ 'white-label-router': '6.1.1',
66
+ 'white-label-view': '7.0.1'
67
67
  }
68
68
  };
69
69
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../scaffold/index.ts"],"names":[],"mappings":"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","sourcesContent":["/** @module scaffold */\nimport {cp, mkdir, readdir, writeFile} from 'node:fs/promises';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nconst packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');\n\nexport interface ScaffoldFileSystem {\n copy(source: string, destination: string): void | Promise<void>;\n writeJSON(destination: string, value: unknown): void | Promise<void>;\n}\n\nexport interface CreateProjectOptions {\n destination: string;\n fileSystem?: ScaffoldFileSystem;\n}\n\nconst nodeFileSystem: ScaffoldFileSystem = {\n async copy(source, destination) {\n await mkdir(path.dirname(destination), {recursive: true});\n await cp(source, destination, {recursive: true});\n },\n async writeJSON(destination, value) {\n await mkdir(path.dirname(destination), {recursive: true});\n await writeFile(destination, `${JSON.stringify(value, null, 2)}\\n`);\n }\n};\n\n/** Refuse to layer a generated project over existing user files. */\nasync function assertDestinationAvailable(destination: string) {\n try {\n const entries = await readdir(destination);\n if (entries.length) {throw new Error(`Destination directory must be empty: ${destination}`);}\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {return;}\n throw error;\n }\n}\n\n/** Return the package manifest used by generated White Label projects. */\nexport function createSiteManifest() {\n return {\n name: 'white-label-site',\n version: '1.0.0',\n private: true,\n type: 'module',\n engines: {node: '^22.18.0 || >=24.11.0'},\n scripts: {\n build: 'tsc -p tsconfig.json && node dist/scripts/build.js',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n test: 'node --run typecheck && node --run build -- --version=test --production=true --site-url=https://example.com && node --test --experimental-test-coverage --test-coverage-include=dist/app/assets/script/index.js --test-coverage-lines=100 --test-coverage-functions=100 --test-coverage-branches=100 test/*.test.js'\n },\n allowScripts: {\n '@parcel/watcher@2.5.1': true,\n 'esbuild@0.28.2': true\n },\n dependenciesMeta: {\n '@parcel/watcher@2.5.1': {built: true},\n 'esbuild@0.28.2': {built: true}\n },\n devDependencies: {\n '@tailwindcss/cli': '4.3.3',\n '@types/node': '24.13.3',\n 'axe-core': '4.13.0',\n 'esbuild': '0.28.2',\n 'html-validate': '11.15.0',\n 'jsdom': '30.0.1',\n 'tailwindcss': '4.3.3',\n 'typescript': '7.0.2'\n },\n dependencies: {\n 'white-label-mediator': '5.0.0',\n 'white-label-model': '7.0.1',\n 'white-label-router': '6.1.0',\n 'white-label-view': '7.0.0'\n }\n };\n}\n\nconst scaffoldCopies = [\n ['.editorconfig', '.editorconfig'],\n ['.yarnrc.yml', '.yarnrc.yml'],\n ['pnpm-workspace.yaml', 'pnpm-workspace.yaml'],\n ['app', 'app'],\n ['app/README.md', 'README.md'],\n ['server', 'server'],\n ['scripts', 'scripts'],\n ['template-test', 'test'],\n ['tsconfig.site.json', 'tsconfig.json']\n] as const;\n\n/** Create the canonical tagged-template White Label starter without overwriting user files. */\nexport async function createProject({destination, fileSystem = nodeFileSystem}: CreateProjectOptions) {\n await assertDestinationAvailable(destination);\n for (const [source, target] of scaffoldCopies) {\n await fileSystem.copy(path.join(packageRoot, source), path.join(destination, target));\n }\n await fileSystem.writeJSON(path.join(destination, 'package.json'), createSiteManifest());\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../scaffold/index.ts"],"names":[],"mappings":"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","sourcesContent":["/** @module scaffold */\nimport {cp, mkdir, readdir, writeFile} from 'node:fs/promises';\nimport path from 'node:path';\nimport {fileURLToPath} from 'node:url';\n\nconst packageRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');\n\nexport interface ScaffoldFileSystem {\n copy(source: string, destination: string): void | Promise<void>;\n writeJSON(destination: string, value: unknown): void | Promise<void>;\n}\n\nexport interface CreateProjectOptions {\n destination: string;\n fileSystem?: ScaffoldFileSystem;\n}\n\nconst nodeFileSystem: ScaffoldFileSystem = {\n async copy(source, destination) {\n await mkdir(path.dirname(destination), {recursive: true});\n await cp(source, destination, {recursive: true, force: false, errorOnExist: true});\n },\n async writeJSON(destination, value) {\n await mkdir(path.dirname(destination), {recursive: true});\n await writeFile(destination, `${JSON.stringify(value, null, 2)}\\n`, {flag: 'wx'});\n }\n};\n\n/** Refuse to layer a generated project over existing user files. */\nasync function assertDestinationAvailable(destination: string) {\n try {\n const entries = await readdir(destination);\n if (entries.length) {throw new Error(`Destination directory must be empty: ${destination}`);}\n } catch (error) {\n if (error instanceof Error && 'code' in error && error.code === 'ENOENT') {return;}\n throw error;\n }\n}\n\n/** Return the package manifest used by generated White Label projects. */\nexport function createSiteManifest() {\n return {\n name: 'white-label-site',\n version: '1.0.0',\n private: true,\n type: 'module',\n engines: {node: '^22.18.0 || >=24.11.0'},\n scripts: {\n build: 'tsc -p tsconfig.json && node dist/scripts/build.js',\n typecheck: 'tsc -p tsconfig.json --noEmit',\n test: 'node --run typecheck && node --run build -- --version=test --production=true --site-url=https://example.com && node --test --experimental-test-coverage --test-coverage-include=dist/app/assets/script/index.js --test-coverage-lines=100 --test-coverage-functions=100 --test-coverage-branches=100 test/*.test.js'\n },\n allowScripts: {\n '@parcel/watcher@2.5.1': true,\n 'esbuild@0.28.2': true\n },\n dependenciesMeta: {\n '@parcel/watcher@2.5.1': {built: true},\n 'esbuild@0.28.2': {built: true}\n },\n devDependencies: {\n '@tailwindcss/cli': '4.3.3',\n '@types/node': '24.13.3',\n 'axe-core': '4.13.0',\n 'esbuild': '0.28.2',\n 'html-validate': '11.15.0',\n 'jsdom': '30.0.1',\n 'tailwindcss': '4.3.3',\n 'typescript': '7.0.2'\n },\n dependencies: {\n 'white-label-mediator': '5.0.1',\n 'white-label-model': '7.0.2',\n 'white-label-router': '6.1.1',\n 'white-label-view': '7.0.1'\n }\n };\n}\n\nconst scaffoldCopies = [\n ['.editorconfig', '.editorconfig'],\n ['.yarnrc.yml', '.yarnrc.yml'],\n ['pnpm-workspace.yaml', 'pnpm-workspace.yaml'],\n ['app', 'app'],\n ['app/README.md', 'README.md'],\n ['server', 'server'],\n ['scripts', 'scripts'],\n ['template-test', 'test'],\n ['tsconfig.site.json', 'tsconfig.json']\n] as const;\n\n/** Create the canonical tagged-template White Label starter without overwriting user files. */\nexport async function createProject({destination, fileSystem = nodeFileSystem}: CreateProjectOptions) {\n await assertDestinationAvailable(destination);\n for (const [source, target] of scaffoldCopies) {\n await fileSystem.copy(path.join(packageRoot, source), path.join(destination, target));\n }\n await fileSystem.writeJSON(path.join(destination, 'package.json'), createSiteManifest());\n}\n"]}
@@ -7,6 +7,7 @@ import { build as buildJavaScript } from 'esbuild';
7
7
  const execFileAsync = promisify(execFile);
8
8
  const defaultProjectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
9
9
  const relativePublicPrefix = /^\/(?!\/)[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/;
10
+ const buildOptionNames = new Set(['cdn', 'production', 'site-url', 'version', 'www']);
10
11
  function hasControlCharacters(value) {
11
12
  return [...value].some(character => {
12
13
  const code = character.charCodeAt(0);
@@ -75,11 +76,28 @@ function normalizeBuildConfig(config) {
75
76
  }
76
77
  /** Read deployment flags and reject unsafe or invalid deployment values. */
77
78
  export function parseArguments(argumentsList) {
78
- const values = Object.fromEntries(argumentsList.map((argument) => {
79
- const [key, ...value] = argument.replace(/^--/, '').split('=');
80
- return [key, value.join('=')];
81
- }));
82
- const production = values.production === 'true';
79
+ const values = {};
80
+ for (const argument of argumentsList) {
81
+ if (!argument.startsWith('--')) {
82
+ throw new Error(`Unknown build option: ${argument}`);
83
+ }
84
+ const separator = argument.indexOf('=');
85
+ const key = argument.slice(2, separator === -1 ? undefined : separator);
86
+ if (!buildOptionNames.has(key)) {
87
+ throw new Error(`Unknown build option: --${key}`);
88
+ }
89
+ if (separator === -1) {
90
+ throw new Error(`Build option --${key} must use --${key}=value`);
91
+ }
92
+ values[key] = argument.slice(separator + 1);
93
+ }
94
+ let production = false;
95
+ if (values.production !== undefined) {
96
+ if (values.production !== 'true' && values.production !== 'false') {
97
+ throw new Error('Production must be true or false');
98
+ }
99
+ production = values.production === 'true';
100
+ }
83
101
  return normalizeBuildConfig({
84
102
  cdn: values.cdn || '/',
85
103
  production,
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../scripts/build.ts"],"names":[],"mappings":"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","sourcesContent":["/** Values injected into page templates and the generated config file. */\nexport interface BuildConfig {cdn: string; production: boolean; siteUrl: string; version: string; www: string}\nimport {execFile} from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport {promisify} from 'node:util';\nimport {fileURLToPath, pathToFileURL} from 'node:url';\nimport {build as buildJavaScript} from 'esbuild';\n\nconst execFileAsync = promisify(execFile);\nconst defaultProjectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');\nconst relativePublicPrefix = /^\\/(?!\\/)[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/;\n\nfunction hasControlCharacters(value: string): boolean {\n return [...value].some(character => {\n const code = character.charCodeAt(0);\n return code <= 0x1f || code === 0x7f;\n });\n}\n\nfunction normalizeVersion(value: unknown): string {\n if (typeof value !== 'string' || !/^[A-Za-z0-9._-]+$/.test(value) || value === '.' || value === '..') {\n throw new Error('Version may contain only letters, numbers, dots, underscores, and hyphens and must name one release directory');\n }\n return value;\n}\n\nfunction normalizeProduction(value: unknown): boolean {\n if (typeof value !== 'boolean') {throw new Error('Production must be a boolean');}\n return value;\n}\n\nfunction normalizeSiteUrl(value: unknown, production: boolean): string {\n if (typeof value !== 'string') {\n throw new Error('Site URL must be an absolute HTTP(S) URL; production builds require HTTPS');\n }\n let url: URL;\n try {url = new URL(value);} catch {throw new Error('Site URL must be an absolute HTTP(S) URL; production builds require HTTPS');}\n if (hasControlCharacters(value) || (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username || url.password || url.search || url.hash || (production && url.protocol !== 'https:')) {\n throw new Error('Site URL must be an absolute HTTP(S) URL without credentials, query, or fragment; production builds require HTTPS');\n }\n return url.toString().replace(/\\/$/, '');\n}\n\nfunction normalizePublicPrefix(value: unknown, name: 'www' | 'cdn', production: boolean): string {\n if (typeof value !== 'string' || hasControlCharacters(value)) {\n throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix`);\n }\n if (relativePublicPrefix.test(value)) {return value.endsWith('/') ? value : `${value}/`;}\n let url: URL;\n try {url = new URL(value);} catch {throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix`);}\n if ((url.protocol !== 'http:' && url.protocol !== 'https:') || url.username || url.password ||\n url.search || url.hash || (production && url.protocol !== 'https:')) {\n throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix${production ? ' using HTTPS in production' : ''}`);\n }\n const normalized = url.toString();\n return normalized.endsWith('/') ? normalized : `${normalized}/`;\n}\n\nfunction normalizeBuildConfig(config: BuildConfig): BuildConfig {\n const production = normalizeProduction(config.production);\n return {\n cdn: normalizePublicPrefix(config.cdn, 'cdn', production),\n production,\n siteUrl: normalizeSiteUrl(config.siteUrl, production),\n version: normalizeVersion(config.version),\n www: normalizePublicPrefix(config.www, 'www', production)\n };\n}\n\n/** Read deployment flags and reject unsafe or invalid deployment values. */\nexport function parseArguments(argumentsList: string[]): BuildConfig {\n const values = Object.fromEntries(argumentsList.map((argument) => {\n const [key, ...value] = argument.replace(/^--/, '').split('=');\n return [key, value.join('=')];\n }));\n const production = values.production === 'true';\n return normalizeBuildConfig({\n cdn: values.cdn || '/',\n production,\n siteUrl: values['site-url'] || 'http://localhost:8080',\n version: values.version || String(Math.floor(Date.now() / 1000)),\n www: values.www || '/'\n });\n}\n\n/** Return the local Tailwind executable name for the current platform. */\nexport function tailwindExecutable(platform: NodeJS.Platform = process.platform) {\n return platform === 'win32' ? 'tailwindcss.cmd' : 'tailwindcss';\n}\n\n/** Recursively collect files below a directory, propagating filesystem failures. */\nasync function filesUnder(directory: string): Promise<string[]> {\n const entries = await fs.readdir(directory, {withFileTypes: true});\n const files = await Promise.all(entries.map(async (entry) => {\n const location = path.join(directory, entry.name);\n return entry.isDirectory() ? filesUnder(location) : [location];\n }));\n return files.flat();\n}\n\ninterface PageModule {\n default(data: Record<string, unknown>): {toString(): string} | string;\n}\n\n/** Render compiled TypeScript pages using global, page-specific, and deployment data. */\nasync function renderMarkup(config: BuildConfig, outputRoot: string, projectRoot: string) {\n const globalData = JSON.parse(await fs.readFile(\n path.join(projectRoot, 'app/assets/data/view/global.json'), 'utf8'\n )) as Record<string, unknown>;\n const appRoot = path.join(projectRoot, 'app');\n const pages = (await filesUnder(appRoot))\n .filter((file) => /\\.ts$/.test(file) && !file.endsWith('.d.ts') && !file.includes(`${path.sep}assets${path.sep}`));\n\n await Promise.all(pages.map(async (page) => {\n const relative = path.relative(appRoot, page);\n const pageDataPath = path.join(projectRoot, 'app/assets/data/view', relative.replace(/\\.ts$/, '.json'));\n let pageData: Record<string, unknown> = {};\n try {\n pageData = JSON.parse(await fs.readFile(pageDataPath, 'utf8')) as Record<string, unknown>;\n } catch (error) {\n if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT')) {\n throw error;\n }\n }\n const compiledPage = path.join(projectRoot, 'dist/app', relative.replace(/\\.ts$/, '.js'));\n const module = await import(pathToFileURL(compiledPage).href) as PageModule;\n if (typeof module.default !== 'function') {\n throw new TypeError(`Page module ${relative} must export a default render function`);\n }\n const markup = module.default({...globalData, ...pageData, ...config});\n const destination = path.join(outputRoot, relative.replace(/\\.ts$/, '.html'));\n await fs.mkdir(path.dirname(destination), {recursive: true});\n await fs.writeFile(destination, `<!DOCTYPE html>\\n${String(markup)}\\n`);\n }));\n}\n\n/** Compile Tailwind and project CSS into the deploy directory. */\nasync function compileStyles(outputAssets: string, production: boolean, projectRoot: string) {\n const styleRoot = path.join(projectRoot, 'app/assets/style');\n await fs.mkdir(path.join(outputAssets, 'style'), {recursive: true});\n const destination = path.join(outputAssets, 'style/global.css');\n const argumentsList = [\n '-i', path.join(styleRoot, 'global.css'),\n '-o', destination\n ];\n if (production) {argumentsList.push('--minify');}\n await execFileAsync(tailwindExecutable(), argumentsList, {cwd: projectRoot});\n await fs.copyFile(path.join(styleRoot, 'print.css'), path.join(outputAssets, 'style/print.css'));\n}\n\n/** Bundle plain TypeScript browser entry points, excluding declaration-only files. */\nasync function compileScripts(outputAssets: string, production: boolean, projectRoot: string) {\n const scriptRoot = path.join(projectRoot, 'app/assets/script');\n const entries = (await fs.readdir(scriptRoot, {withFileTypes: true}))\n .filter((entry) => entry.isFile() && !entry.name.endsWith('.d.ts') && entry.name.endsWith('.ts'))\n .map((entry) => path.join(scriptRoot, entry.name));\n await fs.mkdir(path.join(outputAssets, 'script'), {recursive: true});\n await buildJavaScript({\n bundle: true,\n entryNames: '[name].compiled',\n entryPoints: entries,\n format: 'iife',\n loader: {'.ts': 'ts'},\n minify: production,\n outdir: path.join(outputAssets, 'script'),\n sourcemap: !production,\n target: ['es2018']\n });\n await fs.writeFile(path.join(outputAssets, 'script/global.compiled.js'), '');\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n}\n\n/** Replace the deployment directory with compiled pages, scripts, styles, and static assets. */\nexport async function build(config = parseArguments(process.argv.slice(2)), projectRoot = defaultProjectRoot) {\n const safeConfig = normalizeBuildConfig(config);\n const outputRoot = path.join(projectRoot, '_deploy');\n const outputAssets = path.join(outputRoot, 'release', safeConfig.version, 'assets');\n await fs.rm(outputRoot, {recursive: true, force: true});\n await fs.mkdir(outputAssets, {recursive: true});\n\n await fs.cp(path.join(projectRoot, 'app/assets/data'), path.join(outputAssets, 'data'), {recursive: true});\n await fs.writeFile(path.join(outputAssets, 'data/config.json'), JSON.stringify(safeConfig));\n await renderMarkup(safeConfig, outputRoot, projectRoot);\n await compileStyles(outputAssets, safeConfig.production, projectRoot);\n await compileScripts(outputAssets, safeConfig.production, projectRoot);\n const robots = `User-agent: *\\nAllow: /\\nSitemap: ${safeConfig.siteUrl}/sitemap.xml\\n`;\n await fs.writeFile(path.join(outputRoot, 'robots.txt'), robots);\n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>${escapeXml(`${safeConfig.siteUrl}/`)}</loc></url></urlset>\\n`;\n await fs.writeFile(path.join(outputRoot, 'sitemap.xml'), sitemap);\n}\n\nif (path.resolve(process.argv[1] || '') === fileURLToPath(import.meta.url)) {\n await build();\n}\n"]}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../scripts/build.ts"],"names":[],"mappings":"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","sourcesContent":["/** Values injected into page templates and the generated config file. */\nexport interface BuildConfig {cdn: string; production: boolean; siteUrl: string; version: string; www: string}\nimport {execFile} from 'node:child_process';\nimport fs from 'node:fs/promises';\nimport path from 'node:path';\nimport {promisify} from 'node:util';\nimport {fileURLToPath, pathToFileURL} from 'node:url';\nimport {build as buildJavaScript} from 'esbuild';\n\nconst execFileAsync = promisify(execFile);\nconst defaultProjectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');\nconst relativePublicPrefix = /^\\/(?!\\/)[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/;\nconst buildOptionNames = new Set(['cdn', 'production', 'site-url', 'version', 'www']);\n\nfunction hasControlCharacters(value: string): boolean {\n return [...value].some(character => {\n const code = character.charCodeAt(0);\n return code <= 0x1f || code === 0x7f;\n });\n}\n\nfunction normalizeVersion(value: unknown): string {\n if (typeof value !== 'string' || !/^[A-Za-z0-9._-]+$/.test(value) || value === '.' || value === '..') {\n throw new Error('Version may contain only letters, numbers, dots, underscores, and hyphens and must name one release directory');\n }\n return value;\n}\n\nfunction normalizeProduction(value: unknown): boolean {\n if (typeof value !== 'boolean') {throw new Error('Production must be a boolean');}\n return value;\n}\n\nfunction normalizeSiteUrl(value: unknown, production: boolean): string {\n if (typeof value !== 'string') {\n throw new Error('Site URL must be an absolute HTTP(S) URL; production builds require HTTPS');\n }\n let url: URL;\n try {url = new URL(value);} catch {throw new Error('Site URL must be an absolute HTTP(S) URL; production builds require HTTPS');}\n if (hasControlCharacters(value) || (url.protocol !== 'http:' && url.protocol !== 'https:') ||\n url.username || url.password || url.search || url.hash || (production && url.protocol !== 'https:')) {\n throw new Error('Site URL must be an absolute HTTP(S) URL without credentials, query, or fragment; production builds require HTTPS');\n }\n return url.toString().replace(/\\/$/, '');\n}\n\nfunction normalizePublicPrefix(value: unknown, name: 'www' | 'cdn', production: boolean): string {\n if (typeof value !== 'string' || hasControlCharacters(value)) {\n throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix`);\n }\n if (relativePublicPrefix.test(value)) {return value.endsWith('/') ? value : `${value}/`;}\n let url: URL;\n try {url = new URL(value);} catch {throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix`);}\n if ((url.protocol !== 'http:' && url.protocol !== 'https:') || url.username || url.password ||\n url.search || url.hash || (production && url.protocol !== 'https:')) {\n throw new Error(`${name} must be a root-relative or absolute HTTP(S) URL prefix${production ? ' using HTTPS in production' : ''}`);\n }\n const normalized = url.toString();\n return normalized.endsWith('/') ? normalized : `${normalized}/`;\n}\n\nfunction normalizeBuildConfig(config: BuildConfig): BuildConfig {\n const production = normalizeProduction(config.production);\n return {\n cdn: normalizePublicPrefix(config.cdn, 'cdn', production),\n production,\n siteUrl: normalizeSiteUrl(config.siteUrl, production),\n version: normalizeVersion(config.version),\n www: normalizePublicPrefix(config.www, 'www', production)\n };\n}\n\n/** Read deployment flags and reject unsafe or invalid deployment values. */\nexport function parseArguments(argumentsList: string[]): BuildConfig {\n const values: Record<string, string> = {};\n for (const argument of argumentsList) {\n if (!argument.startsWith('--')) {throw new Error(`Unknown build option: ${argument}`);}\n const separator = argument.indexOf('=');\n const key = argument.slice(2, separator === -1 ? undefined : separator);\n if (!buildOptionNames.has(key)) {throw new Error(`Unknown build option: --${key}`);}\n if (separator === -1) {throw new Error(`Build option --${key} must use --${key}=value`);}\n values[key] = argument.slice(separator + 1);\n }\n\n let production = false;\n if (values.production !== undefined) {\n if (values.production !== 'true' && values.production !== 'false') {\n throw new Error('Production must be true or false');\n }\n production = values.production === 'true';\n }\n\n return normalizeBuildConfig({\n cdn: values.cdn || '/',\n production,\n siteUrl: values['site-url'] || 'http://localhost:8080',\n version: values.version || String(Math.floor(Date.now() / 1000)),\n www: values.www || '/'\n });\n}\n\n/** Return the local Tailwind executable name for the current platform. */\nexport function tailwindExecutable(platform: NodeJS.Platform = process.platform) {\n return platform === 'win32' ? 'tailwindcss.cmd' : 'tailwindcss';\n}\n\n/** Recursively collect files below a directory, propagating filesystem failures. */\nasync function filesUnder(directory: string): Promise<string[]> {\n const entries = await fs.readdir(directory, {withFileTypes: true});\n const files = await Promise.all(entries.map(async (entry) => {\n const location = path.join(directory, entry.name);\n return entry.isDirectory() ? filesUnder(location) : [location];\n }));\n return files.flat();\n}\n\ninterface PageModule {\n default(data: Record<string, unknown>): {toString(): string} | string;\n}\n\n/** Render compiled TypeScript pages using global, page-specific, and deployment data. */\nasync function renderMarkup(config: BuildConfig, outputRoot: string, projectRoot: string) {\n const globalData = JSON.parse(await fs.readFile(\n path.join(projectRoot, 'app/assets/data/view/global.json'), 'utf8'\n )) as Record<string, unknown>;\n const appRoot = path.join(projectRoot, 'app');\n const pages = (await filesUnder(appRoot))\n .filter((file) => /\\.ts$/.test(file) && !file.endsWith('.d.ts') && !file.includes(`${path.sep}assets${path.sep}`));\n\n await Promise.all(pages.map(async (page) => {\n const relative = path.relative(appRoot, page);\n const pageDataPath = path.join(projectRoot, 'app/assets/data/view', relative.replace(/\\.ts$/, '.json'));\n let pageData: Record<string, unknown> = {};\n try {\n pageData = JSON.parse(await fs.readFile(pageDataPath, 'utf8')) as Record<string, unknown>;\n } catch (error) {\n if (!(error instanceof Error && 'code' in error && error.code === 'ENOENT')) {\n throw error;\n }\n }\n const compiledPage = path.join(projectRoot, 'dist/app', relative.replace(/\\.ts$/, '.js'));\n const module = await import(pathToFileURL(compiledPage).href) as PageModule;\n if (typeof module.default !== 'function') {\n throw new TypeError(`Page module ${relative} must export a default render function`);\n }\n const markup = module.default({...globalData, ...pageData, ...config});\n const destination = path.join(outputRoot, relative.replace(/\\.ts$/, '.html'));\n await fs.mkdir(path.dirname(destination), {recursive: true});\n await fs.writeFile(destination, `<!DOCTYPE html>\\n${String(markup)}\\n`);\n }));\n}\n\n/** Compile Tailwind and project CSS into the deploy directory. */\nasync function compileStyles(outputAssets: string, production: boolean, projectRoot: string) {\n const styleRoot = path.join(projectRoot, 'app/assets/style');\n await fs.mkdir(path.join(outputAssets, 'style'), {recursive: true});\n const destination = path.join(outputAssets, 'style/global.css');\n const argumentsList = [\n '-i', path.join(styleRoot, 'global.css'),\n '-o', destination\n ];\n if (production) {argumentsList.push('--minify');}\n await execFileAsync(tailwindExecutable(), argumentsList, {cwd: projectRoot});\n await fs.copyFile(path.join(styleRoot, 'print.css'), path.join(outputAssets, 'style/print.css'));\n}\n\n/** Bundle plain TypeScript browser entry points, excluding declaration-only files. */\nasync function compileScripts(outputAssets: string, production: boolean, projectRoot: string) {\n const scriptRoot = path.join(projectRoot, 'app/assets/script');\n const entries = (await fs.readdir(scriptRoot, {withFileTypes: true}))\n .filter((entry) => entry.isFile() && !entry.name.endsWith('.d.ts') && entry.name.endsWith('.ts'))\n .map((entry) => path.join(scriptRoot, entry.name));\n await fs.mkdir(path.join(outputAssets, 'script'), {recursive: true});\n await buildJavaScript({\n bundle: true,\n entryNames: '[name].compiled',\n entryPoints: entries,\n format: 'iife',\n loader: {'.ts': 'ts'},\n minify: production,\n outdir: path.join(outputAssets, 'script'),\n sourcemap: !production,\n target: ['es2018']\n });\n await fs.writeFile(path.join(outputAssets, 'script/global.compiled.js'), '');\n}\n\nfunction escapeXml(value: string): string {\n return value\n .replaceAll('&', '&amp;')\n .replaceAll('<', '&lt;')\n .replaceAll('>', '&gt;')\n .replaceAll('\"', '&quot;')\n .replaceAll(\"'\", '&apos;');\n}\n\n/** Replace the deployment directory with compiled pages, scripts, styles, and static assets. */\nexport async function build(config = parseArguments(process.argv.slice(2)), projectRoot = defaultProjectRoot) {\n const safeConfig = normalizeBuildConfig(config);\n const outputRoot = path.join(projectRoot, '_deploy');\n const outputAssets = path.join(outputRoot, 'release', safeConfig.version, 'assets');\n await fs.rm(outputRoot, {recursive: true, force: true});\n await fs.mkdir(outputAssets, {recursive: true});\n\n await fs.cp(path.join(projectRoot, 'app/assets/data'), path.join(outputAssets, 'data'), {recursive: true});\n await fs.writeFile(path.join(outputAssets, 'data/config.json'), JSON.stringify(safeConfig));\n await renderMarkup(safeConfig, outputRoot, projectRoot);\n await compileStyles(outputAssets, safeConfig.production, projectRoot);\n await compileScripts(outputAssets, safeConfig.production, projectRoot);\n const robots = `User-agent: *\\nAllow: /\\nSitemap: ${safeConfig.siteUrl}/sitemap.xml\\n`;\n await fs.writeFile(path.join(outputRoot, 'robots.txt'), robots);\n const sitemap = `<?xml version=\"1.0\" encoding=\"UTF-8\"?>\\n<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\"><url><loc>${escapeXml(`${safeConfig.siteUrl}/`)}</loc></url></urlset>\\n`;\n await fs.writeFile(path.join(outputRoot, 'sitemap.xml'), sitemap);\n}\n\nif (path.resolve(process.argv[1] || '') === fileURLToPath(import.meta.url)) {\n await build();\n}\n"]}
@@ -43,7 +43,7 @@ export async function handleRequest(request) {
43
43
  defaultRoute: () => true
44
44
  };
45
45
  try {
46
- router.navigate(`${url.pathname}${url.search}`);
46
+ router.navigate(url.toString());
47
47
  view.initialize();
48
48
  return new Response(`<!doctype html>${view.toString()}`, {
49
49
  status: model.get().status,
@@ -1 +1 @@
1
- {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../server/handler.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,yBAAyB,CAAC;AAC3C,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAQ3C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAChD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACpB,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,gBAAgB,GAAG,CAAC,QAAQ,GAAG;KAC3C,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QAClB,KAAK;QACL,QAAQ,CAAC,IAAI;YACT,MAAM,KAAK,GAAG,IAAmB,CAAC;YAClC,OAAO,IAAI,CAAA,aAAa,KAAK,CAAC,KAAK,WAAW,KAAK,CAAC,OAAO,aAAa,CAAC;QAC7E,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,MAAM,GAAG;QACZ,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,SAAS;YAChB,OAAO,EAAE,6BAA6B;SACzC,CAAC;QACF,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC,MAAM,CAAC;gBAChB,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,SAAS,IAAI,GAAG;aAC5B,CAAC,CAAC;QACP,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI;KAC3B,CAAC;IAEF,IAAI,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,IAAI,QAAQ,CAAC,kBAAkB,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE;YACrD,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM;YAC1B,OAAO,EAAE,EAAC,cAAc,EAAE,0BAA0B,EAAC;SACxD,CAAC,CAAC;IACP,CAAC;YAAS,CAAC;QACP,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,KAAK,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC;AACL,CAAC","sourcesContent":["import Mediator from 'white-label-mediator';\nimport {Model} from 'white-label-model';\nimport Router from 'white-label-router';\nimport View from 'white-label-view/server';\nimport {html} from 'white-label-view/html';\n\ntype ServerState = {\n status: number;\n title: string;\n message: string;\n};\n\n/**\n * Provider-neutral serverless example using the Web Request/Response contract.\n *\n * Keep mutable White Label instances request-scoped. Cloud adapters should only\n * translate their provider event into a Request and translate the Response back.\n */\nexport async function handleRequest(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const mediator = new Mediator();\n const model = new Model({\n status: 404,\n title: 'Not found',\n message: `No route for ${url.pathname}.`\n });\n const router = new Router();\n const view = new View({\n model,\n template(data) {\n const state = data as ServerState;\n return html`<main><h1>${state.title}</h1><p>${state.message}</p></main>`;\n }\n });\n\n router.mediator = mediator;\n router.routes = {\n '/health': () => model.update({\n status: 200,\n title: 'Healthy',\n message: 'Serverless request handled.'\n }),\n '/hello': (_scope, location) => {\n const name = String(location.data.query.name ?? 'world');\n return model.update({\n status: 200,\n title: 'Hello',\n message: `Hello ${name}.`\n });\n },\n defaultRoute: () => true\n };\n\n try {\n router.navigate(`${url.pathname}${url.search}`);\n view.initialize();\n return new Response(`<!doctype html>${view.toString()}`, {\n status: model.get().status,\n headers: {'content-type': 'text/html; charset=utf-8'}\n });\n } finally {\n view.destroy();\n router.destroy();\n mediator.destroy();\n model.destroy();\n }\n}\n"]}
1
+ {"version":3,"file":"handler.js","sourceRoot":"","sources":["../../server/handler.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,sBAAsB,CAAC;AAC5C,OAAO,EAAC,KAAK,EAAC,MAAM,mBAAmB,CAAC;AACxC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,IAAI,MAAM,yBAAyB,CAAC;AAC3C,OAAO,EAAC,IAAI,EAAC,MAAM,uBAAuB,CAAC;AAQ3C;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAAgB;IAChD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACjC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC;IAChC,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACpB,MAAM,EAAE,GAAG;QACX,KAAK,EAAE,WAAW;QAClB,OAAO,EAAE,gBAAgB,GAAG,CAAC,QAAQ,GAAG;KAC3C,CAAC,CAAC;IACH,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC;QAClB,KAAK;QACL,QAAQ,CAAC,IAAI;YACT,MAAM,KAAK,GAAG,IAAmB,CAAC;YAClC,OAAO,IAAI,CAAA,aAAa,KAAK,CAAC,KAAK,WAAW,KAAK,CAAC,OAAO,aAAa,CAAC;QAC7E,CAAC;KACJ,CAAC,CAAC;IAEH,MAAM,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,MAAM,CAAC,MAAM,GAAG;QACZ,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,MAAM,CAAC;YAC1B,MAAM,EAAE,GAAG;YACX,KAAK,EAAE,SAAS;YAChB,OAAO,EAAE,6BAA6B;SACzC,CAAC;QACF,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,EAAE;YAC3B,MAAM,IAAI,GAAG,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,CAAC;YACzD,OAAO,KAAK,CAAC,MAAM,CAAC;gBAChB,MAAM,EAAE,GAAG;gBACX,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,SAAS,IAAI,GAAG;aAC5B,CAAC,CAAC;QACP,CAAC;QACD,YAAY,EAAE,GAAG,EAAE,CAAC,IAAI;KAC3B,CAAC;IAEF,IAAI,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;QAChC,IAAI,CAAC,UAAU,EAAE,CAAC;QAClB,OAAO,IAAI,QAAQ,CAAC,kBAAkB,IAAI,CAAC,QAAQ,EAAE,EAAE,EAAE;YACrD,MAAM,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,MAAM;YAC1B,OAAO,EAAE,EAAC,cAAc,EAAE,0BAA0B,EAAC;SACxD,CAAC,CAAC;IACP,CAAC;YAAS,CAAC;QACP,IAAI,CAAC,OAAO,EAAE,CAAC;QACf,MAAM,CAAC,OAAO,EAAE,CAAC;QACjB,QAAQ,CAAC,OAAO,EAAE,CAAC;QACnB,KAAK,CAAC,OAAO,EAAE,CAAC;IACpB,CAAC;AACL,CAAC","sourcesContent":["import Mediator from 'white-label-mediator';\nimport {Model} from 'white-label-model';\nimport Router from 'white-label-router';\nimport View from 'white-label-view/server';\nimport {html} from 'white-label-view/html';\n\ntype ServerState = {\n status: number;\n title: string;\n message: string;\n};\n\n/**\n * Provider-neutral serverless example using the Web Request/Response contract.\n *\n * Keep mutable White Label instances request-scoped. Cloud adapters should only\n * translate their provider event into a Request and translate the Response back.\n */\nexport async function handleRequest(request: Request): Promise<Response> {\n const url = new URL(request.url);\n const mediator = new Mediator();\n const model = new Model({\n status: 404,\n title: 'Not found',\n message: `No route for ${url.pathname}.`\n });\n const router = new Router();\n const view = new View({\n model,\n template(data) {\n const state = data as ServerState;\n return html`<main><h1>${state.title}</h1><p>${state.message}</p></main>`;\n }\n });\n\n router.mediator = mediator;\n router.routes = {\n '/health': () => model.update({\n status: 200,\n title: 'Healthy',\n message: 'Serverless request handled.'\n }),\n '/hello': (_scope, location) => {\n const name = String(location.data.query.name ?? 'world');\n return model.update({\n status: 200,\n title: 'Hello',\n message: `Hello ${name}.`\n });\n },\n defaultRoute: () => true\n };\n\n try {\n router.navigate(url.toString());\n view.initialize();\n return new Response(`<!doctype html>${view.toString()}`, {\n status: model.get().status,\n headers: {'content-type': 'text/html; charset=utf-8'}\n });\n } finally {\n view.destroy();\n router.destroy();\n mediator.destroy();\n model.destroy();\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "generator-white-label",
3
- "version": "10.0.0",
3
+ "version": "10.0.1",
4
4
  "description": "Framework-independent TypeScript project generator for accessible, SEO-friendly, HTML-first sites with progressive enhancement, tagged HTML templates, and provider-neutral serverless composition.",
5
5
  "type": "module",
6
6
  "main": "dist/scaffold/index.js",
@@ -87,10 +87,10 @@
87
87
  "jsdom": "30.0.1",
88
88
  "tailwindcss": "4.3.3",
89
89
  "typescript": "7.0.2",
90
- "white-label-mediator": "5.0.0",
91
- "white-label-model": "7.0.1",
92
- "white-label-router": "6.1.0",
93
- "white-label-view": "7.0.0"
90
+ "white-label-mediator": "5.0.1",
91
+ "white-label-model": "7.0.2",
92
+ "white-label-router": "6.1.1",
93
+ "white-label-view": "7.0.1"
94
94
  },
95
95
  "types": "dist/scaffold/index.d.ts",
96
96
  "c8": {
@@ -20,4 +20,4 @@ These instructions are more specific than the repository-root agent guide for fi
20
20
 
21
21
  ## Coordinated release dependency
22
22
 
23
- Generator 10 targets the exact published coordinated runtime versions: `white-label-mediator@5.0.0`, `white-label-model@7.0.1`, `white-label-router@6.1.0`, and `white-label-view@7.0.0`. Keep the release lockfile registry-based and regenerate it with the package manager when coordinated runtime versions change.
23
+ Generator 10 targets the exact published coordinated runtime versions: `white-label-mediator@5.0.1`, `white-label-model@7.0.2`, `white-label-router@6.1.1`, and `white-label-view@7.0.1`. Keep the release lockfile registry-based and regenerate it with the package manager when coordinated runtime versions change.
package/scaffold/index.ts CHANGED
@@ -18,11 +18,11 @@ export interface CreateProjectOptions {
18
18
  const nodeFileSystem: ScaffoldFileSystem = {
19
19
  async copy(source, destination) {
20
20
  await mkdir(path.dirname(destination), {recursive: true});
21
- await cp(source, destination, {recursive: true});
21
+ await cp(source, destination, {recursive: true, force: false, errorOnExist: true});
22
22
  },
23
23
  async writeJSON(destination, value) {
24
24
  await mkdir(path.dirname(destination), {recursive: true});
25
- await writeFile(destination, `${JSON.stringify(value, null, 2)}\n`);
25
+ await writeFile(destination, `${JSON.stringify(value, null, 2)}\n`, {flag: 'wx'});
26
26
  }
27
27
  };
28
28
 
@@ -69,10 +69,10 @@ export function createSiteManifest() {
69
69
  'typescript': '7.0.2'
70
70
  },
71
71
  dependencies: {
72
- 'white-label-mediator': '5.0.0',
73
- 'white-label-model': '7.0.1',
74
- 'white-label-router': '6.1.0',
75
- 'white-label-view': '7.0.0'
72
+ 'white-label-mediator': '5.0.1',
73
+ 'white-label-model': '7.0.2',
74
+ 'white-label-router': '6.1.1',
75
+ 'white-label-view': '7.0.1'
76
76
  }
77
77
  };
78
78
  }
package/scripts/build.ts CHANGED
@@ -10,6 +10,7 @@ import {build as buildJavaScript} from 'esbuild';
10
10
  const execFileAsync = promisify(execFile);
11
11
  const defaultProjectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../..');
12
12
  const relativePublicPrefix = /^\/(?!\/)[A-Za-z0-9._~!$&'()*+,;=:@%/-]*$/;
13
+ const buildOptionNames = new Set(['cdn', 'production', 'site-url', 'version', 'www']);
13
14
 
14
15
  function hasControlCharacters(value: string): boolean {
15
16
  return [...value].some(character => {
@@ -71,11 +72,24 @@ function normalizeBuildConfig(config: BuildConfig): BuildConfig {
71
72
 
72
73
  /** Read deployment flags and reject unsafe or invalid deployment values. */
73
74
  export function parseArguments(argumentsList: string[]): BuildConfig {
74
- const values = Object.fromEntries(argumentsList.map((argument) => {
75
- const [key, ...value] = argument.replace(/^--/, '').split('=');
76
- return [key, value.join('=')];
77
- }));
78
- const production = values.production === 'true';
75
+ const values: Record<string, string> = {};
76
+ for (const argument of argumentsList) {
77
+ if (!argument.startsWith('--')) {throw new Error(`Unknown build option: ${argument}`);}
78
+ const separator = argument.indexOf('=');
79
+ const key = argument.slice(2, separator === -1 ? undefined : separator);
80
+ if (!buildOptionNames.has(key)) {throw new Error(`Unknown build option: --${key}`);}
81
+ if (separator === -1) {throw new Error(`Build option --${key} must use --${key}=value`);}
82
+ values[key] = argument.slice(separator + 1);
83
+ }
84
+
85
+ let production = false;
86
+ if (values.production !== undefined) {
87
+ if (values.production !== 'true' && values.production !== 'false') {
88
+ throw new Error('Production must be true or false');
89
+ }
90
+ production = values.production === 'true';
91
+ }
92
+
79
93
  return normalizeBuildConfig({
80
94
  cdn: values.cdn || '/',
81
95
  production,
package/server/handler.ts CHANGED
@@ -52,7 +52,7 @@ export async function handleRequest(request: Request): Promise<Response> {
52
52
  };
53
53
 
54
54
  try {
55
- router.navigate(`${url.pathname}${url.search}`);
55
+ router.navigate(url.toString());
56
56
  view.initialize();
57
57
  return new Response(`<!doctype html>${view.toString()}`, {
58
58
  status: model.get().status,