Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 3x 3x 1x 2x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | /**
* Builds the sockets bundle for preview/production
* Scans apiDir for *.socket.ts/js, generates an entry module, bundles with esbuild
*/
import * as path from 'path';
import * as fs from 'fs';
import { scanApiDirectory } from '../core/file-system/scan-api-dir.js';
import { patternToRegex } from '../core/normalize/normalize-path.js';
import type { ParsedSocket } from '../core/routing/socket-parser.js';
import { VITEK_SOCKETS_BUNDLE_FILENAME } from '../shared/constants.js';
export interface BuildSocketsBundleOptions {
root: string;
apiDir: string;
outDir: string;
}
/**
* Generates the entry file content that imports all socket handlers
* and exports { sockets } in the shape expected by createSocketHandler
*/
function generateSocketsEntryContent(sockets: ParsedSocket[], entryDir: string): string {
const lines: string[] = [];
sockets.forEach((parsed, i) => {
const rel = path.relative(entryDir, parsed.file).replace(/\\/g, '/');
const importPath = rel.startsWith('.') ? rel : `./${rel}`;
lines.push(`import handler_${i} from ${JSON.stringify(importPath)};`);
});
const socketEntries = sockets.map((parsed, i) => {
const regex = patternToRegex(parsed.pattern);
const regexSource = regex.source;
return ` { pattern: ${JSON.stringify(parsed.pattern)}, params: ${JSON.stringify(parsed.params)}, file: ${JSON.stringify(parsed.file)}, regex: new RegExp(${JSON.stringify(regexSource)}), handler: (() => { const m = handler_${i}; return typeof m === 'function' ? m : m.default; })() }`;
});
lines.push('');
lines.push('const sockets = [');
lines.push(socketEntries.join(',\n'));
lines.push('];');
lines.push('');
lines.push('export { sockets };');
return lines.join('\n');
}
/**
* Builds the sockets bundle and writes it to outDir/vitek-sockets.mjs
* Returns the path to the written file, or null if skipped (no sockets or error)
*/
export async function buildSocketsBundle(
options: BuildSocketsBundleOptions
): Promise<string | null> {
const { apiDir, outDir } = options;
if (!fs.existsSync(apiDir)) {
return null;
}
const scanResult = scanApiDirectory(apiDir);
if (scanResult.sockets.length === 0) {
return null;
}
const tmpDir = path.join(outDir, '.vitek-tmp');
Eif (!fs.existsSync(tmpDir)) {
fs.mkdirSync(tmpDir, { recursive: true });
}
const tmpEntry = path.join(tmpDir, 'vitek-sockets-entry.mts');
const entryContent = generateSocketsEntryContent(
scanResult.sockets,
path.dirname(tmpEntry)
);
fs.writeFileSync(tmpEntry, entryContent, 'utf-8');
const outFile = path.join(outDir, VITEK_SOCKETS_BUNDLE_FILENAME);
const esbuild = (await import('esbuild').catch(() => null)) as {
build: (opts: unknown) => Promise<void>;
} | null;
Iif (!esbuild) {
return null;
}
try {
await esbuild.build({
entryPoints: [tmpEntry],
bundle: true,
format: 'esm',
platform: 'node',
outfile: outFile,
external: ['vitek-plugin'],
});
return outFile;
} finally {
try {
fs.unlinkSync(tmpEntry);
Eif (fs.existsSync(tmpDir) && fs.readdirSync(tmpDir).length === 0) {
fs.rmdirSync(tmpDir);
}
} catch {
// ignore cleanup errors
}
}
}
export function getSocketsBundleFilename(): string {
return VITEK_SOCKETS_BUNDLE_FILENAME;
}
|