feat: add database schema support for gateway and game profiles
- Introduced `dbSchema` configuration option in GatewayApiConfig and GatewayOrchestratorConfig. - Implemented schema resolution logic in environment configuration functions. - Updated context and orchestrator factory to use GatewayPrismaClient instead of PrismaClient. - Refactored orchestrator server and profile repository to accommodate new database schema handling. - Created separate Prisma schemas for game and gateway in the infra package. - Enhanced Postgres connector to support schema overrides in database URLs. - Updated documentation to reflect changes in database schema handling. - Added new Prisma generation and database push scripts for game and gateway schemas.
This commit is contained in:
@@ -26,7 +26,7 @@ const parseNumber = (value: string | undefined, fallback: number, label: string)
|
||||
export const resolveGameApiConfigFromEnv = (
|
||||
env: NodeJS.ProcessEnv = process.env
|
||||
): GameApiConfig => {
|
||||
const profile = env.PROFILE ?? env.SERVER_PROFILE ?? 'che';
|
||||
const profile = env.PROFILE ?? env.SERVER_PROFILE ?? 'hwe';
|
||||
const scenario = env.SCENARIO ?? 'default';
|
||||
const profileName = `${profile}:${scenario}`;
|
||||
const secret = env.GAME_TOKEN_SECRET ?? env.GATEWAY_TOKEN_SECRET ?? '';
|
||||
|
||||
@@ -2,7 +2,7 @@ import fastify, { type FastifyRequest } from 'fastify';
|
||||
import cors from '@fastify/cors';
|
||||
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGamePostgresConnector,
|
||||
createRedisConnector,
|
||||
resolvePostgresConfigFromEnv,
|
||||
resolveRedisConfigFromEnv,
|
||||
@@ -35,7 +35,9 @@ const extractBearerToken = (value: string | string[] | undefined): string | null
|
||||
|
||||
export const createGameApiServer = async () => {
|
||||
const config = resolveGameApiConfigFromEnv();
|
||||
const postgres = createPostgresConnector(resolvePostgresConfigFromEnv());
|
||||
const postgres = createGamePostgresConnector(
|
||||
resolvePostgresConfigFromEnv({ schema: config.profile })
|
||||
);
|
||||
const redis = createRedisConnector(resolveRedisConfigFromEnv());
|
||||
|
||||
await postgres.connect();
|
||||
|
||||
@@ -11,6 +11,7 @@ type EnvMap = Record<string, string | undefined>;
|
||||
export interface DatabaseUrlOptions {
|
||||
envFile?: string;
|
||||
env?: NodeJS.ProcessEnv;
|
||||
schema?: string;
|
||||
}
|
||||
|
||||
const parseEnvFile = (rawText: string): EnvMap => {
|
||||
@@ -47,18 +48,42 @@ const loadEnvFile = async (envFile: string): Promise<EnvMap> => {
|
||||
}
|
||||
};
|
||||
|
||||
const applySchemaToDatabaseUrl = (
|
||||
url: string,
|
||||
schema: string | undefined
|
||||
): string => {
|
||||
if (!schema) {
|
||||
return url;
|
||||
}
|
||||
try {
|
||||
const parsed = new URL(url);
|
||||
parsed.searchParams.set('schema', schema);
|
||||
return parsed.toString();
|
||||
} catch {
|
||||
return url;
|
||||
}
|
||||
};
|
||||
|
||||
export const resolveDatabaseUrl = async (
|
||||
options?: DatabaseUrlOptions
|
||||
): Promise<string> => {
|
||||
const env = options?.env ?? process.env;
|
||||
if (env.DATABASE_URL) {
|
||||
return env.DATABASE_URL;
|
||||
const schema =
|
||||
options?.schema ??
|
||||
env.POSTGRES_SCHEMA ??
|
||||
env.DATABASE_SCHEMA;
|
||||
return applySchemaToDatabaseUrl(env.DATABASE_URL, schema);
|
||||
}
|
||||
|
||||
const envFile = options?.envFile ?? DEFAULT_ENV_FILE;
|
||||
const fileEnv = await loadEnvFile(envFile);
|
||||
if (fileEnv.DATABASE_URL) {
|
||||
return fileEnv.DATABASE_URL;
|
||||
const schema =
|
||||
options?.schema ??
|
||||
fileEnv.POSTGRES_SCHEMA ??
|
||||
fileEnv.DATABASE_SCHEMA;
|
||||
return applySchemaToDatabaseUrl(fileEnv.DATABASE_URL, schema);
|
||||
}
|
||||
|
||||
const host = env.POSTGRES_HOST ?? fileEnv.POSTGRES_HOST ?? '127.0.0.1';
|
||||
@@ -66,5 +91,12 @@ export const resolveDatabaseUrl = async (
|
||||
const user = env.POSTGRES_USER ?? fileEnv.POSTGRES_USER ?? 'sammo';
|
||||
const password = env.POSTGRES_PASSWORD ?? fileEnv.POSTGRES_PASSWORD ?? '';
|
||||
const dbName = env.POSTGRES_DB ?? fileEnv.POSTGRES_DB ?? 'sammo';
|
||||
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
|
||||
const schema =
|
||||
options?.schema ??
|
||||
env.POSTGRES_SCHEMA ??
|
||||
fileEnv.POSTGRES_SCHEMA ??
|
||||
env.DATABASE_SCHEMA ??
|
||||
fileEnv.DATABASE_SCHEMA ??
|
||||
'public';
|
||||
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=${schema}`;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGamePostgresConnector,
|
||||
type InputJsonValue,
|
||||
type TurnEngineDatabaseClient,
|
||||
type TurnEngineEventCreateManyInput,
|
||||
@@ -117,7 +117,7 @@ export const seedScenarioToDatabase = async (
|
||||
},
|
||||
});
|
||||
|
||||
const connector = createPostgresConnector({ url: options.databaseUrl });
|
||||
const connector = createGamePostgresConnector({ url: options.databaseUrl });
|
||||
const now = options.now ?? new Date();
|
||||
const tickSeconds = options.tickSeconds ?? DEFAULT_TICK_SECONDS;
|
||||
const generalGold = options.defaultGeneralGold ?? DEFAULT_GENERAL_GOLD;
|
||||
@@ -125,7 +125,7 @@ export const seedScenarioToDatabase = async (
|
||||
|
||||
await connector.connect();
|
||||
try {
|
||||
const prisma = connector.prisma as TurnEngineDatabaseClient;
|
||||
const prisma = connector.prisma as unknown as TurnEngineDatabaseClient;
|
||||
|
||||
if (options.resetTables ?? true) {
|
||||
await prisma.event.deleteMany();
|
||||
|
||||
@@ -9,6 +9,7 @@ export interface TurnDaemonCliOptions {
|
||||
profileName?: string;
|
||||
scenario?: string;
|
||||
databaseUrl?: string;
|
||||
gatewayDatabaseUrl?: string;
|
||||
tickMinutes?: number;
|
||||
schedule?: TurnSchedule;
|
||||
budget?: Partial<TurnRunBudget>;
|
||||
@@ -72,14 +73,22 @@ export const runTurnDaemonCli = async (
|
||||
): Promise<void> => {
|
||||
const env = options.env ?? process.env;
|
||||
const profile =
|
||||
options.profile ?? env.TURN_PROFILE ?? env.PROFILE ?? 'che';
|
||||
options.profile ?? env.TURN_PROFILE ?? env.PROFILE ?? 'hwe';
|
||||
const scenario = options.scenario ?? env.TURN_SCENARIO ?? env.SCENARIO;
|
||||
const profileName =
|
||||
options.profileName ??
|
||||
env.TURN_PROFILE_NAME ??
|
||||
(scenario ? `${profile}:${scenario}` : profile);
|
||||
const databaseUrl =
|
||||
options.databaseUrl ?? (await resolveDatabaseUrl({ env }));
|
||||
options.databaseUrl ??
|
||||
(await resolveDatabaseUrl({ env, schema: profile }));
|
||||
const gatewayDatabaseUrl =
|
||||
options.gatewayDatabaseUrl ??
|
||||
env.GATEWAY_DATABASE_URL ??
|
||||
(await resolveDatabaseUrl({
|
||||
env,
|
||||
schema: env.GATEWAY_DB_SCHEMA ?? 'public',
|
||||
}));
|
||||
const budget = buildBudgetOverride(env, options.budget);
|
||||
const tickMinutes =
|
||||
options.tickMinutes ?? parseNumber(env.TURN_TICK_MINUTES);
|
||||
@@ -93,6 +102,7 @@ export const runTurnDaemonCli = async (
|
||||
profile,
|
||||
profileName,
|
||||
databaseUrl,
|
||||
gatewayDatabaseUrl,
|
||||
defaultBudget: budget,
|
||||
tickMinutes,
|
||||
schedule: options.schedule,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGamePostgresConnector,
|
||||
type InputJsonValue,
|
||||
type TurnEngineCityUpdateInput,
|
||||
type TurnEngineDatabaseClient,
|
||||
@@ -236,9 +236,9 @@ export const createDatabaseTurnHooks = async (
|
||||
options?: { reservedTurns?: InMemoryReservedTurnStore }
|
||||
): Promise<DatabaseTurnHooks> => {
|
||||
// 턴 처리 결과를 DB에 반영하는 훅을 만든다.
|
||||
const connector = createPostgresConnector({ url: databaseUrl });
|
||||
const connector = createGamePostgresConnector({ url: databaseUrl });
|
||||
await connector.connect();
|
||||
const prisma = connector.prisma as TurnEngineDatabaseClient;
|
||||
const prisma = connector.prisma as unknown as TurnEngineDatabaseClient;
|
||||
|
||||
const hooks: TurnDaemonHooks = {
|
||||
flushChanges: async () => {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { createPostgresConnector } from '@sammo-ts/infra';
|
||||
import { createGatewayPostgresConnector } from '@sammo-ts/infra';
|
||||
|
||||
export interface GatewayProfileGateOptions {
|
||||
databaseUrl: string;
|
||||
gatewayDatabaseUrl?: string;
|
||||
profileName: string;
|
||||
cacheMs?: number;
|
||||
}
|
||||
@@ -29,7 +30,9 @@ type GatewayProfileClient = {
|
||||
export const createGatewayProfileGate = async (
|
||||
options: GatewayProfileGateOptions
|
||||
): Promise<GatewayProfileGate> => {
|
||||
const connector = createPostgresConnector({ url: options.databaseUrl });
|
||||
const connector = createGatewayPostgresConnector({
|
||||
url: options.gatewayDatabaseUrl ?? options.databaseUrl,
|
||||
});
|
||||
await connector.connect();
|
||||
const prisma = connector.prisma as unknown as {
|
||||
gatewayProfile: GatewayProfileClient;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGamePostgresConnector,
|
||||
type InputJsonValue,
|
||||
type TurnEngineDatabaseClient,
|
||||
} from '@sammo-ts/infra';
|
||||
@@ -269,10 +269,10 @@ export class InMemoryReservedTurnStore {
|
||||
export const createReservedTurnStore = async (
|
||||
options: ReservedTurnStoreOptions
|
||||
): Promise<ReservedTurnStoreHandle> => {
|
||||
const connector = createPostgresConnector({ url: options.databaseUrl });
|
||||
const connector = createGamePostgresConnector({ url: options.databaseUrl });
|
||||
await connector.connect();
|
||||
const store = new InMemoryReservedTurnStore(
|
||||
connector.prisma as ReservedTurnDatabaseClient,
|
||||
connector.prisma as unknown as ReservedTurnDatabaseClient,
|
||||
{
|
||||
maxGeneralTurns: options.maxGeneralTurns ?? DEFAULT_GENERAL_TURNS,
|
||||
maxNationTurns: options.maxNationTurns ?? DEFAULT_NATION_TURNS,
|
||||
|
||||
@@ -30,6 +30,7 @@ export interface TurnDaemonRuntimeOptions {
|
||||
profile: string;
|
||||
profileName?: string;
|
||||
databaseUrl: string;
|
||||
gatewayDatabaseUrl?: string;
|
||||
defaultBudget?: TurnRunBudget;
|
||||
clock?: Clock;
|
||||
controlQueue?: TurnDaemonControlQueue;
|
||||
@@ -137,6 +138,7 @@ export const createTurnDaemonRuntime = async (
|
||||
options.profileName
|
||||
? await createGatewayProfileGate({
|
||||
databaseUrl: options.databaseUrl,
|
||||
gatewayDatabaseUrl: options.gatewayDatabaseUrl,
|
||||
profileName: options.profileName,
|
||||
cacheMs: options.pauseGateIntervalMs,
|
||||
})
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGamePostgresConnector,
|
||||
type JsonValue,
|
||||
type TurnEngineCityRow,
|
||||
type TurnEngineDatabaseClient,
|
||||
@@ -252,10 +252,10 @@ const mapTroopRow = (row: TurnEngineTroopRow): Troop => ({
|
||||
export const loadTurnWorldFromDatabase = async (
|
||||
options: TurnWorldLoaderOptions
|
||||
): Promise<TurnWorldLoadResult> => {
|
||||
const connector = createPostgresConnector({ url: options.databaseUrl });
|
||||
const connector = createGamePostgresConnector({ url: options.databaseUrl });
|
||||
await connector.connect();
|
||||
try {
|
||||
const prisma = connector.prisma as TurnEngineDatabaseClient;
|
||||
const prisma = connector.prisma as unknown as TurnEngineDatabaseClient;
|
||||
const worldState = await prisma.worldState.findFirst();
|
||||
if (!worldState) {
|
||||
throw new Error('world_state row is required to start turn daemon.');
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { createPostgresConnector } from '@sammo-ts/infra';
|
||||
import { createGamePostgresConnector } from '@sammo-ts/infra';
|
||||
import { describe, expect, test } from 'vitest';
|
||||
import { resolveDatabaseUrl } from '../src/scenario/databaseUrl.js';
|
||||
import { seedScenarioToDatabase } from '../src/scenario/scenarioSeeder.js';
|
||||
|
||||
const scenarioId = 1010;
|
||||
const databaseUrl = await resolveDatabaseUrl();
|
||||
const schema = process.env.POSTGRES_SCHEMA ?? 'public';
|
||||
process.env.POSTGRES_SCHEMA = schema;
|
||||
const databaseUrl = await resolveDatabaseUrl({ schema });
|
||||
|
||||
type ScenarioSeederPrismaClient = {
|
||||
$queryRawUnsafe(query: string): Promise<unknown>;
|
||||
@@ -26,7 +28,7 @@ type ScenarioSeederPrismaClient = {
|
||||
};
|
||||
|
||||
const canConnectToDatabase = async (url: string): Promise<boolean> => {
|
||||
const connector = createPostgresConnector({ url });
|
||||
const connector = createGamePostgresConnector({ url });
|
||||
try {
|
||||
await connector.connect();
|
||||
const prisma = connector.prisma as ScenarioSeederPrismaClient;
|
||||
@@ -49,7 +51,7 @@ describeDb('scenario database seed', () => {
|
||||
databaseUrl,
|
||||
});
|
||||
|
||||
const connector = createPostgresConnector({ url: databaseUrl });
|
||||
const connector = createGamePostgresConnector({ url: databaseUrl });
|
||||
await connector.connect();
|
||||
try {
|
||||
const prisma = connector.prisma as ScenarioSeederPrismaClient;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Prisma, type PrismaClient } from '@prisma/client';
|
||||
import { GatewayPrisma, type GatewayPrismaClient } from '@sammo-ts/infra';
|
||||
|
||||
import { createSimplePasswordHasher, type PasswordHasher } from './passwordHasher.js';
|
||||
import type {
|
||||
@@ -29,12 +29,12 @@ const mapUser = (row: {
|
||||
displayName: string;
|
||||
passwordHash: string;
|
||||
passwordSalt: string;
|
||||
roles: Prisma.JsonValue;
|
||||
sanctions: Prisma.JsonValue;
|
||||
roles: GatewayPrisma.JsonValue;
|
||||
sanctions: GatewayPrisma.JsonValue;
|
||||
oauthType: 'NONE' | 'KAKAO';
|
||||
oauthId: string | null;
|
||||
email: string | null;
|
||||
oauthInfo: Prisma.JsonValue;
|
||||
oauthInfo: GatewayPrisma.JsonValue;
|
||||
createdAt: Date;
|
||||
}): UserRecord => ({
|
||||
id: row.id,
|
||||
@@ -52,7 +52,7 @@ const mapUser = (row: {
|
||||
});
|
||||
|
||||
export const createPostgresUserRepository = (
|
||||
prisma: PrismaClient,
|
||||
prisma: GatewayPrismaClient,
|
||||
hasher: PasswordHasher = createSimplePasswordHasher()
|
||||
): UserRepository => {
|
||||
return {
|
||||
@@ -98,12 +98,12 @@ export const createPostgresUserRepository = (
|
||||
displayName: input.displayName ?? input.username,
|
||||
passwordHash: hasher.hash(input.password, salt),
|
||||
passwordSalt: salt,
|
||||
roles: ['user'] satisfies Prisma.JsonArray,
|
||||
sanctions: {} satisfies Prisma.JsonObject,
|
||||
roles: ['user'] satisfies GatewayPrisma.JsonArray,
|
||||
sanctions: {} satisfies GatewayPrisma.JsonObject,
|
||||
oauthType,
|
||||
oauthId: input.oauth?.id,
|
||||
email: input.oauth?.email?.toLowerCase(),
|
||||
oauthInfo: (input.oauth?.info ?? {}) as Prisma.JsonObject,
|
||||
oauthInfo: (input.oauth?.info ?? {}) as GatewayPrisma.JsonObject,
|
||||
},
|
||||
});
|
||||
return mapUser(row);
|
||||
@@ -125,7 +125,7 @@ export const createPostgresUserRepository = (
|
||||
await prisma.appUser.update({
|
||||
where: { id: userId },
|
||||
data: {
|
||||
oauthInfo: oauthInfo as Prisma.JsonObject,
|
||||
oauthInfo: oauthInfo as GatewayPrisma.JsonObject,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
@@ -4,6 +4,7 @@ export interface GatewayApiConfig {
|
||||
host: string;
|
||||
port: number;
|
||||
trpcPath: string;
|
||||
dbSchema: string;
|
||||
redisKeyPrefix: string;
|
||||
flushChannel: string;
|
||||
sessionTtlSeconds: number;
|
||||
@@ -24,6 +25,7 @@ export interface GatewayApiConfig {
|
||||
}
|
||||
|
||||
export interface GatewayOrchestratorConfig {
|
||||
dbSchema: string;
|
||||
redisKeyPrefix: string;
|
||||
gameTokenSecret: string;
|
||||
orchestratorReconcileIntervalMs: number;
|
||||
@@ -58,6 +60,14 @@ const parseBoolean = (value: string | undefined, fallback: boolean): boolean =>
|
||||
return fallback;
|
||||
};
|
||||
|
||||
const resolveSchemaName = (value: string | undefined): string => {
|
||||
if (!value) {
|
||||
return 'public';
|
||||
}
|
||||
const trimmed = value.trim();
|
||||
return trimmed ? trimmed : 'public';
|
||||
};
|
||||
|
||||
export const resolveGatewayApiConfigFromEnv = (
|
||||
env: NodeJS.ProcessEnv = process.env
|
||||
): GatewayApiConfig => {
|
||||
@@ -76,6 +86,7 @@ export const resolveGatewayApiConfigFromEnv = (
|
||||
host: env.GATEWAY_API_HOST ?? '0.0.0.0',
|
||||
port: parseNumber(env.GATEWAY_API_PORT, 13000, 'GATEWAY_API_PORT'),
|
||||
trpcPath: env.TRPC_PATH ?? '/trpc',
|
||||
dbSchema: resolveSchemaName(env.GATEWAY_DB_SCHEMA),
|
||||
redisKeyPrefix,
|
||||
flushChannel: `${redisKeyPrefix}:flush`,
|
||||
sessionTtlSeconds: parseNumber(env.SESSION_TTL_SECONDS, 60 * 60 * 24 * 7, 'SESSION_TTL_SECONDS'),
|
||||
@@ -127,6 +138,7 @@ export const resolveGatewayOrchestratorConfigFromEnv = (
|
||||
}
|
||||
const redisKeyPrefix = env.GATEWAY_REDIS_PREFIX ?? 'sammo:gateway';
|
||||
return {
|
||||
dbSchema: resolveSchemaName(env.GATEWAY_DB_SCHEMA),
|
||||
redisKeyPrefix,
|
||||
gameTokenSecret: secret,
|
||||
orchestratorReconcileIntervalMs: parseNumber(
|
||||
|
||||
@@ -6,7 +6,7 @@ import type { OAuthSessionStore } from './auth/oauthSessionStore.js';
|
||||
import type { GatewayProfileRepository } from './orchestrator/profileRepository.js';
|
||||
import type { GatewayOrchestratorHandle } from './orchestrator/gatewayOrchestrator.js';
|
||||
import type { GatewayProfileStatusService } from './lobby/profileStatusService.js';
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
import type { GatewayPrismaClient } from '@sammo-ts/infra';
|
||||
|
||||
export interface GatewayApiContext {
|
||||
users: UserRepository;
|
||||
@@ -22,7 +22,7 @@ export interface GatewayApiContext {
|
||||
profileStatus: GatewayProfileStatusService;
|
||||
adminToken?: string;
|
||||
requestHeaders: Record<string, string | string[] | undefined>;
|
||||
prisma: PrismaClient;
|
||||
prisma: GatewayPrismaClient;
|
||||
}
|
||||
|
||||
export const createGatewayApiContext = (options: {
|
||||
@@ -39,7 +39,7 @@ export const createGatewayApiContext = (options: {
|
||||
profileStatus: GatewayProfileStatusService;
|
||||
adminToken?: string;
|
||||
requestHeaders?: Record<string, string | string[] | undefined>;
|
||||
prisma: PrismaClient;
|
||||
prisma: GatewayPrismaClient;
|
||||
}): GatewayApiContext => ({
|
||||
users: options.users,
|
||||
sessions: options.sessions,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
import type { GatewayPrismaClient } from '@sammo-ts/infra';
|
||||
|
||||
import type { GatewayOrchestratorConfig } from '../config.js';
|
||||
import { createGatewayProfileRepository } from './profileRepository.js';
|
||||
@@ -16,7 +16,7 @@ export const buildEnvMap = (env: NodeJS.ProcessEnv): Record<string, string> => {
|
||||
};
|
||||
|
||||
export const createGatewayOrchestrator = (
|
||||
prisma: PrismaClient,
|
||||
prisma: GatewayPrismaClient,
|
||||
config: GatewayOrchestratorConfig,
|
||||
env: NodeJS.ProcessEnv = process.env
|
||||
): {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGatewayPostgresConnector,
|
||||
type GatewayPrismaClient,
|
||||
resolvePostgresConfigFromEnv,
|
||||
} from '@sammo-ts/infra';
|
||||
|
||||
@@ -9,11 +9,13 @@ import { createGatewayOrchestrator } from './orchestratorFactory.js';
|
||||
|
||||
export const runGatewayOrchestrator = async (): Promise<void> => {
|
||||
const config = resolveGatewayOrchestratorConfigFromEnv();
|
||||
const postgres = createPostgresConnector(resolvePostgresConfigFromEnv());
|
||||
const postgres = createGatewayPostgresConnector(
|
||||
resolvePostgresConfigFromEnv({ schema: config.dbSchema })
|
||||
);
|
||||
await postgres.connect();
|
||||
|
||||
const { orchestrator } = createGatewayOrchestrator(
|
||||
postgres.prisma as PrismaClient,
|
||||
postgres.prisma as GatewayPrismaClient,
|
||||
config,
|
||||
process.env
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Prisma, type PrismaClient } from '@prisma/client';
|
||||
import { GatewayPrisma, type GatewayPrismaClient } from '@sammo-ts/infra';
|
||||
|
||||
export const GATEWAY_PROFILE_STATUSES = [
|
||||
'RESERVED',
|
||||
@@ -38,7 +38,7 @@ export interface GatewayProfileRecord {
|
||||
buildCompletedAt?: string;
|
||||
buildError?: string;
|
||||
lastError?: string;
|
||||
meta: Prisma.JsonObject;
|
||||
meta: GatewayPrisma.JsonObject;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export interface GatewayProfileUpsertInput {
|
||||
openAt?: string;
|
||||
scheduledStartAt?: string;
|
||||
buildCommitSha?: string;
|
||||
meta?: Prisma.JsonObject;
|
||||
meta?: GatewayPrisma.JsonObject;
|
||||
}
|
||||
|
||||
export interface GatewayProfileRepository {
|
||||
@@ -113,7 +113,7 @@ type GatewayProfileRow = {
|
||||
buildCompletedAt: Date | null;
|
||||
buildError: string | null;
|
||||
lastError: string | null;
|
||||
meta: Prisma.JsonValue;
|
||||
meta: GatewayPrisma.JsonValue;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
};
|
||||
@@ -145,7 +145,7 @@ const mapProfile = (row: GatewayProfileRow): GatewayProfileRecord => ({
|
||||
buildCompletedAt: toIso(row.buildCompletedAt),
|
||||
buildError: row.buildError ?? undefined,
|
||||
lastError: row.lastError ?? undefined,
|
||||
meta: (row.meta ?? {}) as Prisma.JsonObject,
|
||||
meta: (row.meta ?? {}) as GatewayPrisma.JsonObject,
|
||||
createdAt: row.createdAt.toISOString(),
|
||||
updatedAt: row.updatedAt.toISOString(),
|
||||
});
|
||||
@@ -154,7 +154,7 @@ const buildProfileName = (profile: string, scenario: string): string =>
|
||||
`${profile}:${scenario}`;
|
||||
|
||||
export const createGatewayProfileRepository = (
|
||||
prisma: PrismaClient
|
||||
prisma: GatewayPrismaClient
|
||||
): GatewayProfileRepository => ({
|
||||
async listProfiles(): Promise<GatewayProfileRecord[]> {
|
||||
const gatewayProfile = prisma.gatewayProfile as unknown as GatewayProfileClient;
|
||||
@@ -187,7 +187,7 @@ export const createGatewayProfileRepository = (
|
||||
? new Date(input.scheduledStartAt)
|
||||
: null,
|
||||
buildCommitSha: input.buildCommitSha ?? null,
|
||||
meta: (input.meta ?? {}) as Prisma.JsonObject,
|
||||
meta: (input.meta ?? {}) as GatewayPrisma.JsonObject,
|
||||
},
|
||||
update: {
|
||||
apiPort: input.apiPort,
|
||||
@@ -211,7 +211,7 @@ export const createGatewayProfileRepository = (
|
||||
input.buildCommitSha === undefined
|
||||
? undefined
|
||||
: input.buildCommitSha,
|
||||
meta: input.meta ? (input.meta as Prisma.JsonObject) : undefined,
|
||||
meta: input.meta ? (input.meta as GatewayPrisma.JsonObject) : undefined,
|
||||
},
|
||||
});
|
||||
return mapProfile(row);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import fastify, { type FastifyRequest } from 'fastify';
|
||||
import cors from '@fastify/cors';
|
||||
import { fastifyTRPCPlugin } from '@trpc/server/adapters/fastify';
|
||||
import type { PrismaClient } from '@prisma/client';
|
||||
import {
|
||||
createPostgresConnector,
|
||||
createGatewayPostgresConnector,
|
||||
createRedisConnector,
|
||||
type GatewayPrismaClient,
|
||||
resolvePostgresConfigFromEnv,
|
||||
resolveRedisConfigFromEnv,
|
||||
} from '@sammo-ts/infra';
|
||||
@@ -22,13 +22,15 @@ import { RepositoryProfileStatusService } from './lobby/profileStatusService.js'
|
||||
|
||||
export const createGatewayApiServer = async () => {
|
||||
const config = resolveGatewayApiConfigFromEnv();
|
||||
const postgres = createPostgresConnector(resolvePostgresConfigFromEnv());
|
||||
const postgres = createGatewayPostgresConnector(
|
||||
resolvePostgresConfigFromEnv({ schema: config.dbSchema })
|
||||
);
|
||||
const redis = createRedisConnector(resolveRedisConfigFromEnv());
|
||||
await postgres.connect();
|
||||
await redis.connect();
|
||||
|
||||
const users = createPostgresUserRepository(
|
||||
postgres.prisma as PrismaClient
|
||||
postgres.prisma as GatewayPrismaClient
|
||||
);
|
||||
const sessions = new RedisGatewaySessionService(redis.client, {
|
||||
keyPrefix: config.redisKeyPrefix,
|
||||
@@ -48,7 +50,7 @@ export const createGatewayApiServer = async () => {
|
||||
);
|
||||
|
||||
const { orchestrator, profiles } = createGatewayOrchestrator(
|
||||
postgres.prisma as PrismaClient,
|
||||
postgres.prisma as GatewayPrismaClient,
|
||||
config,
|
||||
process.env
|
||||
);
|
||||
@@ -82,7 +84,7 @@ export const createGatewayApiServer = async () => {
|
||||
profileStatus,
|
||||
adminToken: config.adminToken,
|
||||
requestHeaders: req.headers,
|
||||
prisma: postgres.prisma as PrismaClient,
|
||||
prisma: postgres.prisma as GatewayPrismaClient,
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user