everything-dev
Version:
A consolidated product package for building Module Federation apps with oRPC APIs.
1 lines • 23.3 kB
Source Map (JSON)
{"version":3,"file":"planner.mjs","names":[],"sources":["../../src/infra/planner.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport { resolve } from \"node:path\";\nimport { Effect } from \"effect\";\nimport { PortAllocator } from \"../app\";\nimport {\n buildDatabaseConfigs,\n buildOriginMap,\n buildRedisConfigs,\n type DatabaseSecretConfig,\n getSecretGroups,\n loadPortState,\n type RedisSecretConfig,\n savePortState,\n} from \"../cli/infra\";\nimport { buildDescription } from \"../service-descriptor\";\nimport type { RuntimeConfig } from \"../types\";\nimport type {\n ClaimRecord,\n CliPorts,\n ComposeModelPlan,\n DatabasePlan,\n InfraInput,\n InfraPlan,\n RedisPlan,\n ResolvedPorts,\n RuntimeLaunchSpec,\n ServiceDescriptorPlan,\n} from \"./types\";\nimport { InfraError } from \"./types\";\n\nconst DEFAULT_HOST_PORT = 3000;\nconst DEFAULT_API_PORT = 3001;\nconst DEFAULT_AUTH_PORT = 3002;\nconst DEFAULT_UI_PORT = 3003;\nconst DEFAULT_PLUGIN_PORT_START = 3010;\nconst POSTGRES_USER = \"everythingdev\";\nconst POSTGRES_PASSWORD = \"everythingdev\";\n\nexport function workspaceKey(configDir: string): string {\n const hash = createHash(\"sha256\").update(resolve(configDir)).digest(\"hex\");\n return hash.slice(0, 12);\n}\n\nfunction normalizeCliPorts(input: InfraInput[\"cli\"]): CliPorts {\n return {\n host: input.port,\n api: input.apiPort,\n auth: input.authPort,\n ui: input.uiPort,\n uiSsr: undefined,\n pluginsStart: input.pluginPortStart,\n plugins: input.plugins,\n };\n}\n\ninterface AllocateServicesResult {\n ports: ResolvedPorts;\n claims: ClaimRecord[];\n devPortsState: { host: number; api: number; auth: number; ui: number; pluginPortStart: number };\n}\n\nfunction allocateServices(\n cliPorts: CliPorts,\n plugins: Record<\n string,\n { source: string; localPath?: string; ui?: { source: string; localPath?: string } }\n >,\n configDir: string,\n): Effect.Effect<AllocateServicesResult, InfraError, PortAllocator> {\n return Effect.gen(function* () {\n const wKey = workspaceKey(configDir);\n const persisted = loadPortState(configDir).devPorts;\n const allocator = yield* PortAllocator;\n\n const hostPort = yield* allocator.pickAvailable(\n cliPorts.host ?? persisted?.host ?? DEFAULT_HOST_PORT,\n );\n\n const apiPort = yield* allocator.pickAvailable(\n cliPorts.api ?? persisted?.api ?? DEFAULT_API_PORT,\n );\n\n const authPort = yield* allocator.pickAvailable(\n cliPorts.auth ?? persisted?.auth ?? DEFAULT_AUTH_PORT,\n );\n\n const uiPort = yield* allocator.pickAvailable(cliPorts.ui ?? persisted?.ui ?? DEFAULT_UI_PORT);\n\n const uiSsrPort = yield* allocator.pickAvailable(cliPorts.uiSsr ?? uiPort + 1);\n\n const pluginApiPorts: Record<string, number> = {};\n const pluginUiPorts: Record<string, number> = {};\n\n const pluginKeys = Object.keys(plugins).sort();\n const pluginStart =\n cliPorts.pluginsStart ?? persisted?.pluginPortStart ?? DEFAULT_PLUGIN_PORT_START;\n let nextPluginPort = pluginStart;\n for (const pluginId of pluginKeys) {\n const pluginCfg = plugins[pluginId];\n const preferred = cliPorts.plugins?.[pluginId]?.api ?? nextPluginPort;\n const pluginPort = yield* allocator.pickAvailable(preferred);\n pluginApiPorts[pluginId] = pluginPort;\n nextPluginPort = pluginPort + 1;\n\n if (\n pluginCfg?.source === \"local\" &&\n pluginCfg?.localPath &&\n pluginCfg?.ui?.source === \"local\"\n ) {\n const uiPreferred = cliPorts.plugins?.[pluginId]?.ui ?? nextPluginPort;\n const pluginUiPort = yield* allocator.pickAvailable(uiPreferred);\n pluginUiPorts[pluginId] = pluginUiPort;\n nextPluginPort = pluginUiPort + 1;\n }\n }\n\n const resolved: ResolvedPorts = {\n host: hostPort,\n api: apiPort,\n auth: authPort,\n ui: uiPort,\n uiSsr: uiSsrPort,\n plugins: Object.fromEntries(\n Object.entries(pluginApiPorts).map(([k, v]) => [k, { api: v, ui: pluginUiPorts[k] }]),\n ),\n postgres: {},\n redis: {},\n };\n\n const devPortsState = {\n host: hostPort,\n api: apiPort,\n auth: authPort,\n ui: uiPort,\n pluginPortStart: pluginStart,\n };\n\n const claimPorts: Record<string, number> = {\n host: hostPort,\n api: apiPort,\n auth: authPort,\n ui: uiPort,\n uiSsr: uiSsrPort,\n };\n for (const [id, port] of Object.entries(pluginApiPorts)) {\n claimPorts[`plugin:${id}`] = port;\n }\n for (const [id, port] of Object.entries(pluginUiPorts)) {\n claimPorts[`plugin-ui:${id}`] = port;\n }\n\n const claim: ClaimRecord = {\n resourceKey: `workspace:${wKey}`,\n pid: process.pid,\n configDir,\n ports: claimPorts,\n startedAt: Date.now(),\n };\n\n return { ports: resolved, claims: [claim], devPortsState };\n }).pipe(\n Effect.mapError(\n (portErr) =>\n new InfraError({\n phase: \"allocate-services\",\n message: `Port allocation failed: ${String(portErr)}`,\n cause: portErr,\n }),\n ),\n );\n}\n\nfunction allocateDatabases(\n runtimeConfig: RuntimeConfig,\n configDir: string,\n): Effect.Effect<\n {\n postgres: Record<string, number>;\n redis: Record<string, number>;\n dbs: DatabasePlan[];\n redisPlans: RedisPlan[];\n },\n InfraError,\n PortAllocator\n> {\n return Effect.gen(function* () {\n const persisted = loadPortState(configDir);\n const groups = getSecretGroups(runtimeConfig);\n const allSecrets = groups.flatMap((group) => group.secrets);\n const originMap = buildOriginMap(configDir, runtimeConfig);\n const allocator = yield* PortAllocator;\n\n const infraDatabases: DatabaseSecretConfig[] = yield* Effect.sync(() =>\n buildDatabaseConfigs(allSecrets, originMap, { ...persisted.postgresPorts }),\n );\n const infraRedis: RedisSecretConfig[] = yield* Effect.sync(() =>\n buildRedisConfigs(allSecrets, originMap, { ...persisted.redisPorts }),\n );\n\n const postgres: Record<string, number> = {};\n const dbs: DatabasePlan[] = [];\n for (const db of infraDatabases) {\n const port = yield* allocator.pickAvailable(db.port);\n postgres[db.slug] = port;\n dbs.push({\n secret: db.secret,\n slug: db.slug,\n port,\n dbName: db.databaseName,\n containerName: db.containerName,\n volumeName: db.volumeName,\n url: `postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:${port}/${db.slug}_db`,\n });\n }\n\n const redis: Record<string, number> = {};\n const redisPlans: RedisPlan[] = [];\n for (const r of infraRedis) {\n const port = yield* allocator.pickAvailable(r.port);\n redis[r.slug] = port;\n redisPlans.push({\n secret: r.secret,\n slug: r.slug,\n port,\n containerName: r.containerName,\n volumeName: r.volumeName,\n url: `redis://localhost:${port}`,\n });\n }\n\n return { postgres, redis, dbs, redisPlans };\n }).pipe(\n Effect.mapError(\n (portErr) =>\n new InfraError({\n phase: \"allocate-databases\",\n message: `Database port allocation failed: ${String(portErr)}`,\n cause: portErr,\n }),\n ),\n );\n}\n\nexport function buildServiceDescriptors(\n runtimeConfig: RuntimeConfig,\n resolvedPorts: ResolvedPorts,\n): ServiceDescriptorPlan[] {\n const descriptors: ServiceDescriptorPlan[] = [];\n\n if (runtimeConfig.host) {\n const isLocal = runtimeConfig.host.source === \"local\";\n descriptors.push({\n key: \"host\",\n source: runtimeConfig.host.source,\n url: isLocal ? `http://localhost:${resolvedPorts.host}` : runtimeConfig.host.url,\n port: isLocal ? resolvedPorts.host : undefined,\n localPath: isLocal ? runtimeConfig.host.localPath : undefined,\n });\n }\n\n if (runtimeConfig.api) {\n const isLocal = runtimeConfig.api.source === \"local\";\n descriptors.push({\n key: \"api\",\n source: runtimeConfig.api.source,\n url: isLocal ? `http://localhost:${resolvedPorts.api}` : runtimeConfig.api.url,\n port: isLocal ? resolvedPorts.api : undefined,\n localPath: isLocal ? runtimeConfig.api.localPath : undefined,\n });\n }\n\n if (runtimeConfig.auth) {\n const isLocal = runtimeConfig.auth.source === \"local\";\n descriptors.push({\n key: \"auth\",\n source: runtimeConfig.auth.source,\n url: isLocal ? `http://localhost:${resolvedPorts.auth}` : runtimeConfig.auth.url,\n port: isLocal ? resolvedPorts.auth : undefined,\n localPath: isLocal ? runtimeConfig.auth.localPath : undefined,\n });\n }\n\n if (runtimeConfig.ui) {\n const isLocal = runtimeConfig.ui.source === \"local\";\n descriptors.push({\n key: \"ui\",\n source: runtimeConfig.ui.source,\n url: isLocal ? `http://localhost:${resolvedPorts.ui}` : runtimeConfig.ui.url,\n port: isLocal ? resolvedPorts.ui : undefined,\n localPath: isLocal ? runtimeConfig.ui.localPath : undefined,\n });\n if (isLocal && resolvedPorts.uiSsr) {\n descriptors.push({\n key: \"ui-ssr\",\n source: \"local\",\n url: `http://localhost:${resolvedPorts.uiSsr}`,\n port: resolvedPorts.uiSsr,\n localPath: runtimeConfig.ui.localPath,\n });\n }\n }\n\n if (runtimeConfig.plugins) {\n for (const [pluginId, pluginCfg] of Object.entries(runtimeConfig.plugins)) {\n const pluginIsLocal = pluginCfg.source === \"local\";\n const p = resolvedPorts.plugins[pluginId];\n if (pluginIsLocal && p?.api) {\n descriptors.push({\n key: `plugin:${pluginId}`,\n source: \"local\",\n url: `http://localhost:${p.api}`,\n port: p.api,\n localPath: pluginCfg.localPath,\n });\n }\n if (!pluginIsLocal && pluginCfg.url) {\n descriptors.push({\n key: `plugin:${pluginId}`,\n source: \"remote\",\n url: pluginCfg.url,\n port: undefined,\n localPath: undefined,\n });\n }\n if (pluginIsLocal && p?.ui && pluginCfg.ui?.source === \"local\") {\n descriptors.push({\n key: `plugin-ui:${pluginId}`,\n source: \"local\",\n url: `http://localhost:${p.ui}`,\n port: p.ui,\n localPath: pluginCfg.ui?.localPath,\n });\n }\n }\n }\n\n return descriptors;\n}\n\nexport function buildLaunchSpec(\n runtimeConfig: RuntimeConfig,\n resolvedPorts: ResolvedPorts,\n): RuntimeLaunchSpec {\n const hostPort =\n runtimeConfig.host?.source === \"local\" ? resolvedPorts.host : runtimeConfig.host?.port;\n const corsOrigin = hostPort ? `http://localhost:${hostPort}` : `http://localhost:3000`;\n\n return {\n port: resolvedPorts.host,\n hostUrl: runtimeConfig.host?.url,\n corsOrigin,\n env: {\n ...(resolvedPorts.host ? { PORT: String(resolvedPorts.host) } : {}),\n ...(resolvedPorts.api ? { API_PORT: String(resolvedPorts.api) } : {}),\n ...(resolvedPorts.ui ? { UI_PORT: String(resolvedPorts.ui) } : {}),\n ...(resolvedPorts.auth ? { AUTH_PORT: String(resolvedPorts.auth) } : {}),\n },\n runtimeConfig,\n };\n}\n\nexport function buildComposeModel(dbs: DatabasePlan[], redisPlans: RedisPlan[]): ComposeModelPlan {\n return { databases: dbs, redis: redisPlans };\n}\n\nexport function buildEnvGenerated(\n resolvedPorts: ResolvedPorts,\n dbs: DatabasePlan[],\n redisPlans: RedisPlan[],\n): Record<string, string> {\n const env: Record<string, string> = {};\n\n if (resolvedPorts.host) {\n env.CORS_ORIGIN = `http://localhost:${resolvedPorts.host}`;\n }\n\n for (const db of dbs) {\n env[db.secret] = db.url;\n }\n for (const r of redisPlans) {\n env[r.secret] = r.url;\n }\n\n return env;\n}\n\nexport function planInfra(input: InfraInput): Effect.Effect<InfraPlan, InfraError, PortAllocator> {\n return Effect.gen(function* () {\n const cliPorts = normalizeCliPorts(input.cli);\n const wKey = workspaceKey(input.configDir);\n\n const plugins = (input.bosConfig.plugins ?? {}) as Record<\n string,\n { source: string; localPath?: string; ui?: { source: string; localPath?: string } }\n >;\n\n const {\n ports: svcPorts,\n claims,\n devPortsState,\n } = yield* allocateServices(cliPorts, plugins, input.configDir);\n\n const {\n dbs,\n redisPlans,\n postgres: pgPorts,\n redis: rdPorts,\n } = yield* allocateDatabases(input.bosConfig, input.configDir);\n\n const resolvedPorts: ResolvedPorts = {\n ...svcPorts,\n postgres: pgPorts,\n redis: rdPorts,\n };\n\n // Write merged state once after all allocations succeed\n savePortState(input.configDir, {\n postgresPorts: pgPorts,\n redisPorts: rdPorts,\n devPorts: devPortsState,\n });\n\n const hostIsLocal = input.bosConfig.host?.source === \"local\";\n const apiIsLocal = input.bosConfig.api?.source === \"local\";\n const uiIsLocal = input.bosConfig.ui?.source === \"local\";\n const authIsLocal = input.bosConfig.auth?.source === \"local\";\n const assignedRuntimeConfig: RuntimeConfig = {\n ...input.bosConfig,\n host: resolvedPorts.host\n ? {\n ...input.bosConfig.host,\n port: resolvedPorts.host,\n url: `http://localhost:${resolvedPorts.host}`,\n remoteUrl: !hostIsLocal\n ? (input.bosConfig.host.remoteUrl ?? input.bosConfig.host.url)\n : undefined,\n }\n : input.bosConfig.host,\n api:\n apiIsLocal && resolvedPorts.api\n ? {\n ...input.bosConfig.api,\n port: resolvedPorts.api,\n url: `http://localhost:${resolvedPorts.api}`,\n }\n : input.bosConfig.api,\n ui:\n uiIsLocal && resolvedPorts.ui\n ? {\n ...input.bosConfig.ui,\n port: resolvedPorts.ui,\n url: `http://localhost:${resolvedPorts.ui}`,\n }\n : input.bosConfig.ui,\n auth:\n authIsLocal && resolvedPorts.auth && input.bosConfig.auth\n ? {\n ...input.bosConfig.auth,\n port: resolvedPorts.auth,\n url: `http://localhost:${resolvedPorts.auth}`,\n }\n : input.bosConfig.auth,\n plugins: input.bosConfig.plugins\n ? Object.fromEntries(\n Object.entries(input.bosConfig.plugins).map(([id, p]) => {\n const pluginPort = resolvedPorts.plugins[id];\n if (p.source === \"local\" && pluginPort?.api) {\n return [\n id,\n { ...p, port: pluginPort.api, url: `http://localhost:${pluginPort.api}` },\n ];\n }\n return [id, p];\n }),\n )\n : undefined,\n };\n\n const serviceDescriptors = buildServiceDescriptors(input.bosConfig, resolvedPorts);\n\n const launch = buildLaunchSpec(input.bosConfig, resolvedPorts);\n const composeModel = buildComposeModel(dbs, redisPlans);\n const envGenerated = buildEnvGenerated(resolvedPorts, dbs, redisPlans);\n\n const packages = serviceDescriptors.map((d) => d.key);\n const descriptionMap = new Map(serviceDescriptors.map((d) => [d.key, d]));\n const description = buildDescription(descriptionMap);\n\n const orchestrator = {\n packages,\n env: {},\n description,\n port: resolvedPorts.host,\n interactive: input.cli.interactive,\n };\n\n return {\n workspaceKey: wKey,\n cliPorts,\n resolvedPorts,\n runtimeConfig: assignedRuntimeConfig,\n launch,\n description,\n serviceDescriptors: new Map(serviceDescriptors.map((d) => [d.key, d])),\n envGenerated,\n composeModel,\n claims,\n orchestrator,\n };\n });\n}\n"],"mappings":"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"}