import path from 'node:path'; import { createDbPool, isDatabaseConfigured } from './db.mjs'; import { projectRoot } from './load-env.mjs'; import { importMemind, resolveMemindLib } from './lib-path.mjs'; import { createSystemTestAccountService, ensureSystemTestAccountSchema } from './system-test-accounts.mjs'; export async function bootstrapAdminServices() { if (!isDatabaseConfigured()) { throw new Error('数据库未配置'); } const memindLib = resolveMemindLib(); const h5Root = process.env.MEMIND_LIB_ROOT?.trim() ?? path.join(projectRoot, '../Memind'); const pool = createDbPool(); const { loadCreateLlmProviderService } = await import('./llm-provider-loader.mjs'); const createLlmProviderService = await loadCreateLlmProviderService(); const { createWechatAdminService } = await importMemind('wechat-admin.mjs'); const { createWechatMpService, loadWechatMpConfig } = await importMemind('wechat-mp.mjs'); const { createNotificationDispatcher } = await importMemind('notification-dispatcher.mjs'); const { createPlazaPostService, formatPostRow } = await importMemind('plaza-posts.mjs'); const { createPlazaInteractionService } = await importMemind('plaza-interactions.mjs'); const { createPlazaOpsService } = await importMemind('plaza-ops.mjs'); const { createNoopPlazaRedis } = await importMemind('plaza-redis.mjs'); const { ensureAlgorithmConfig, loadAlgorithmConfig } = await importMemind('plaza-algorithm.mjs'); const { ensureMindSpaceConfig, loadMindSpaceConfig, updateMindSpaceConfig, } = await importMemind('mindspace-config.mjs'); const { createMemoryV2AdminConfigService } = await importMemind('memory-v2-admin-config.mjs'); const { createMindSearchConfigService } = await importMemind('mindsearch-config.mjs'); const { createOrchestratorAdminConfigService } = await importMemind( 'services/orchestrator/admin-config.mjs', ); const { createOrchestratorObservabilityService } = await importMemind( 'services/orchestrator/observability.mjs', ); const { createPersonalMemoryCandidateStore } = await importMemind('memory-v2-personal-store.mjs'); const { createSkillRuntimeAdminConfigService } = await importMemind('skill-runtime-admin-config.mjs'); const { createAssetGatewayConfigService } = await importMemind('asset-gateway.mjs'); const { ensureAssetGatewaySchema } = await importMemind('db.mjs'); const { createWechatScheduleLlmConfigService } = await importMemind('wechat-schedule-llm-config.mjs'); const { createAdminSystemTestService } = await importMemind('admin-system-tests.mjs'); const { createOpsApi } = await importMemind('admin-routes.mjs'); const { createWordFilterService, ensureWordFilterSchema } = await importMemind('word-filter.mjs'); const { USER_COOKIE, clearUserSessionCookie, createUserAuth, resolveCookieDomainForRequest, userLoginCookies, } = await importMemind('user-auth.mjs'); const { ensurePlanCatalogSchema, createPlanCatalogService, createSubscriptionService, } = await importMemind('billing-subscription.mjs'); const usersRoot = process.env.H5_USERS_ROOT?.trim() ?? path.join(projectRoot, 'data', 'users'); const apiTarget = process.env.TKMIND_API_TARGET ?? 'https://127.0.0.1:18006'; const apiSecret = process.env.TKMIND_SERVER__SECRET_KEY ?? 'local-dev-secret'; const plazaRedis = createNoopPlazaRedis(); await ensureAlgorithmConfig(pool); const algorithmConfig = await loadAlgorithmConfig(pool); await ensureMindSpaceConfig(pool, { env: process.env, seedDefault: false }); const mindSpaceConfig = await loadMindSpaceConfig(pool, { env: process.env }); const plazaInteractions = createPlazaInteractionService(pool, { formatPostRow, plazaRedis }); let plazaOps = null; const plazaPosts = createPlazaPostService(pool, { loadViewerReactions: (viewerId, postIds) => plazaInteractions.loadViewerReactions(viewerId, postIds), plazaRedis, algorithmConfig, onPostPublished: () => {}, loadFeaturedPosts: async (viewerId) => { if (!plazaOps) return { homepage_banner: [], trending: [], category_top: {} }; return plazaOps.loadActiveFeaturedPosts(viewerId); }, }); plazaOps = createPlazaOpsService(pool, { formatPostRow, reviewPost: (...args) => plazaPosts.reviewPost(...args), invalidateFeedCaches: () => plazaRedis?.invalidateFeedCaches?.(), }); const userAuth = createUserAuth(pool, { usersRoot, h5Root, defaultSignupBalanceCents: Number(process.env.H5_SIGNUP_BALANCE_CENTS ?? 500), }); const llmProviderService = createLlmProviderService(pool, { apiTarget, apiSecret, }); await ensureAssetGatewaySchema(pool); const assetGatewayConfigService = createAssetGatewayConfigService(pool, { llmProviderService }); const memoryV2ConfigService = createMemoryV2AdminConfigService(pool, { env: process.env, }); const mindSearchConfigService = createMindSearchConfigService(pool, { env: process.env }); await mindSearchConfigService.ensureSchema(); const orchestratorConfigService = createOrchestratorAdminConfigService(pool, { env: process.env, }); await orchestratorConfigService.ensureSchema(); const orchestratorObservabilityService = createOrchestratorObservabilityService({ pool, configService: orchestratorConfigService, }); const personalMemoryCandidateStore = createPersonalMemoryCandidateStore(pool); const skillRuntimeConfigService = createSkillRuntimeAdminConfigService(pool, { env: process.env, h5Root, }); const wechatScheduleLlmConfigService = createWechatScheduleLlmConfigService(pool, { env: process.env, }); const adminSystemTestService = createAdminSystemTestService({ pool, userAuth, portalBaseUrl: `http://127.0.0.1:${process.env.H5_PORT ?? 8081}`, }); const wechatMpConfig = loadWechatMpConfig(); const wechatMpService = createWechatMpService({ config: wechatMpConfig, userAuth, apiFetch: async () => { throw new Error('admin api does not proxy WeChat chat sessions'); }, }); const notificationDispatcher = createNotificationDispatcher({ sendWechatTextToUser: wechatMpService?.enabled ? (userId, text) => wechatMpService.sendTextToUser(userId, text) : null, }); userAuth.setRechargeNotifier(async ({ userId, title, body, dedupeKey }) => { await notificationDispatcher.sendRechargeSuccess({ userId, title, body, dedupeKey }); }); const wechatAdmin = createWechatAdminService(pool, { config: wechatMpConfig, scheduleEnabled: process.env.H5_SCHEDULE_ENABLED === '1', reminderWorkerEnabled: process.env.H5_REMINDER_WORKER_ENABLED === '1', sendWechatTextToUser: wechatMpService?.enabled ? (userId, text) => wechatMpService.sendTextToUser(userId, text) : null, }); await ensureWordFilterSchema(pool); const wordFilterService = createWordFilterService(pool); await ensurePlanCatalogSchema(pool); const planCatalogService = createPlanCatalogService(pool); const subscriptionService = createSubscriptionService(pool, { getPlanAsync: (planType) => planCatalogService.getPlan(planType), }); await ensureSystemTestAccountSchema(pool); const systemTestAccountService = createSystemTestAccountService(pool); console.log(`Admin DB connected (${process.env.MYSQL_DATABASE ?? 'via DATABASE_URL'})`); console.log(`Users root: ${usersRoot}`); console.log(`Memind lib: ${memindLib}`); return { pool, userAuth, llmProviderService, assetGatewayConfigService, plazaOps, createOpsApi, wechatAdmin, mindSpaceConfig, loadMindSpaceConfig, updateMindSpaceConfig, memoryV2ConfigService, mindSearchConfigService, orchestratorConfigService, orchestratorObservabilityService, personalMemoryCandidateStore, skillRuntimeConfigService, wechatScheduleLlmConfigService, adminSystemTestService, systemTestAccountService, wordFilterService, planCatalogService, subscriptionService, USER_COOKIE, userLoginCookies, clearUserSessionCookie, resolveCookieDomainForRequest, }; }