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 | 3x 7x 7x 10x 10x 10x 7x 7x 7x 10x 10x 10x 2x 2x 2x 1x 2x | /**
* AsyncAPI specification generation for WebSocket endpoints
* Core logic - no Vite dependencies
*/
import * as fs from 'fs';
import * as path from 'path';
export type SocketForDocs = { pattern: string };
export interface AsyncApiInfo {
title?: string;
version?: string;
description?: string;
}
export interface AsyncApiOptions {
info?: AsyncApiInfo;
/** Server URL for WebSocket (e.g. ws://localhost:5173). Defaults to current origin with ws(s). */
serverUrl?: string;
}
const DEFAULT_ASYNCAPI_INFO: AsyncApiInfo = {
title: 'Vitek WebSocket API',
version: '1.0.0',
description: 'WebSocket endpoints (auto-generated from socket routes)',
};
function fullSocketPath(basePath: string, pattern: string): string {
const base = basePath.replace(/\/$/, '');
return pattern === '' ? base : `${base}/${pattern}`;
}
/**
* Generates AsyncAPI 2.x specification from socket entries
*/
export function generateAsyncApiSpec(
sockets: SocketForDocs[],
socketBasePath: string,
options: AsyncApiOptions = {}
): object {
const info = { ...DEFAULT_ASYNCAPI_INFO, ...options.info };
const channels: Record<string, unknown> = {};
for (const socket of sockets) {
const channelPath = fullSocketPath(socketBasePath, socket.pattern);
const description =
socket.pattern === ''
? 'Root WebSocket endpoint'
: `WebSocket: ${channelPath}`;
channels[channelPath] = {
description,
subscribe: {
operationId: `onMessage_${channelPath.replace(/\//g, '_')}`,
message: {
description: 'Incoming message',
payload: { type: 'object', description: 'JSON payload' },
},
},
publish: {
operationId: `send_${channelPath.replace(/\//g, '_')}`,
message: {
description: 'Outgoing message',
payload: { type: 'object', description: 'JSON payload' },
},
},
};
}
const serverUrl = options.serverUrl ?? 'ws://localhost:5173';
const spec: Record<string, unknown> = {
asyncapi: '2.4.0',
info: {
title: info.title,
version: info.version ?? '1.0.0',
description: info.description,
},
servers: {
development: {
url: serverUrl,
protocol: serverUrl.startsWith('wss') ? 'wss' : 'ws',
description: 'Development server',
},
},
channels,
};
return spec;
}
/**
* Writes AsyncAPI spec to a JSON file
*/
export async function generateAsyncApiFile(
outputPath: string,
sockets: SocketForDocs[],
socketBasePath: string,
options: AsyncApiOptions = {}
): Promise<void> {
const spec = generateAsyncApiSpec(sockets, socketBasePath, options);
const dir = path.dirname(outputPath);
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir, { recursive: true });
}
fs.writeFileSync(outputPath, JSON.stringify(spec, null, 2), 'utf-8');
}
|