(opts: StartUiServerOptions)
| 64 | } |
| 65 | |
| 66 | export async function startUiServer(opts: StartUiServerOptions): Promise<UiServerHandle> { |
| 67 | const { existsSync } = await import('node:fs'); |
| 68 | const { createServer: createHttpServer } = await import('node:http'); |
| 69 | const { resolve } = await import('node:path'); |
| 70 | const { |
| 71 | acquireUiLock, |
| 72 | clearArmedPaneTarget, |
| 73 | createAssetServeMiddleware, |
| 74 | createContentFilter, |
| 75 | readArmedPaneTarget, |
| 76 | readServerLock, |
| 77 | releaseUiLock, |
| 78 | updateUiLockPort, |
| 79 | } = await import('@inkeep/open-knowledge-server'); |
| 80 | const { default: sirv } = await import('sirv'); |
| 81 | const { resolveContentDir, resolveLockDir } = await import('@inkeep/open-knowledge-server'); |
| 82 | |
| 83 | const contentDir = resolveContentDir(opts.config, opts.cwd); |
| 84 | const lockDir = resolveLockDir(opts.cwd); |
| 85 | |
| 86 | acquireUiLock(lockDir, { port: 0, worktreeRoot: opts.cwd }); |
| 87 | |
| 88 | const cliDir = import.meta.dirname ?? new URL('.', import.meta.url).pathname; |
| 89 | const assetPaths = [ |
| 90 | resolve(cliDir, 'public'), // npm install: dist/public/ (bundled) |
| 91 | resolve(cliDir, '../../app/dist'), // monorepo dev from src/ |
| 92 | resolve(cliDir, '../../../app/dist'), // monorepo dev from dist/ |
| 93 | ]; |
| 94 | const assetDir = opts.assetDir ?? assetPaths.find((p) => existsSync(p)); |
| 95 | const staticHandler = assetDir |
| 96 | ? sirv(assetDir, { single: true, gzip: true, etag: true, dev: true, extensions: [] }) |
| 97 | : null; |
| 98 | |
| 99 | const assetServeMiddleware = existsSync(contentDir) |
| 100 | ? createAssetServeMiddleware({ |
| 101 | contentFilter: createContentFilter({ |
| 102 | projectDir: opts.cwd, |
| 103 | contentDir, |
| 104 | }), |
| 105 | contentSirv: sirv(contentDir, { dotfiles: false, dev: true, extensions: [] }), |
| 106 | inlineExtensions: INLINE_RENDERABLE_EXTENSIONS, |
| 107 | assetExtensions: ASSET_EXTENSIONS, |
| 108 | blocklistExtensions: EXECUTABLE_BLOCKLIST_EXTENSIONS, |
| 109 | }) |
| 110 | : null; |
| 111 | |
| 112 | let resolvedPort = opts.port; |
| 113 | |
| 114 | let apiConfigNudge: (() => void) | null = null; |
| 115 | |
| 116 | const requestHandler = (req: import('node:http').IncomingMessage, res: ServerResponse) => { |
| 117 | const url = req.url?.split('?')[0]; |
| 118 | |
| 119 | if (req.method === 'GET' && (url === '/' || url === '')) { |
| 120 | const armed = readArmedPaneTarget(lockDir); |
| 121 | if (armed && !/[\r\n]/.test(armed)) { |
| 122 | clearArmedPaneTarget(lockDir); |
| 123 | res.statusCode = 302; |
no test coverage detected