You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
73 lines
2.9 KiB
73 lines
2.9 KiB
import { loadEnv, type Plugin } from 'vite';
|
|
import type { SessionPersona } from '../../project/persona.js';
|
|
import { NoopAnalyticsRecorder, SqliteAnalyticsRecorder } from './analytics.js';
|
|
import { loadConfig } from './config.js';
|
|
import { resolveSessionDefaults } from './defaults.js';
|
|
import { selectProvider } from './providers/index.js';
|
|
import type { ToolRegistry } from './tools.js';
|
|
import { handleRealtimeUpgrade } from './ws-handler.js';
|
|
|
|
export interface RealtimeDevWsPluginOptions {
|
|
/**
|
|
* Raw, env-independent pieces (project persona + tool registry) — taken as
|
|
* parameters rather than imported here so this module (server/core) never
|
|
* has to import project code directly. See vite.config.ts, the
|
|
* composition root that supplies these, and docs/TOOLS.md.
|
|
*
|
|
* Deliberately NOT pre-resolved against env vars by the caller: resolving
|
|
* them happens inside configureServer below, gated by the VITEST check —
|
|
* see the comment on that check for why.
|
|
*/
|
|
persona: SessionPersona;
|
|
toolRegistry: ToolRegistry;
|
|
}
|
|
|
|
/**
|
|
* Wires the same upgrade handling used in production (see repo-root
|
|
* server.js) into Vite's dev server, so `npm run dev` supports the realtime
|
|
* WS endpoint without a production build.
|
|
*
|
|
* Loads .env itself: this hook runs at dev-server startup, outside
|
|
* SvelteKit's own request/module graph, so `$env/...` isn't available here —
|
|
* see the note in ./tokens.ts for why this whole module tree reads
|
|
* `process.env` directly instead.
|
|
*/
|
|
export function realtimeDevWsPlugin(options: RealtimeDevWsPluginOptions): Plugin {
|
|
return {
|
|
name: 'webavatar-realtime-ws-dev',
|
|
configureServer(server) {
|
|
// vitest's browser-mode project boots its own Vite dev server for
|
|
// component tests; this plugin has nothing to do there. Critically,
|
|
// this guard is also what keeps loadConfig()'s fail-fast validation
|
|
// (below) from running during `npm run test:unit` — that suite's
|
|
// `test.projects` entries both `extends: './vite.config.ts'`, so this
|
|
// plugin's config gets evaluated there too, and unit tests need no env
|
|
// vars set at all. Don't move config resolution above this line.
|
|
if (process.env.VITEST) return;
|
|
|
|
const loaded = loadEnv('development', process.cwd(), '');
|
|
for (const [key, value] of Object.entries(loaded)) {
|
|
if (process.env[key] === undefined) process.env[key] = value;
|
|
}
|
|
|
|
const config = loadConfig();
|
|
const provider = selectProvider(config);
|
|
const recorder = config.analytics.enabled
|
|
? new SqliteAnalyticsRecorder(config.analytics.dbPath, config.analytics)
|
|
: new NoopAnalyticsRecorder();
|
|
const defaults = {
|
|
...resolveSessionDefaults(options.persona, config.session),
|
|
toolRegistry: options.toolRegistry
|
|
};
|
|
|
|
server.httpServer?.on('upgrade', (req, socket, head) => {
|
|
handleRealtimeUpgrade(req, socket, head, {
|
|
provider,
|
|
defaults,
|
|
recorder,
|
|
clientToolTimeoutMs: config.session.clientToolTimeoutMs
|
|
});
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|