From 4b52a7d2f84241f99effdaea2327fc15c8076d4e Mon Sep 17 00:00:00 2001 From: digua Date: Thu, 16 Jul 2026 14:49:33 +0800 Subject: [PATCH] refactor(http): organize shared route package --- apps/cli/src/http/auth.test.ts | 2 +- apps/cli/src/http/auth.ts | 21 ++++++ apps/cli/src/http/index.ts | 4 +- apps/cli/src/http/routes/web/helpers.ts | 19 ----- apps/cli/src/http/routes/web/sessions.test.ts | 45 ------------ apps/cli/src/http/server.ts | 2 +- apps/desktop/electron.vite.config.ts | 5 +- apps/desktop/main/internal-api/server.ts | 2 +- packages/http-routes/package.json | 7 +- packages/http-routes/src/ai-config.ts | 1 - packages/http-routes/src/auth.ts | 25 +------ packages/http-routes/src/context.ts | 2 +- packages/http-routes/src/import.ts | 10 --- packages/http-routes/src/index.ts | 69 ------------------- packages/http-routes/src/register.ts | 8 +-- packages/http-routes/src/rest.ts | 13 ---- .../src/routes/{ => rest}/imports.test.ts | 2 +- .../src/routes/{ => rest}/imports.ts | 4 +- packages/http-routes/src/routes/rest/index.ts | 13 ++++ .../session-provider.test.ts} | 2 +- .../session-provider.ts} | 1 + .../src/routes/{ => rest}/sessions.ts | 11 ++- .../src/routes/{ => rest}/system.ts | 2 +- .../src/routes/shared-routes.test.ts | 4 +- .../{ => routes/web}/analytics-cache.test.ts | 4 +- .../src/{ => routes/web}/analytics-cache.ts | 2 +- .../http-routes/src/routes/web/analytics.ts | 4 +- packages/http-routes/src/routes/web/nlp.ts | 2 +- .../{helpers.ts => routes/web/time-filter.ts} | 2 +- packages/node-runtime/package.json | 1 + .../ai/auth-profile-llm-config-store.test.ts | 2 +- .../src/ai/auth-profile-llm-config-store.ts | 2 +- packages/node-runtime/src/ai/index.ts | 2 + packages/node-runtime/src/index.ts | 3 +- pnpm-lock.yaml | 3 + 35 files changed, 84 insertions(+), 217 deletions(-) create mode 100644 apps/cli/src/http/auth.ts delete mode 100644 apps/cli/src/http/routes/web/sessions.test.ts delete mode 100644 packages/http-routes/src/ai-config.ts delete mode 100644 packages/http-routes/src/import.ts delete mode 100644 packages/http-routes/src/rest.ts rename packages/http-routes/src/routes/{ => rest}/imports.test.ts (98%) rename packages/http-routes/src/routes/{ => rest}/imports.ts (91%) create mode 100644 packages/http-routes/src/routes/rest/index.ts rename packages/http-routes/src/routes/{rest-session-provider.test.ts => rest/session-provider.test.ts} (98%) rename packages/http-routes/src/routes/{rest-session-provider.ts => rest/session-provider.ts} (98%) rename packages/http-routes/src/routes/{ => rest}/sessions.ts (96%) rename packages/http-routes/src/routes/{ => rest}/system.ts (98%) rename packages/http-routes/src/{ => routes/web}/analytics-cache.test.ts (96%) rename packages/http-routes/src/{ => routes/web}/analytics-cache.ts (98%) rename packages/http-routes/src/{helpers.ts => routes/web/time-filter.ts} (89%) rename packages/{http-routes => node-runtime}/src/ai/auth-profile-llm-config-store.test.ts (96%) rename packages/{http-routes => node-runtime}/src/ai/auth-profile-llm-config-store.ts (97%) diff --git a/apps/cli/src/http/auth.test.ts b/apps/cli/src/http/auth.test.ts index 94553248..766c7250 100644 --- a/apps/cli/src/http/auth.test.ts +++ b/apps/cli/src/http/auth.test.ts @@ -1,6 +1,6 @@ import { describe, it, beforeEach } from 'node:test' import assert from 'node:assert/strict' -import { setAuthToken, setRequireAuth, authHook } from '@openchatlab/http-routes/auth' +import { setAuthToken, setRequireAuth, authHook } from './auth' function fakeRequest(url: string, authorization?: string) { return { url, headers: { authorization } } as never diff --git a/apps/cli/src/http/auth.ts b/apps/cli/src/http/auth.ts new file mode 100644 index 00000000..4c68f418 --- /dev/null +++ b/apps/cli/src/http/auth.ts @@ -0,0 +1,21 @@ +/** CLI HTTP authentication policy built on the shared Bearer hook. */ + +import { createBearerAuthHook } from '@openchatlab/http-routes/auth' + +let cachedToken: string | null = null +let requireAuthEnabled = false + +export function setAuthToken(token: string): void { + cachedToken = token +} + +/** Require Bearer auth for Web UI routes in headless or remote deployments. */ +export function setRequireAuth(enabled: boolean): void { + requireAuthEnabled = enabled +} + +export const authHook = createBearerAuthHook({ + getToken: () => cachedToken, + shouldAuthenticate: (request) => + request.url.startsWith('/api/') || (requireAuthEnabled && request.url.startsWith('/_web/')), +}) diff --git a/apps/cli/src/http/index.ts b/apps/cli/src/http/index.ts index e3ba6b8e..8349df94 100644 --- a/apps/cli/src/http/index.ts +++ b/apps/cli/src/http/index.ts @@ -17,6 +17,7 @@ import { CustomProviderStore, CustomModelStore, createFileConfigStorage, + createAuthProfileLlmConfigStore, applyPendingNodeDataDirMigrationIfNeeded, hasPendingElectronDataWarning, verifyCliDataPath, @@ -27,8 +28,7 @@ import { } from '@openchatlab/node-runtime' import type { SemanticIndexRuntime } from '@openchatlab/node-runtime' import { createServer } from './server' -import { setAuthToken, setRequireAuth } from '@openchatlab/http-routes/auth' -import { createAuthProfileLlmConfigStore } from '@openchatlab/http-routes/ai-config' +import { setAuthToken, setRequireAuth } from './auth' import { registerWebRoutes } from './routes/web' import { registerProxyRoutes } from './routes/proxy' import { initServerAiLogger, closeServerAiLogger } from '../ai/logger' diff --git a/apps/cli/src/http/routes/web/helpers.ts b/apps/cli/src/http/routes/web/helpers.ts index 5c97832a..471f613a 100644 --- a/apps/cli/src/http/routes/web/helpers.ts +++ b/apps/cli/src/http/routes/web/helpers.ts @@ -3,20 +3,9 @@ */ import * as fs from 'fs' -import type { TimeFilter } from '@openchatlab/shared-types' import type { DatabaseManager } from '@openchatlab/node-runtime' import { resolveCliPath } from '../../../paths' -export function parseTimeFilter(query: Record): TimeFilter | undefined { - const { startTs, endTs, memberId } = query - if (!startTs && !endTs && !memberId) return undefined - const filter: TimeFilter = {} - if (startTs) filter.startTs = parseInt(startTs, 10) - if (endTs) filter.endTs = parseInt(endTs, 10) - if (memberId) filter.memberId = parseInt(memberId, 10) - return filter -} - export function resolveNativeBinding(): string | undefined { if (process.versions.electron) return undefined const nativePath = resolveCliPath('native/better_sqlite3.node') @@ -31,11 +20,3 @@ export function getAiDataDir(dbManager: DatabaseManager): string { } return pathProvider.getAiDataDir() } - -export function ensureDb(dbManager: DatabaseManager, sessionId: string) { - const db = dbManager.open(sessionId) - if (!db) { - throw Object.assign(new Error(`Session not found: ${sessionId}`), { statusCode: 404 }) - } - return db -} diff --git a/apps/cli/src/http/routes/web/sessions.test.ts b/apps/cli/src/http/routes/web/sessions.test.ts deleted file mode 100644 index c262cc4a..00000000 --- a/apps/cli/src/http/routes/web/sessions.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { describe, it } from 'node:test' -import assert from 'node:assert/strict' -import Fastify from 'fastify' -import type { SessionRuntimeAdapter } from '@openchatlab/node-runtime' -import type { HttpRouteContext } from '@openchatlab/http-routes' -import { registerSessionRoutes } from '@openchatlab/http-routes' - -function createMissingSessionAdapter(): SessionRuntimeAdapter { - return { - listSessionIds: () => [], - openReadonly: () => null, - openWritable: () => null, - closeSession: () => {}, - getDbPath: (sessionId) => `/tmp/${sessionId}.db`, - deleteSessionFile: () => false, - ensureReadonly: () => { - throw Object.assign(new Error('Session not found'), { statusCode: 404 }) - }, - ensureWritable: () => { - throw Object.assign(new Error('Session not found'), { statusCode: 404 }) - }, - } -} - -function createMockContext(adapter: SessionRuntimeAdapter): HttpRouteContext { - return { - dbManager: {} as any, - sessionAdapter: adapter, - pathProvider: {} as any, - getVersion: () => '0.0.0-test', - } -} - -describe('shared session routes', () => { - it('returns 404 when requesting a missing session by id', async () => { - const app = Fastify() - const ctx = createMockContext(createMissingSessionAdapter()) - registerSessionRoutes(app, ctx) - - const response = await app.inject({ method: 'GET', url: '/_web/sessions/missing' }) - await app.close() - - assert.equal(response.statusCode, 404) - }) -}) diff --git a/apps/cli/src/http/server.ts b/apps/cli/src/http/server.ts index 8cd8194e..32ba3063 100644 --- a/apps/cli/src/http/server.ts +++ b/apps/cli/src/http/server.ts @@ -5,9 +5,9 @@ */ import type { FastifyInstance } from 'fastify' -import { authHook } from '@openchatlab/http-routes/auth' import { createApiServer } from '@openchatlab/http-routes/server' import { appLogger } from '@openchatlab/node-runtime' +import { authHook } from './auth' export function createServer(): FastifyInstance { return createApiServer({ diff --git a/apps/desktop/electron.vite.config.ts b/apps/desktop/electron.vite.config.ts index 356bc51a..0c9bca87 100644 --- a/apps/desktop/electron.vite.config.ts +++ b/apps/desktop/electron.vite.config.ts @@ -8,11 +8,10 @@ const rootDir = resolve(__dirname, '../..') const rootPkg = JSON.parse(readFileSync(resolve(rootDir, 'package.json'), 'utf-8')) const appVersion: string = rootPkg.version const openChatLabAliases = { - '@openchatlab/http-routes/ai-config': resolve(rootDir, 'packages/http-routes/src/ai-config.ts'), '@openchatlab/http-routes/auth': resolve(rootDir, 'packages/http-routes/src/auth.ts'), '@openchatlab/http-routes/errors': resolve(rootDir, 'packages/http-routes/src/errors.ts'), - '@openchatlab/http-routes/import': resolve(rootDir, 'packages/http-routes/src/import.ts'), - '@openchatlab/http-routes/rest': resolve(rootDir, 'packages/http-routes/src/rest.ts'), + '@openchatlab/http-routes/import': resolve(rootDir, 'packages/http-routes/src/import/json-push-handler.ts'), + '@openchatlab/http-routes/rest': resolve(rootDir, 'packages/http-routes/src/routes/rest/index.ts'), '@openchatlab/http-routes/server': resolve(rootDir, 'packages/http-routes/src/server.ts'), '@openchatlab/node-runtime/import/archive/source-manager': resolve( rootDir, diff --git a/apps/desktop/main/internal-api/server.ts b/apps/desktop/main/internal-api/server.ts index 925f8f32..151a3735 100644 --- a/apps/desktop/main/internal-api/server.ts +++ b/apps/desktop/main/internal-api/server.ts @@ -19,6 +19,7 @@ import { CustomProviderStore, CustomModelStore, createFileConfigStorage, + createAuthProfileLlmConfigStore, MergeSessionCache, withDataDirImportLock, raiseChatDbCompatibilityGate, @@ -30,7 +31,6 @@ import type { StreamImportDeps, SemanticIndexRuntime } from '@openchatlab/node-r import { getLoadablePath as getSqliteVecLoadablePath } from 'sqlite-vec' import multipart from '@fastify/multipart' import { registerSharedRoutes, registerAutomationRoutes } from '@openchatlab/http-routes' -import { createAuthProfileLlmConfigStore } from '@openchatlab/http-routes/ai-config' import { createApiServer } from '@openchatlab/http-routes/server' import type { HttpRouteContext } from '@openchatlab/http-routes' import { reloadTimer, stopTimer, type DataSourceManager, type PullEngine } from '@openchatlab/sync' diff --git a/packages/http-routes/package.json b/packages/http-routes/package.json index 51fe17da..95622828 100644 --- a/packages/http-routes/package.json +++ b/packages/http-routes/package.json @@ -2,17 +2,16 @@ "name": "@openchatlab/http-routes", "version": "0.0.0", "private": true, - "description": "ChatLab shared HTTP API routes — consumed by CLI Server and Electron Internal Server", + "description": "ChatLab shared HTTP routes and infrastructure for CLI and Electron servers", "type": "module", "main": "./src/index.ts", "types": "./src/index.ts", "exports": { ".": "./src/index.ts", - "./ai-config": "./src/ai-config.ts", "./auth": "./src/auth.ts", "./errors": "./src/errors.ts", - "./import": "./src/import.ts", - "./rest": "./src/rest.ts", + "./import": "./src/import/json-push-handler.ts", + "./rest": "./src/routes/rest/index.ts", "./server": "./src/server.ts" }, "dependencies": { diff --git a/packages/http-routes/src/ai-config.ts b/packages/http-routes/src/ai-config.ts deleted file mode 100644 index 2cec797f..00000000 --- a/packages/http-routes/src/ai-config.ts +++ /dev/null @@ -1 +0,0 @@ -export { createAuthProfileLlmConfigStore, type AuthProfileLlmConfigStoreDeps } from './ai/auth-profile-llm-config-store' diff --git a/packages/http-routes/src/auth.ts b/packages/http-routes/src/auth.ts index edaae653..d9d52370 100644 --- a/packages/http-routes/src/auth.ts +++ b/packages/http-routes/src/auth.ts @@ -1,18 +1,13 @@ /** * ChatLab HTTP API — Bearer Token authentication hook * - * Shared auth middleware for CLI Server and Electron APIs. - * URL classification: /api/* always requires token, /_web/* conditionally, - * static files and SPA fallback are public. + * Shared auth middleware factory for CLI and Electron APIs. */ import type { FastifyRequest, FastifyReply } from 'fastify' import { timingSafeEqual, createHmac, randomBytes } from 'crypto' import { unauthorized, errorResponse } from './errors' -let cachedToken: string | null = null -let requireAuthEnabled = false - export interface BearerAuthOptions { getToken: () => string | null | undefined shouldAuthenticate?: (request: FastifyRequest) => boolean @@ -21,18 +16,6 @@ export interface BearerAuthOptions { invalidTokenMessage?: string } -export function setAuthToken(token: string): void { - cachedToken = token -} - -/** - * When enabled, /_web/* routes also require Bearer token (same as /api/*). - * Used for server/headless deployments where same-origin assumption doesn't hold. - */ -export function setRequireAuth(enabled: boolean): void { - requireAuthEnabled = enabled -} - export function createBearerAuthHook(options: BearerAuthOptions) { // Compare via HMAC digests (fixed 32-byte length) to avoid leaking token length. const hmacKey = randomBytes(32) @@ -62,9 +45,3 @@ export function createBearerAuthHook(options: BearerAuthOptions) { } } } - -export const authHook = createBearerAuthHook({ - getToken: () => cachedToken, - shouldAuthenticate: (request) => - request.url.startsWith('/api/') || (requireAuthEnabled && request.url.startsWith('/_web/')), -}) diff --git a/packages/http-routes/src/context.ts b/packages/http-routes/src/context.ts index 75036aae..c6528d95 100644 --- a/packages/http-routes/src/context.ts +++ b/packages/http-routes/src/context.ts @@ -30,7 +30,7 @@ import type { GlobalInsightService, } from '@openchatlab/node-runtime' import type { RuntimeIdentity } from '@openchatlab/node-runtime' -import type { RestSessionProvider } from './routes/rest-session-provider' +import type { RestSessionProvider } from './routes/rest/session-provider' export interface HttpRouteContext { dbManager: DatabaseManager diff --git a/packages/http-routes/src/import.ts b/packages/http-routes/src/import.ts deleted file mode 100644 index e80fcfe2..00000000 --- a/packages/http-routes/src/import.ts +++ /dev/null @@ -1,10 +0,0 @@ -export { registerImportRoutes } from './routes/imports' -export { - buildImportIdempotencyCacheKey, - createJsonPushImportHandler, - type ImportSuccessResponse, - type JsonPushImportHandler, - type JsonPushImportHandlerOptions, - type JsonPushImportHttpResult, - type JsonPushImportRequest, -} from './import/json-push-handler' diff --git a/packages/http-routes/src/index.ts b/packages/http-routes/src/index.ts index b8dede8f..ca39f684 100644 --- a/packages/http-routes/src/index.ts +++ b/packages/http-routes/src/index.ts @@ -8,75 +8,6 @@ export type { } from './context' export { registerSharedRoutes } from './register' export type { SharedRouteOptions } from './register' -export { setAuthToken, setRequireAuth, authHook } from './auth' -export { - ApiError, - ApiErrorCode, - unauthorized, - sessionNotFound, - invalidFormat, - invalidPayload, - sqlReadonlyViolation, - sqlExecutionError, - exportTooLarge, - serverError, - importInProgress, - idempotencyConflict, - idempotencyPending, - importFailed, - dataDirIncompatible, - apiErrorFromUnknown, - successResponse, - errorResponse, -} from './errors' -export { parseTimeFilter } from './helpers' -export { createApiServer, configureApiErrorHandler, DEFAULT_JSON_BODY_LIMIT } from './server' -export type { ApiServerOptions } from './server' -export { - buildImportIdempotencyCacheKey, - createJsonPushImportHandler, - type ImportSuccessResponse, - type JsonPushImportHandler, - type JsonPushImportHandlerOptions, - type JsonPushImportHttpResult, - type JsonPushImportRequest, -} from './import/json-push-handler' -export { buildAnalyticsCacheKey, withAnalyticsCache } from './analytics-cache' export { executeRegistryTool } from './ai/tool-executor' export type { AiToolExecutionDeps } from './ai/tool-executor' -export { createAuthProfileLlmConfigStore } from './ai/auth-profile-llm-config-store' -export type { AuthProfileLlmConfigStoreDeps } from './ai/auth-profile-llm-config-store' - -// Individual route registration for granular testing or selective registration -export { registerSystemRoutes } from './routes/system' -export type { SystemRouteContext } from './routes/system' -export { registerRestSessionRoutes } from './routes/sessions' -export { createDatabaseRestSessionProvider } from './routes/rest-session-provider' -export type { - RestMessageQuery, - RestMessagePage, - RestSessionDetail, - RestSessionExportData, - RestSessionOverview, - RestSessionProvider, - RestSessionSummary, -} from './routes/rest-session-provider' -export { registerSessionRoutes } from './routes/web/sessions' -export { registerMemberRoutes } from './routes/web/members' -export { registerPreferencesRoutes } from './routes/web/preferences' -export { registerAnalyticsRoutes } from './routes/web/analytics' -export { registerSqlRoutes } from './routes/web/sql' -export { registerSessionIndexRoutes } from './routes/web/session-index' -export { registerExportRoutes } from './routes/web/export' -export { registerNlpRoutes } from './routes/web/nlp' -export { registerAiAssistantRoutes } from './routes/web/ai-assistants' -export { registerAiSkillRoutes } from './routes/web/ai-skills' -export { registerAiLlmRoutes } from './routes/web/ai-llm' -export { registerAiChatRoutes } from './routes/web/ai-chats' -export { registerAiSummaryRoutes } from './routes/web/ai-summaries' -export { registerAiLlmStreamRoutes } from './routes/web/ai-llm-stream' -export { registerAiAgentStreamRoutes } from './routes/web/ai-agent-stream' -export { registerAiToolRoutes } from './routes/web/ai-tools' -export { registerTelemetryRoutes } from './routes/web/telemetry' export { registerAutomationRoutes } from './routes/web/automation' -export { registerGlobalInsightRoutes } from './routes/web/global-insight' diff --git a/packages/http-routes/src/register.ts b/packages/http-routes/src/register.ts index 255867e4..2394f2bf 100644 --- a/packages/http-routes/src/register.ts +++ b/packages/http-routes/src/register.ts @@ -8,10 +8,10 @@ import type { FastifyInstance } from 'fastify' import type { HttpRouteContext } from './context' import { PreferencesManager } from '@openchatlab/node-runtime' -import { registerSystemRoutes } from './routes/system' -import { registerRestSessionRoutes } from './routes/sessions' -import { createDatabaseRestSessionProvider } from './routes/rest-session-provider' -import { registerImportRoutes } from './routes/imports' +import { registerSystemRoutes } from './routes/rest/system' +import { registerRestSessionRoutes } from './routes/rest/sessions' +import { createDatabaseRestSessionProvider } from './routes/rest/session-provider' +import { registerImportRoutes } from './routes/rest/imports' import { registerSessionRoutes } from './routes/web/sessions' import { registerMemberRoutes } from './routes/web/members' import { registerContactsRoutes } from './routes/web/contacts' diff --git a/packages/http-routes/src/rest.ts b/packages/http-routes/src/rest.ts deleted file mode 100644 index ef27159e..00000000 --- a/packages/http-routes/src/rest.ts +++ /dev/null @@ -1,13 +0,0 @@ -export type { - RestMessageQuery, - RestMessagePage, - RestSessionDetail, - RestSessionExportData, - RestSessionOverview, - RestSessionProvider, - RestSessionSummary, -} from './routes/rest-session-provider' -export { createDatabaseRestSessionProvider } from './routes/rest-session-provider' -export { registerSystemRoutes } from './routes/system' -export type { SystemRouteContext } from './routes/system' -export { registerRestSessionRoutes } from './routes/sessions' diff --git a/packages/http-routes/src/routes/imports.test.ts b/packages/http-routes/src/routes/rest/imports.test.ts similarity index 98% rename from packages/http-routes/src/routes/imports.test.ts rename to packages/http-routes/src/routes/rest/imports.test.ts index 7d85b7f9..b02be48d 100644 --- a/packages/http-routes/src/routes/imports.test.ts +++ b/packages/http-routes/src/routes/rest/imports.test.ts @@ -6,7 +6,7 @@ import test from 'node:test' import Fastify from 'fastify' import type { PathProvider } from '@openchatlab/core' import { DatabaseManager } from '@openchatlab/node-runtime' -import type { HttpRouteContext } from '../context' +import type { HttpRouteContext } from '../../context' import { registerImportRoutes } from './imports' const nativeBinding = path.resolve('apps/cli/native/better_sqlite3.node') diff --git a/packages/http-routes/src/routes/imports.ts b/packages/http-routes/src/routes/rest/imports.ts similarity index 91% rename from packages/http-routes/src/routes/imports.ts rename to packages/http-routes/src/routes/rest/imports.ts index 4d2b4769..3bcec466 100644 --- a/packages/http-routes/src/routes/imports.ts +++ b/packages/http-routes/src/routes/rest/imports.ts @@ -7,10 +7,10 @@ */ import type { FastifyInstance } from 'fastify' -import type { HttpRouteContext } from '../context' +import type { HttpRouteContext } from '../../context' import { appLogger, pushImport } from '@openchatlab/node-runtime' import type { PushImportPayload } from '@openchatlab/node-runtime' -import { createJsonPushImportHandler } from '../import/json-push-handler' +import { createJsonPushImportHandler } from '../../import/json-push-handler' export function registerImportRoutes(server: FastifyInstance, ctx: HttpRouteContext): void { const handleJsonPushImport = createJsonPushImportHandler({ diff --git a/packages/http-routes/src/routes/rest/index.ts b/packages/http-routes/src/routes/rest/index.ts new file mode 100644 index 00000000..7c85763d --- /dev/null +++ b/packages/http-routes/src/routes/rest/index.ts @@ -0,0 +1,13 @@ +export type { + RestMessageQuery, + RestMessagePage, + RestSessionDetail, + RestSessionExportData, + RestSessionOverview, + RestSessionProvider, + RestSessionSummary, +} from './session-provider' +export { createDatabaseRestSessionProvider } from './session-provider' +export { registerSystemRoutes } from './system' +export type { SystemRouteContext } from './system' +export { registerRestSessionRoutes } from './sessions' diff --git a/packages/http-routes/src/routes/rest-session-provider.test.ts b/packages/http-routes/src/routes/rest/session-provider.test.ts similarity index 98% rename from packages/http-routes/src/routes/rest-session-provider.test.ts rename to packages/http-routes/src/routes/rest/session-provider.test.ts index 5fbcca82..a0e27ed1 100644 --- a/packages/http-routes/src/routes/rest-session-provider.test.ts +++ b/packages/http-routes/src/routes/rest/session-provider.test.ts @@ -1,7 +1,7 @@ import assert from 'node:assert/strict' import test from 'node:test' import Fastify from 'fastify' -import type { RestSessionProvider } from './rest-session-provider' +import type { RestSessionProvider } from './session-provider' import { registerRestSessionRoutes } from './sessions' import { registerSystemRoutes } from './system' diff --git a/packages/http-routes/src/routes/rest-session-provider.ts b/packages/http-routes/src/routes/rest/session-provider.ts similarity index 98% rename from packages/http-routes/src/routes/rest-session-provider.ts rename to packages/http-routes/src/routes/rest/session-provider.ts index adc2c5fd..c33e6d39 100644 --- a/packages/http-routes/src/routes/rest-session-provider.ts +++ b/packages/http-routes/src/routes/rest/session-provider.ts @@ -1,3 +1,4 @@ +/** Data access contract for the public REST session routes. */ import { executeReadonlySql, getLastPlatformMessageId, diff --git a/packages/http-routes/src/routes/sessions.ts b/packages/http-routes/src/routes/rest/sessions.ts similarity index 96% rename from packages/http-routes/src/routes/sessions.ts rename to packages/http-routes/src/routes/rest/sessions.ts index a3dee6a6..2565d0c0 100644 --- a/packages/http-routes/src/routes/sessions.ts +++ b/packages/http-routes/src/routes/rest/sessions.ts @@ -6,8 +6,15 @@ */ import type { FastifyInstance } from 'fastify' -import { successResponse, errorResponse, sessionNotFound, exportTooLarge, sqlExecutionError, ApiError } from '../errors' -import type { RestSessionProvider } from './rest-session-provider' +import { + successResponse, + errorResponse, + sessionNotFound, + exportTooLarge, + sqlExecutionError, + ApiError, +} from '../../errors' +import type { RestSessionProvider } from './session-provider' const EXPORT_MESSAGE_LIMIT = 100_000 diff --git a/packages/http-routes/src/routes/system.ts b/packages/http-routes/src/routes/rest/system.ts similarity index 98% rename from packages/http-routes/src/routes/system.ts rename to packages/http-routes/src/routes/rest/system.ts index 92bfbca2..229ae205 100644 --- a/packages/http-routes/src/routes/system.ts +++ b/packages/http-routes/src/routes/rest/system.ts @@ -6,7 +6,7 @@ */ import type { FastifyInstance } from 'fastify' -import { successResponse } from '../errors' +import { successResponse } from '../../errors' export interface SystemRouteContext { getVersion: () => string diff --git a/packages/http-routes/src/routes/shared-routes.test.ts b/packages/http-routes/src/routes/shared-routes.test.ts index 140695f3..9ff6348d 100644 --- a/packages/http-routes/src/routes/shared-routes.test.ts +++ b/packages/http-routes/src/routes/shared-routes.test.ts @@ -16,8 +16,8 @@ import type { DatabaseAdapter, PathProvider, PreparedStatement, RunResult } from import { PreferencesManager, type DatabaseManager, type SessionRuntimeAdapter } from '@openchatlab/node-runtime' import type { HttpRouteContext } from '../context' import { registerSharedRoutes } from '../register' -import { registerRestSessionRoutes } from './sessions' -import { createDatabaseRestSessionProvider } from './rest-session-provider' +import { registerRestSessionRoutes } from './rest/sessions' +import { createDatabaseRestSessionProvider } from './rest/session-provider' import { registerAutomationRoutes } from './web/automation' import { registerSessionRoutes } from './web/sessions' diff --git a/packages/http-routes/src/analytics-cache.test.ts b/packages/http-routes/src/routes/web/analytics-cache.test.ts similarity index 96% rename from packages/http-routes/src/analytics-cache.test.ts rename to packages/http-routes/src/routes/web/analytics-cache.test.ts index 826ad7d1..1be4d45f 100644 --- a/packages/http-routes/src/analytics-cache.test.ts +++ b/packages/http-routes/src/routes/web/analytics-cache.test.ts @@ -1,7 +1,7 @@ /** * buildAnalyticsCacheKey tests. * - * 运行:node --import tsx --test packages/http-routes/src/analytics-cache.test.ts + * Run: pnpm test -- packages/http-routes/src/routes/web/analytics-cache.test.ts * * 键的确定性直接决定缓存命中率与正确性:等价请求必须同键,不同请求必须异键。 */ @@ -12,7 +12,7 @@ import fs from 'node:fs' import os from 'node:os' import path from 'node:path' import { buildAnalyticsCacheKey, withAnalyticsCache } from './analytics-cache' -import type { HttpRouteContext } from './context' +import type { HttpRouteContext } from '../../context' describe('buildAnalyticsCacheKey', () => { it('is independent of param key order', () => { diff --git a/packages/http-routes/src/analytics-cache.ts b/packages/http-routes/src/routes/web/analytics-cache.ts similarity index 98% rename from packages/http-routes/src/analytics-cache.ts rename to packages/http-routes/src/routes/web/analytics-cache.ts index 4200774e..e5744385 100644 --- a/packages/http-routes/src/analytics-cache.ts +++ b/packages/http-routes/src/routes/web/analytics-cache.ts @@ -11,7 +11,7 @@ import * as path from 'path' import { getDbFileVersion, getOrComputeAnalysisCache } from '@openchatlab/node-runtime' -import type { HttpRouteContext } from './context' +import type { HttpRouteContext } from '../../context' /** Deterministic stringify: sorts object keys recursively and drops `undefined`. */ function canonical(value: unknown): string { diff --git a/packages/http-routes/src/routes/web/analytics.ts b/packages/http-routes/src/routes/web/analytics.ts index 349c1ee4..faa8bc84 100644 --- a/packages/http-routes/src/routes/web/analytics.ts +++ b/packages/http-routes/src/routes/web/analytics.ts @@ -33,8 +33,8 @@ import { getRepeatAnalysis, } from '@openchatlab/core' import type { ClusterGraphOptions } from '@openchatlab/core' -import { parseTimeFilter } from '../../helpers' -import { withAnalyticsCache } from '../../analytics-cache' +import { parseTimeFilter } from './time-filter' +import { withAnalyticsCache } from './analytics-cache' type FilteredQuery = { startTs?: string; endTs?: string; memberId?: string } diff --git a/packages/http-routes/src/routes/web/nlp.ts b/packages/http-routes/src/routes/web/nlp.ts index 0be0b87f..486770b1 100644 --- a/packages/http-routes/src/routes/web/nlp.ts +++ b/packages/http-routes/src/routes/web/nlp.ts @@ -9,7 +9,7 @@ import * as fs from 'fs' import * as path from 'path' import type { FastifyInstance } from 'fastify' import type { HttpRouteContext } from '../../context' -import { withAnalyticsCache } from '../../analytics-cache' +import { withAnalyticsCache } from './analytics-cache' import type { WordFrequencyParams, SupportedLocale } from '@openchatlab/core' import { POS_TAG_DEFINITIONS } from '@openchatlab/core' import { diff --git a/packages/http-routes/src/helpers.ts b/packages/http-routes/src/routes/web/time-filter.ts similarity index 89% rename from packages/http-routes/src/helpers.ts rename to packages/http-routes/src/routes/web/time-filter.ts index 44c2ffd8..b1a98432 100644 --- a/packages/http-routes/src/helpers.ts +++ b/packages/http-routes/src/routes/web/time-filter.ts @@ -1,5 +1,5 @@ /** - * Shared helpers for route modules. + * Time-filter query parsing for Web analytics routes. */ import type { TimeFilter } from '@openchatlab/shared-types' diff --git a/packages/node-runtime/package.json b/packages/node-runtime/package.json index 48eeb901..bcac2908 100644 --- a/packages/node-runtime/package.json +++ b/packages/node-runtime/package.json @@ -17,6 +17,7 @@ "@earendil-works/pi-agent-core": "0.74.2", "@earendil-works/pi-ai": "0.74.2", "@huggingface/transformers": "^4.2.0", + "@openchatlab/config": "workspace:*", "@openchatlab/core": "workspace:*", "better-sqlite3": "^12.4.6", "gray-matter": "^4.0.3", diff --git a/packages/http-routes/src/ai/auth-profile-llm-config-store.test.ts b/packages/node-runtime/src/ai/auth-profile-llm-config-store.test.ts similarity index 96% rename from packages/http-routes/src/ai/auth-profile-llm-config-store.test.ts rename to packages/node-runtime/src/ai/auth-profile-llm-config-store.test.ts index b9d20007..f01d3472 100644 --- a/packages/http-routes/src/ai/auth-profile-llm-config-store.test.ts +++ b/packages/node-runtime/src/ai/auth-profile-llm-config-store.test.ts @@ -1,6 +1,6 @@ import assert from 'node:assert/strict' import test from 'node:test' -import type { ConfigStorage } from '@openchatlab/node-runtime' +import type { ConfigStorage } from './llm-config-store' import { createAuthProfileLlmConfigStore } from './auth-profile-llm-config-store' function createMemoryStorage(): ConfigStorage & { data: Map } { diff --git a/packages/http-routes/src/ai/auth-profile-llm-config-store.ts b/packages/node-runtime/src/ai/auth-profile-llm-config-store.ts similarity index 97% rename from packages/http-routes/src/ai/auth-profile-llm-config-store.ts rename to packages/node-runtime/src/ai/auth-profile-llm-config-store.ts index 5e817cf3..855fe336 100644 --- a/packages/http-routes/src/ai/auth-profile-llm-config-store.ts +++ b/packages/node-runtime/src/ai/auth-profile-llm-config-store.ts @@ -1,5 +1,5 @@ import { deleteAuthProfile, resolveApiKey, writeAuthProfile, type AuthProfile } from '@openchatlab/config' -import { LLMConfigStore, type AIServiceConfig, type ConfigStorage } from '@openchatlab/node-runtime' +import { LLMConfigStore, type AIServiceConfig, type ConfigStorage } from './llm-config-store' export interface AuthProfileLlmConfigStoreDeps { resolveApiKey: (provider: string, authProfile?: string) => string | undefined diff --git a/packages/node-runtime/src/ai/index.ts b/packages/node-runtime/src/ai/index.ts index 92ebe0f5..d7d58bb5 100644 --- a/packages/node-runtime/src/ai/index.ts +++ b/packages/node-runtime/src/ai/index.ts @@ -164,6 +164,8 @@ export type { SummaryDeps, SummaryMessage, SummaryOptions, SummaryResult, Summar export { LLMConfigStore, MAX_CONFIG_COUNT } from './llm-config-store' export type { AIServiceConfig, AIConfigStore, ConfigStorage, LLMConfigStoreDeps } from './llm-config-store' export { createFileConfigStorage } from './file-config-storage' +export { createAuthProfileLlmConfigStore } from './auth-profile-llm-config-store' +export type { AuthProfileLlmConfigStoreDeps } from './auth-profile-llm-config-store' // Custom Provider/Model Store export { CustomProviderStore, CustomModelStore } from './custom-store' diff --git a/packages/node-runtime/src/index.ts b/packages/node-runtime/src/index.ts index 8da1ad40..328c2e11 100644 --- a/packages/node-runtime/src/index.ts +++ b/packages/node-runtime/src/index.ts @@ -157,7 +157,8 @@ export type { AssistantConfig, AssistantSummary, SkillDef, SkillSummary } from ' export { parseAssistantFile, serializeAssistant, parseSkillFile, extractSkillId } from './ai' export { AIChatManager } from './ai' export { countTokens, countMessagesTokens, initTokenizer } from './ai' -export { createFileConfigStorage } from './ai' +export { createFileConfigStorage, createAuthProfileLlmConfigStore } from './ai' +export type { AuthProfileLlmConfigStoreDeps } from './ai' // Assistant Manager export { AssistantManager } from './ai' diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b6e3cc62..95fd52d7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -331,6 +331,9 @@ importers: '@huggingface/transformers': specifier: ^4.2.0 version: 4.2.0 + '@openchatlab/config': + specifier: workspace:* + version: link:../config '@openchatlab/core': specifier: workspace:* version: link:../core