feat: refactor database connection handling and add legacy map loading functionality

- Updated check-connections.mts to use Prisma with PostgreSQL adapter.
- Introduced databaseUrl.ts for resolving database URLs from environment variables.
- Added legacyMapLoader.ts to load and parse legacy map data.
- Implemented scenarioSeeder.ts to seed scenario data into the database.
- Created tests for scenario seeding in scenarioSeeder.test.ts.
- Configured Prisma datasource in prisma.config.ts to support dynamic database URLs.
This commit is contained in:
2025-12-29 05:49:25 +00:00
parent 7124483001
commit 9fe4c8f96c
12 changed files with 1863 additions and 81 deletions
+3 -1
View File
@@ -12,7 +12,9 @@
},
"dependencies": {
"@sammo-ts/common": "workspace:*",
"@sammo-ts/logic": "workspace:*"
"@sammo-ts/infra": "workspace:*",
"@sammo-ts/logic": "workspace:*",
"@prisma/client": "^7.2.0"
},
"devDependencies": {
"tsdown": "^0.18.3",
+3
View File
@@ -4,3 +4,6 @@ export * from './lifecycle/inMemoryControlQueue.js';
export * from './lifecycle/turnDaemonLifecycle.js';
export * from './lifecycle/getNextTickTime.js';
export * from './scenario/scenarioLoader.js';
export * from './scenario/databaseUrl.js';
export * from './scenario/legacyMapLoader.js';
export * from './scenario/scenarioSeeder.js';
@@ -0,0 +1,70 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const DEFAULT_ENV_FILE = path.resolve(__dirname, '..', '..', '..', '..', '.env.ci');
type EnvMap = Record<string, string | undefined>;
export interface DatabaseUrlOptions {
envFile?: string;
env?: NodeJS.ProcessEnv;
}
const parseEnvFile = (rawText: string): EnvMap => {
const env: EnvMap = {};
const lines = rawText.split(/\r?\n/);
for (const line of lines) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith('#')) {
continue;
}
const index = trimmed.indexOf('=');
if (index < 0) {
continue;
}
const key = trimmed.slice(0, index).trim();
let value = trimmed.slice(index + 1).trim();
if (
(value.startsWith('"') && value.endsWith('"')) ||
(value.startsWith("'") && value.endsWith("'"))
) {
value = value.slice(1, -1);
}
env[key] = value;
}
return env;
};
const loadEnvFile = async (envFile: string): Promise<EnvMap> => {
try {
const text = await fs.readFile(envFile, 'utf8');
return parseEnvFile(text);
} catch {
return {};
}
};
export const resolveDatabaseUrl = async (
options?: DatabaseUrlOptions
): Promise<string> => {
const env = options?.env ?? process.env;
if (env.DATABASE_URL) {
return env.DATABASE_URL;
}
const envFile = options?.envFile ?? DEFAULT_ENV_FILE;
const fileEnv = await loadEnvFile(envFile);
if (fileEnv.DATABASE_URL) {
return fileEnv.DATABASE_URL;
}
const host = env.POSTGRES_HOST ?? fileEnv.POSTGRES_HOST ?? '127.0.0.1';
const port = env.POSTGRES_PORT ?? fileEnv.POSTGRES_PORT ?? '15432';
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`;
};
@@ -0,0 +1,427 @@
import fs from 'node:fs/promises';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import type {
MapCityDefinition,
MapCityStats,
MapDefinition,
} from '@sammo-ts/logic';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const DEFAULT_LEGACY_MAP_ROOT = path.resolve(
__dirname,
'..',
'..',
'..',
'..',
'legacy',
'hwe',
'scenario',
'map'
);
const DEFAULT_LEGACY_BASE_FILE = path.resolve(
__dirname,
'..',
'..',
'..',
'..',
'legacy',
'hwe',
'sammo',
'CityConstBase.php'
);
const LEVEL_MAP: Record<string, number> = {
'수': 1,
'진': 2,
'관': 3,
'이': 4,
'소': 5,
'중': 6,
'대': 7,
'특': 8,
};
const LEVEL_LABELS: Record<number, string> = Object.entries(LEVEL_MAP)
.reduce<Record<number, string>>((acc, [label, value]) => {
acc[value] = label;
return acc;
}, {});
const REGION_MAP: Record<string, number> = {
'하북': 1,
'중원': 2,
'서북': 3,
'서촉': 4,
'남중': 5,
'초': 6,
'오월': 7,
'동이': 8,
};
const BUILD_INIT_COMMON = {
trust: 50,
trade: 100,
};
const BUILD_INIT: Record<string, MapCityStats> = {
'수': {
population: 5000,
agriculture: 100,
commerce: 100,
security: 100,
defence: 500,
wall: 500,
},
'진': {
population: 5000,
agriculture: 100,
commerce: 100,
security: 100,
defence: 500,
wall: 500,
},
'관': {
population: 10000,
agriculture: 100,
commerce: 100,
security: 100,
defence: 1000,
wall: 1000,
},
'이': {
population: 50000,
agriculture: 1000,
commerce: 1000,
security: 1000,
defence: 1000,
wall: 1000,
},
'소': {
population: 100000,
agriculture: 1000,
commerce: 1000,
security: 1000,
defence: 2000,
wall: 2000,
},
'중': {
population: 100000,
agriculture: 1000,
commerce: 1000,
security: 1000,
defence: 3000,
wall: 3000,
},
'대': {
population: 150000,
agriculture: 1000,
commerce: 1000,
security: 1000,
defence: 4000,
wall: 4000,
},
'특': {
population: 150000,
agriculture: 1000,
commerce: 1000,
security: 1000,
defence: 5000,
wall: 5000,
},
};
const DEFAULT_SUPPLY_STATE = 1;
const DEFAULT_FRONT_STATE = 0;
interface LegacyCityRow {
id: number;
name: string;
level: string | number;
population: number;
agriculture: number;
commerce: number;
security: number;
defence: number;
wall: number;
region: string | number;
positionX: number;
positionY: number;
connectionNames: string[];
}
export interface LegacyMapLoaderOptions {
mapRoot?: string;
baseFilePath?: string;
}
const readFileOrNull = async (filePath: string): Promise<string | null> => {
try {
return await fs.readFile(filePath, 'utf8');
} catch {
return null;
}
};
const extractPhpArray = (source: string, marker: string): string | null => {
const markerIndex = source.indexOf(marker);
if (markerIndex < 0) {
return null;
}
const start = source.indexOf('[', markerIndex);
if (start < 0) {
return null;
}
let depth = 0;
let inString: '"' | "'" | null = null;
for (let i = start; i < source.length; i += 1) {
const char = source[i];
if (inString) {
if (char === '\\') {
i += 1;
continue;
}
if (char === inString) {
inString = null;
}
continue;
}
if (char === '"' || char === "'") {
inString = char;
continue;
}
if (char === '[') {
depth += 1;
continue;
}
if (char === ']') {
depth -= 1;
if (depth === 0) {
return source.slice(start, i + 1);
}
}
}
return null;
};
const stripPhpComments = (source: string): string =>
source
.replace(/\/\*[\s\S]*?\*\//g, '')
.replace(/\/\/.*$/gm, '')
.replace(/#.*$/gm, '');
const normalizePhpArray = (source: string): string =>
stripPhpComments(source)
.replace(/\bNULL\b/gi, 'null')
.replace(/'/g, '"')
.replace(/,(\s*[\]\}])/g, '$1');
const parseLegacyCityRows = (value: unknown): LegacyCityRow[] => {
if (!Array.isArray(value)) {
throw new Error('Legacy map data is not an array.');
}
return value.map((row, index) => {
if (!Array.isArray(row)) {
throw new Error(`Legacy map row ${index} is not an array.`);
}
const [
id,
name,
level,
population,
agriculture,
commerce,
security,
defence,
wall,
region,
positionX,
positionY,
connections,
] = row;
if (typeof id !== 'number' || typeof name !== 'string') {
throw new Error(`Legacy map row ${index} has invalid id/name.`);
}
if (
typeof level !== 'string' &&
typeof level !== 'number'
) {
throw new Error(`Legacy map row ${index} has invalid level.`);
}
const stats = [
population,
agriculture,
commerce,
security,
defence,
wall,
];
if (stats.some((value) => typeof value !== 'number')) {
throw new Error(`Legacy map row ${index} has invalid stats.`);
}
if (
typeof region !== 'string' &&
typeof region !== 'number'
) {
throw new Error(`Legacy map row ${index} has invalid region.`);
}
if (
typeof positionX !== 'number' ||
typeof positionY !== 'number'
) {
throw new Error(`Legacy map row ${index} has invalid position.`);
}
const connectionNames = Array.isArray(connections)
? connections.filter(
(value): value is string => typeof value === 'string'
)
: [];
return {
id,
name,
level,
population,
agriculture,
commerce,
security,
defence,
wall,
region,
positionX,
positionY,
connectionNames,
};
});
};
const resolveLevelLabel = (level: string | number): string => {
if (typeof level === 'string') {
return level;
}
const label = LEVEL_LABELS[level];
if (!label) {
throw new Error(`Unknown level value: ${level}`);
}
return label;
};
const resolveLevelValue = (level: string | number): number => {
if (typeof level === 'number') {
return level;
}
const value = LEVEL_MAP[level];
if (!value) {
throw new Error(`Unknown level label: ${level}`);
}
return value;
};
const resolveRegionValue = (region: string | number): number => {
if (typeof region === 'number') {
return region;
}
const value = REGION_MAP[region];
if (!value) {
throw new Error(`Unknown region label: ${region}`);
}
return value;
};
const buildCityDefinition = (
row: LegacyCityRow,
nameToId: Map<string, number>
): MapCityDefinition => {
const levelLabel = resolveLevelLabel(row.level);
const initial = BUILD_INIT[levelLabel];
if (!initial) {
throw new Error(`Missing build init for level ${levelLabel}.`);
}
const connections = row.connectionNames
.map((name) => nameToId.get(name))
.filter((value): value is number => typeof value === 'number');
return {
id: row.id,
name: row.name,
level: resolveLevelValue(row.level),
region: resolveRegionValue(row.region),
position: {
x: row.positionX,
y: row.positionY,
},
connections,
max: {
population: row.population * 100,
agriculture: row.agriculture * 100,
commerce: row.commerce * 100,
security: row.security * 100,
defence: row.defence * 100,
wall: row.wall * 100,
},
initial,
meta: {
source: 'legacy',
connectionNames: row.connectionNames,
},
};
};
export const loadLegacyMapDefinition = async (
mapName: string,
options?: LegacyMapLoaderOptions
): Promise<MapDefinition> => {
const mapRoot = options?.mapRoot ?? DEFAULT_LEGACY_MAP_ROOT;
const baseFilePath = options?.baseFilePath ?? DEFAULT_LEGACY_BASE_FILE;
const mapFilePath = path.resolve(mapRoot, `${mapName}.php`);
const [mapSource, baseSource] = await Promise.all([
readFileOrNull(mapFilePath),
readFileOrNull(baseFilePath),
]);
if (!baseSource) {
throw new Error(`Legacy base map file is missing: ${baseFilePath}`);
}
const mapInitCity =
(mapSource
? extractPhpArray(mapSource, 'protected static $initCity')
: null) ??
extractPhpArray(baseSource, 'protected static $initCity');
if (!mapInitCity) {
throw new Error(`Legacy map data not found for ${mapName}.`);
}
const parsed = JSON.parse(normalizePhpArray(mapInitCity)) as unknown;
const rows = parseLegacyCityRows(parsed);
const nameToId = new Map(rows.map((row) => [row.name, row.id]));
return {
id: mapName,
name: mapName,
cities: rows.map((row) => buildCityDefinition(row, nameToId)),
defaults: {
trust: BUILD_INIT_COMMON.trust,
trade: BUILD_INIT_COMMON.trade,
supplyState: DEFAULT_SUPPLY_STATE,
frontState: DEFAULT_FRONT_STATE,
},
meta: {
source: 'legacy',
mapName,
},
};
};
@@ -0,0 +1,268 @@
import type { Prisma } from '@prisma/client';
import { createPostgresConnector } from '@sammo-ts/infra';
import {
buildScenarioBootstrap,
type ScenarioBootstrapWarning,
type WorldSeedPayload,
} from '@sammo-ts/logic';
import type { LegacyMapLoaderOptions } from './legacyMapLoader.js';
import { loadLegacyMapDefinition } from './legacyMapLoader.js';
import type { ScenarioLoaderOptions } from './scenarioLoader.js';
import { loadScenarioDefinitionById } from './scenarioLoader.js';
const DEFAULT_TICK_SECONDS = 120 * 60;
const DEFAULT_GENERAL_GOLD = 1000;
const DEFAULT_GENERAL_RICE = 1000;
export interface ScenarioSeedOptions {
scenarioId: number;
databaseUrl: string;
scenarioOptions?: ScenarioLoaderOptions;
mapOptions?: LegacyMapLoaderOptions;
resetTables?: boolean;
now?: Date;
tickSeconds?: number;
includeNeutralNationInSeed?: boolean;
defaultGeneralGold?: number;
defaultGeneralRice?: number;
}
export interface ScenarioSeedResult {
seed: WorldSeedPayload;
warnings: ScenarioBootstrapWarning[];
}
const asJson = (value: unknown): Prisma.InputJsonValue =>
value as Prisma.InputJsonValue;
const resolveGeneralAge = (
startYear: number | null,
birthYear: number
): number => {
if (startYear === null || birthYear <= 0) {
return 20;
}
return Math.max(startYear - birthYear, 0);
};
const buildEventRows = (
rows: unknown[],
targetOverride?: string
): Prisma.EventCreateManyInput[] => {
const result: Prisma.EventCreateManyInput[] = [];
for (const row of rows) {
if (!Array.isArray(row)) {
continue;
}
if (targetOverride) {
const [condition, ...actions] = row;
result.push({
targetCode: targetOverride,
priority: 0,
condition: asJson(condition ?? null),
action: asJson(actions),
meta: asJson({ source: targetOverride }),
});
continue;
}
const [target, priority, condition, ...actions] = row;
if (typeof target !== 'string' || typeof priority !== 'number') {
continue;
}
result.push({
targetCode: target,
priority,
condition: asJson(condition ?? null),
action: asJson(actions),
meta: asJson({ source: 'scenario' }),
});
}
return result;
};
// 시나리오 초기 데이터를 로드해 DB에 저장한다.
export const seedScenarioToDatabase = async (
options: ScenarioSeedOptions
): Promise<ScenarioSeedResult> => {
const scenario = await loadScenarioDefinitionById(
options.scenarioId,
options.scenarioOptions
);
const map = await loadLegacyMapDefinition(
scenario.config.environment.mapName,
options.mapOptions
);
const { seed, warnings } = buildScenarioBootstrap({
scenario,
map,
options: {
includeNeutralNationInSeed:
options.includeNeutralNationInSeed ?? true,
},
});
const connector = createPostgresConnector({ url: options.databaseUrl });
const now = options.now ?? new Date();
const tickSeconds = options.tickSeconds ?? DEFAULT_TICK_SECONDS;
const generalGold = options.defaultGeneralGold ?? DEFAULT_GENERAL_GOLD;
const generalRice = options.defaultGeneralRice ?? DEFAULT_GENERAL_RICE;
await connector.connect();
try {
const prisma = connector.prisma;
if (options.resetTables ?? true) {
await prisma.event.deleteMany();
await prisma.diplomacy.deleteMany();
await prisma.general.deleteMany();
await prisma.city.deleteMany();
await prisma.nation.deleteMany();
await prisma.worldState.deleteMany();
}
await prisma.worldState.create({
data: {
scenarioCode: String(options.scenarioId),
currentYear: scenario.startYear ?? 0,
currentMonth: 1,
tickSeconds,
config: asJson(seed.scenarioConfig),
meta: asJson({
scenarioId: options.scenarioId,
scenarioMeta: seed.scenarioMeta,
}),
},
});
if (seed.nations.length > 0) {
await prisma.nation.createMany({
data: seed.nations.map((nation) => ({
id: nation.id,
name: nation.name,
color: nation.color,
capitalCityId: nation.capitalCityId ?? null,
gold: nation.gold,
rice: nation.rice,
tech: nation.tech,
level: nation.level,
typeCode: nation.typeCode,
meta: asJson({
infoText: nation.infoText,
cityIds: nation.cityIds,
}),
})),
});
}
if (seed.cities.length > 0) {
await prisma.city.createMany({
data: seed.cities.map((city) => ({
id: city.id,
name: city.name,
level: city.level,
nationId: city.nationId,
supplyState: city.supplyState,
frontState: city.frontState,
population: city.population,
populationMax: city.populationMax,
agriculture: city.agriculture,
agricultureMax: city.agricultureMax,
commerce: city.commerce,
commerceMax: city.commerceMax,
security: city.security,
securityMax: city.securityMax,
trust: city.trust,
trade: city.trade,
defence: city.defence,
defenceMax: city.defenceMax,
wall: city.wall,
wallMax: city.wallMax,
region: city.region,
conflict: asJson({}),
meta: asJson({
position: city.position,
connections: city.connections,
...city.meta,
}),
})),
});
}
if (seed.generals.length > 0) {
await prisma.general.createMany({
data: seed.generals.map((general) => ({
id: general.id,
name: general.name,
nationId: general.nationId,
cityId: general.cityId,
npcState: general.npcType,
affinity: general.affinity,
bornYear: general.birthYear,
deadYear: general.deathYear,
picture:
general.picture === null
? null
: String(general.picture),
leadership: general.stats.leadership,
strength: general.stats.strength,
intel: general.stats.intelligence,
officerLevel: general.officerLevel,
gold: generalGold,
rice: generalRice,
crewTypeId: general.crewTypeId,
horseCode: general.horse ?? 'None',
weaponCode: general.weapon ?? 'None',
bookCode: general.book ?? 'None',
itemCode: general.item ?? 'None',
turnTime: now,
age: resolveGeneralAge(
scenario.startYear ?? null,
general.birthYear
),
personalCode: general.personality ?? 'None',
specialCode: general.special ?? 'None',
special2Code: general.specialWar ?? 'None',
lastTurn: asJson({}),
meta: asJson({
npcType: general.npcType,
crewTypeId: general.crewTypeId,
...general.meta,
}),
penalty: asJson({}),
})),
});
}
if (seed.diplomacy.length > 0) {
await prisma.diplomacy.createMany({
data: seed.diplomacy.map((row) => ({
srcNationId: row.fromNationId,
destNationId: row.toNationId,
stateCode: row.state,
term: row.durationMonths,
meta: asJson({}),
})),
});
}
const eventRows = [
...buildEventRows(seed.events),
...buildEventRows(seed.initialEvents, 'initial'),
];
if (eventRows.length > 0) {
await prisma.event.createMany({
data: eventRows,
});
}
} finally {
await connector.disconnect();
}
return { seed, warnings };
};
@@ -0,0 +1,71 @@
import { createPostgresConnector } from '@sammo-ts/infra';
import { resolveDatabaseUrl } from '../src/scenario/databaseUrl.js';
import { seedScenarioToDatabase } from '../src/scenario/scenarioSeeder.js';
const scenarioId = 1010;
const databaseUrl = await resolveDatabaseUrl();
const canConnectToDatabase = async (url: string): Promise<boolean> => {
const connector = createPostgresConnector({ url });
try {
await connector.connect();
await connector.prisma.$queryRawUnsafe('SELECT 1');
return true;
} catch {
return false;
} finally {
await connector.disconnect();
}
};
const canRun = await canConnectToDatabase(databaseUrl);
const describeDb = describe.runIf(canRun);
describeDb('scenario database seed', () => {
test('writes scenario data into tables', async () => {
const { seed } = await seedScenarioToDatabase({
scenarioId,
databaseUrl,
});
const connector = createPostgresConnector({ url: databaseUrl });
await connector.connect();
try {
const prisma = connector.prisma;
const [
nationCount,
cityCount,
generalCount,
diplomacyCount,
] = await Promise.all([
prisma.nation.count(),
prisma.city.count(),
prisma.general.count(),
prisma.diplomacy.count(),
]);
expect(nationCount).toBe(seed.nations.length);
expect(cityCount).toBe(seed.cities.length);
expect(generalCount).toBe(seed.generals.length);
expect(diplomacyCount).toBe(seed.diplomacy.length);
expect(generalCount).toBeGreaterThan(0);
if (seed.diplomacy.length > 0) {
const sample = seed.diplomacy[0];
const row = await prisma.diplomacy.findFirst({
where: {
srcNationId: sample.fromNationId,
destNationId: sample.toNationId,
},
});
expect(row).not.toBeNull();
if (row) {
expect(row.stateCode).toBe(sample.state);
}
}
} finally {
await connector.disconnect();
}
});
});
+5 -2
View File
@@ -13,11 +13,14 @@
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@prisma/client": "^5.18.0",
"@prisma/adapter-pg": "^7.2.0",
"@prisma/client": "^7.2.0",
"pg": "^8.16.3",
"redis": "^4.7.0"
},
"devDependencies": {
"prisma": "^5.18.0",
"dotenv": "^17.2.3",
"prisma": "^7.2.0",
"tsdown": "^0.18.3"
}
}
+22
View File
@@ -0,0 +1,22 @@
import 'dotenv/config';
import { defineConfig } from 'prisma/config';
const buildDatabaseUrlFromEnv = (): string => {
const host = process.env.POSTGRES_HOST ?? '127.0.0.1';
const port = process.env.POSTGRES_PORT ?? '15432';
const user = process.env.POSTGRES_USER ?? 'sammo';
const password = process.env.POSTGRES_PASSWORD ?? '';
const dbName = process.env.POSTGRES_DB ?? 'sammo';
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
};
const databaseUrl =
process.env.DATABASE_URL ?? buildDatabaseUrlFromEnv();
export default defineConfig({
schema: 'prisma/schema.prisma',
datasource: {
url: databaseUrl,
},
});
+127 -2
View File
@@ -4,7 +4,132 @@ generator client {
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// TODO: Translate docs/architecture/postgres-schema.md into Prisma models.
model WorldState {
id Int @id @default(autoincrement())
scenarioCode String @map("scenario_code")
currentYear Int @map("current_year")
currentMonth Int @map("current_month")
tickSeconds Int @map("tick_seconds")
config Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
updatedAt DateTime @updatedAt @map("updated_at")
@@map("world_state")
}
model Nation {
id Int @id
name String
color String
capitalCityId Int? @map("capital_city_id")
gold Int @default(0)
rice Int @default(0)
tech Float @default(0)
level Int @default(0)
typeCode String @default("che_중립") @map("type_code")
meta Json @default(dbgenerated("'{}'::jsonb"))
@@map("nation")
}
model City {
id Int @id
name String
level Int
nationId Int @default(0) @map("nation_id")
supplyState Int @default(1) @map("supply_state")
frontState Int @default(0) @map("front_state")
population Int @map("pop")
populationMax Int @map("pop_max")
agriculture Int @map("agri")
agricultureMax Int @map("agri_max")
commerce Int @map("comm")
commerceMax Int @map("comm_max")
security Int @map("secu")
securityMax Int @map("secu_max")
trust Int @default(0)
trade Int @default(100)
defence Int @map("def")
defenceMax Int @map("def_max")
wall Int @map("wall")
wallMax Int @map("wall_max")
region Int
conflict Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
@@map("city")
}
model General {
id Int @id
name String
nationId Int @default(0) @map("nation_id")
cityId Int @default(0) @map("city_id")
troopId Int @default(0) @map("troop_id")
npcState Int @default(0) @map("npc_state")
affinity Int?
bornYear Int @default(180) @map("born_year")
deadYear Int @default(300) @map("dead_year")
picture String?
imageServer Int @default(0) @map("image_server")
leadership Int @default(50)
strength Int @default(50)
intel Int @default(50)
injury Int @default(0)
experience Int @default(0)
dedication Int @default(0)
officerLevel Int @default(0) @map("officer_level")
gold Int @default(1000)
rice Int @default(1000)
crew Int @default(0)
crewTypeId Int @default(0) @map("crew_type_id")
train Int @default(0)
atmos Int @default(0)
weaponCode String @default("None") @map("weapon_code")
bookCode String @default("None") @map("book_code")
horseCode String @default("None") @map("horse_code")
itemCode String @default("None") @map("item_code")
turnTime DateTime @map("turn_time")
recentWarTime DateTime? @map("recent_war_time")
age Int @default(20)
startAge Int @default(20) @map("start_age")
personalCode String @default("None") @map("personal_code")
specialCode String @default("None") @map("special_code")
special2Code String @default("None") @map("special2_code")
lastTurn Json @default(dbgenerated("'{}'::jsonb")) @map("last_turn")
meta Json @default(dbgenerated("'{}'::jsonb"))
penalty Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @default(now()) @map("updated_at")
@@map("general")
}
model Diplomacy {
id Int @id @default(autoincrement())
srcNationId Int @map("src_nation_id")
destNationId Int @map("dest_nation_id")
stateCode Int @map("state_code")
term Int @default(0)
isDead Boolean @default(false) @map("is_dead")
isShowing Boolean @default(true) @map("is_showing")
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
@@unique([srcNationId, destNationId])
@@map("diplomacy")
}
model Event {
id Int @id @default(autoincrement())
targetCode String @map("target_code")
priority Int @default(0)
condition Json @default(dbgenerated("'{}'::jsonb"))
action Json @default(dbgenerated("'{}'::jsonb"))
meta Json @default(dbgenerated("'{}'::jsonb"))
createdAt DateTime @default(now()) @map("created_at")
@@map("event")
}
+23 -7
View File
@@ -1,4 +1,6 @@
import { Prisma, PrismaClient } from '@prisma/client';
import { PrismaPg } from '@prisma/adapter-pg';
import { Pool } from 'pg';
export interface PostgresConfig {
url: string;
@@ -11,10 +13,21 @@ export interface PostgresConnector {
disconnect(): Promise<void>;
}
const buildDatabaseUrlFromEnv = (
env: NodeJS.ProcessEnv
): string => {
const host = env.POSTGRES_HOST ?? '127.0.0.1';
const port = env.POSTGRES_PORT ?? '15432';
const user = env.POSTGRES_USER ?? 'sammo';
const password = env.POSTGRES_PASSWORD ?? '';
const dbName = env.POSTGRES_DB ?? 'sammo';
return `postgresql://${user}:${password}@${host}:${port}/${dbName}?schema=public`;
};
export const resolvePostgresConfigFromEnv = (
env: NodeJS.ProcessEnv = process.env
): PostgresConfig => {
const url = env.DATABASE_URL ?? '';
const url = env.DATABASE_URL ?? buildDatabaseUrlFromEnv(env);
if (!url) {
throw new Error('DATABASE_URL is required to create a Postgres client.');
}
@@ -25,18 +38,21 @@ export const resolvePostgresConfigFromEnv = (
export const createPostgresConnector = (
config: PostgresConfig
): PostgresConnector => {
const pool = new Pool({
connectionString: config.url,
});
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({
datasources: {
db: {
url: config.url,
},
},
adapter,
log: config.log,
});
return {
prisma,
connect: () => prisma.$connect(),
disconnect: () => prisma.$disconnect(),
disconnect: async () => {
await prisma.$disconnect();
await pool.end();
},
};
};
+827 -54
View File
@@ -26,9 +26,15 @@ importers:
app/game-engine:
dependencies:
'@prisma/client':
specifier: ^7.2.0
version: 7.2.0(prisma@7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)
'@sammo-ts/common':
specifier: workspace:*
version: link:../../packages/common
'@sammo-ts/infra':
specifier: workspace:*
version: link:../../packages/infra
'@sammo-ts/logic':
specifier: workspace:*
version: link:../../packages/logic
@@ -38,10 +44,10 @@ importers:
version: 0.18.3(typescript@5.9.3)
vite-tsconfig-paths:
specifier: ^4.3.2
version: 4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27))
version: 4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1))
vitest:
specifier: ^4.0.16
version: 4.0.16(@types/node@20.19.27)
version: 4.0.16(@types/node@20.19.27)(jiti@2.6.1)
app/game-frontend: {}
@@ -64,20 +70,29 @@ importers:
version: 0.18.3(typescript@5.9.3)
vitest:
specifier: ^4.0.16
version: 4.0.16(@types/node@20.19.27)
version: 4.0.16(@types/node@20.19.27)(jiti@2.6.1)
packages/infra:
dependencies:
'@prisma/adapter-pg':
specifier: ^7.2.0
version: 7.2.0
'@prisma/client':
specifier: ^5.18.0
version: 5.22.0(prisma@5.22.0)
specifier: ^7.2.0
version: 7.2.0(prisma@7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)
pg:
specifier: ^8.16.3
version: 8.16.3
redis:
specifier: ^4.7.0
version: 4.7.1
devDependencies:
dotenv:
specifier: ^17.2.3
version: 17.2.3
prisma:
specifier: ^5.18.0
version: 5.22.0
specifier: ^7.2.0
version: 7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)
tsdown:
specifier: ^0.18.3
version: 0.18.3(typescript@5.9.3)
@@ -96,10 +111,10 @@ importers:
version: 0.18.3(typescript@5.9.3)
vite-tsconfig-paths:
specifier: ^4.3.2
version: 4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27))
version: 4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1))
vitest:
specifier: ^4.0.16
version: 4.0.16(@types/node@20.19.27)
version: 4.0.16(@types/node@20.19.27)(jiti@2.6.1)
tools/build-scripts: {}
@@ -126,6 +141,32 @@ packages:
resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==}
engines: {node: '>=6.9.0'}
'@chevrotain/cst-dts-gen@10.5.0':
resolution: {integrity: sha512-lhmC/FyqQ2o7pGK4Om+hzuDrm9rhFYIJ/AXoQBeongmn870Xeb0L6oGEiuR8nohFNL5sMaQEJWCxr1oIVIVXrw==}
'@chevrotain/gast@10.5.0':
resolution: {integrity: sha512-pXdMJ9XeDAbgOWKuD1Fldz4ieCs6+nLNmyVhe2gZVqoO7v8HXuHYs5OV2EzUtbuai37TlOAQHrTDvxMnvMJz3A==}
'@chevrotain/types@10.5.0':
resolution: {integrity: sha512-f1MAia0x/pAVPWH/T73BJVyO2XU5tI4/iE7cnxb7tqdNTNhQI3Uq3XkqcoteTmD4t1aM0LbHCJOhgIDn07kl2A==}
'@chevrotain/utils@10.5.0':
resolution: {integrity: sha512-hBzuU5+JjB2cqNZyszkDHZgOSrUUT8V3dhgRl8Q9Gp6dAj/H5+KILGjbhDpc3Iy9qmqlm/akuOI2ut9VUtzJxQ==}
'@electric-sql/pglite-socket@0.0.6':
resolution: {integrity: sha512-6RjmgzphIHIBA4NrMGJsjNWK4pu+bCWJlEWlwcxFTVY3WT86dFpKwbZaGWZV6C5Rd7sCk1Z0CI76QEfukLAUXw==}
hasBin: true
peerDependencies:
'@electric-sql/pglite': 0.3.2
'@electric-sql/pglite-tools@0.2.7':
resolution: {integrity: sha512-9dAccClqxx4cZB+Ar9B+FZ5WgxDc/Xvl9DPrTWv+dYTf0YNubLzi4wHHRGRGhrJv15XwnyKcGOZAP1VXSneSUg==}
peerDependencies:
'@electric-sql/pglite': 0.3.2
'@electric-sql/pglite@0.3.2':
resolution: {integrity: sha512-zfWWa+V2ViDCY/cmUfRqeWY1yLto+EpxjXnZzenB1TyxsTiXaTWeZFIZw6mac52BsuQm0RjCnisjBtdBaXOI6w==}
'@emnapi/core@1.7.1':
resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==}
@@ -291,6 +332,12 @@ packages:
cpu: [x64]
os: [win32]
'@hono/node-server@1.19.6':
resolution: {integrity: sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==}
engines: {node: '>=18.14.1'}
peerDependencies:
hono: ^4
'@jridgewell/gen-mapping@0.3.13':
resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==}
@@ -304,35 +351,73 @@ packages:
'@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@mrleebo/prisma-ast@0.12.1':
resolution: {integrity: sha512-JwqeCQ1U3fvccttHZq7Tk0m/TMC6WcFAQZdukypW3AzlJYKYTGNVd1ANU2GuhKnv4UQuOFj3oAl0LLG/gxFN1w==}
engines: {node: '>=16'}
'@napi-rs/wasm-runtime@1.1.0':
resolution: {integrity: sha512-Fq6DJW+Bb5jaWE69/qOE0D1TUN9+6uWhCeZpdnSBk14pjLcCWR7Q8n49PTSPHazM37JqrsdpEthXy2xn6jWWiA==}
'@oxc-project/types@0.103.0':
resolution: {integrity: sha512-bkiYX5kaXWwUessFRSoXFkGIQTmc6dLGdxuRTrC+h8PSnIdZyuXHHlLAeTmOue5Br/a0/a7dHH0Gca6eXn9MKg==}
'@prisma/client@5.22.0':
resolution: {integrity: sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==}
engines: {node: '>=16.13'}
'@prisma/adapter-pg@7.2.0':
resolution: {integrity: sha512-euIdQ13cRB2wZ3jPsnDnFhINquo1PYFPCg6yVL8b2rp3EdinQHsX9EDdCtRr489D5uhphcRk463OdQAFlsCr0w==}
'@prisma/client-runtime-utils@7.2.0':
resolution: {integrity: sha512-dn7oB53v0tqkB0wBdMuTNFNPdEbfICEUe82Tn9FoKAhJCUkDH+fmyEp0ClciGh+9Hp2Tuu2K52kth2MTLstvmA==}
'@prisma/client@7.2.0':
resolution: {integrity: sha512-JdLF8lWZ+LjKGKpBqyAlenxd/kXjd1Abf/xK+6vUA7R7L2Suo6AFTHFRpPSdAKCan9wzdFApsUpSa/F6+t1AtA==}
engines: {node: ^20.19 || ^22.12 || >=24.0}
peerDependencies:
prisma: '*'
typescript: '>=5.4.0'
peerDependenciesMeta:
prisma:
optional: true
typescript:
optional: true
'@prisma/debug@5.22.0':
resolution: {integrity: sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==}
'@prisma/config@7.2.0':
resolution: {integrity: sha512-qmvSnfQ6l/srBW1S7RZGfjTQhc44Yl3ldvU6y3pgmuLM+83SBDs6UQVgMtQuMRe9J3gGqB0RF8wER6RlXEr6jQ==}
'@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2':
resolution: {integrity: sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==}
'@prisma/debug@6.8.2':
resolution: {integrity: sha512-4muBSSUwJJ9BYth5N8tqts8JtiLT8QI/RSAzEogwEfpbYGFo9mYsInsVo8dqXdPO2+Rm5OG5q0qWDDE3nyUbVg==}
'@prisma/engines@5.22.0':
resolution: {integrity: sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==}
'@prisma/debug@7.2.0':
resolution: {integrity: sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==}
'@prisma/fetch-engine@5.22.0':
resolution: {integrity: sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==}
'@prisma/dev@0.17.0':
resolution: {integrity: sha512-6sGebe5jxX+FEsQTpjHLzvOGPn6ypFQprcs3jcuIWv1Xp/5v6P/rjfdvAwTkP2iF6pDx2tCd8vGLNWcsWzImTA==}
'@prisma/get-platform@5.22.0':
resolution: {integrity: sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==}
'@prisma/driver-adapter-utils@7.2.0':
resolution: {integrity: sha512-gzrUcbI9VmHS24Uf+0+7DNzdIw7keglJsD5m/MHxQOU68OhGVzlphQRobLiDMn8CHNA2XN8uugwKjudVtnfMVQ==}
'@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3':
resolution: {integrity: sha512-KezsjCZDsbjNR7SzIiVlUsn9PnLePI7r5uxABlwL+xoerurZTfgQVbIjvjF2sVr3Uc0ZcsnREw3F84HvbggGdA==}
'@prisma/engines@7.2.0':
resolution: {integrity: sha512-HUeOI/SvCDsHrR9QZn24cxxZcujOjcS3w1oW/XVhnSATAli5SRMOfp/WkG3TtT5rCxDA4xOnlJkW7xkho4nURA==}
'@prisma/fetch-engine@7.2.0':
resolution: {integrity: sha512-Z5XZztJ8Ap+wovpjPD2lQKnB8nWFGNouCrglaNFjxIWAGWz0oeHXwUJRiclIoSSXN/ptcs9/behptSk8d0Yy6w==}
'@prisma/get-platform@6.8.2':
resolution: {integrity: sha512-vXSxyUgX3vm1Q70QwzwkjeYfRryIvKno1SXbIqwSptKwqKzskINnDUcx85oX+ys6ooN2ATGSD0xN2UTfg6Zcow==}
'@prisma/get-platform@7.2.0':
resolution: {integrity: sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==}
'@prisma/query-plan-executor@6.18.0':
resolution: {integrity: sha512-jZ8cfzFgL0jReE1R10gT8JLHtQxjWYLiQ//wHmVYZ2rVkFHoh0DT8IXsxcKcFlfKN7ak7k6j0XMNn2xVNyr5cA==}
'@prisma/studio-core@0.9.0':
resolution: {integrity: sha512-xA2zoR/ADu/NCSQuriBKTh6Ps4XjU0bErkEcgMfnSGh346K1VI7iWKnoq1l2DoxUqiddPHIEWwtxJ6xCHG6W7g==}
peerDependencies:
'@types/react': ^18.0.0 || ^19.0.0
react: ^18.0.0 || ^19.0.0
react-dom: ^18.0.0 || ^19.0.0
'@quansync/fs@1.0.0':
resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==}
@@ -574,6 +659,9 @@ packages:
'@types/node@20.19.27':
resolution: {integrity: sha512-N2clP5pJhB2YnZJ3PIHFk5RkygRX5WO/5f0WC08tp0wd+sv0rsJk3MqWn3CbNmT2J505a5336jaQj4ph1AdMug==}
'@types/react@19.2.7':
resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==}
'@vitest/expect@4.0.16':
resolution: {integrity: sha512-eshqULT2It7McaJkQGLkPjPjNph+uevROGuIMJdG3V+0BSR2w9u6J9Lwu+E8cK5TETlfou8GRijhafIMhXsimA==}
@@ -615,9 +703,21 @@ packages:
resolution: {integrity: sha512-m1Q/RaVOnTp9JxPX+F+Zn7IcLYMzM8kZofDImfsKZd8MbR+ikdOzTeztStWqfrqIxZnYWryyI9ePm3NGjnZgGw==}
engines: {node: '>=20.19.0'}
aws-ssl-profiles@1.1.2:
resolution: {integrity: sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==}
engines: {node: '>= 6.0.0'}
birpc@4.0.0:
resolution: {integrity: sha512-LShSxJP0KTmd101b6DRyGBj57LZxSDYWKitQNW/mi8GRMvZb078Uf9+pveax1DrVL89vm7mWe+TovdI/UDOuPw==}
c12@3.1.0:
resolution: {integrity: sha512-uWoS8OU1MEIsOv8p/5a82c3H31LsWVR5qiyXVfBNOzfffjUWtPnhAb4BYI2uG2HfGmZmFjCtui5XNWaps+iFuw==}
peerDependencies:
magicast: ^0.3.5
peerDependenciesMeta:
magicast:
optional: true
cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@@ -626,10 +726,34 @@ packages:
resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==}
engines: {node: '>=18'}
chevrotain@10.5.0:
resolution: {integrity: sha512-Pkv5rBY3+CsHOYfV5g/Vs5JY9WTHHDEKOlohI2XeygaZhUeqhAlldZ8Hz9cRmxu709bvS08YzxHdTPHhffc13A==}
chokidar@4.0.3:
resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==}
engines: {node: '>= 14.16.0'}
citty@0.1.6:
resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==}
cluster-key-slot@1.1.2:
resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==}
engines: {node: '>=0.10.0'}
confbox@0.2.2:
resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==}
consola@3.4.2:
resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==}
engines: {node: ^14.18.0 || >=16.10.0}
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
csstype@3.2.3:
resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'}
@@ -639,9 +763,28 @@ packages:
supports-color:
optional: true
deepmerge-ts@7.1.5:
resolution: {integrity: sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==}
engines: {node: '>=16.0.0'}
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
denque@2.1.0:
resolution: {integrity: sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==}
engines: {node: '>=0.10'}
destr@2.0.5:
resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==}
dotenv@16.6.1:
resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==}
engines: {node: '>=12'}
dotenv@17.2.3:
resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==}
engines: {node: '>=12'}
dts-resolver@2.1.3:
resolution: {integrity: sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw==}
engines: {node: '>=20.19.0'}
@@ -651,6 +794,9 @@ packages:
oxc-resolver:
optional: true
effect@3.18.4:
resolution: {integrity: sha512-b1LXQJLe9D11wfnOKAk3PKxuqYshQ0Heez+y5pnkd3jLj1yx9QhM72zZ9uUrOQyNvrs2GZZd/3maL0ZV18YuDA==}
empathic@2.0.0:
resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==}
engines: {node: '>=14'}
@@ -670,6 +816,13 @@ packages:
resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==}
engines: {node: '>=12.0.0'}
exsolve@1.0.8:
resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==}
fast-check@3.23.2:
resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==}
engines: {node: '>=8.0.0'}
fdir@6.5.0:
resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==}
engines: {node: '>=12.0.0'}
@@ -679,28 +832,69 @@ packages:
picomatch:
optional: true
foreground-child@3.3.1:
resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==}
engines: {node: '>=14'}
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
generate-function@2.3.1:
resolution: {integrity: sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==}
generic-pool@3.9.0:
resolution: {integrity: sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==}
engines: {node: '>= 4'}
get-port-please@3.1.2:
resolution: {integrity: sha512-Gxc29eLs1fbn6LQ4jSU4vXjlwyZhF5HsGuMAa7gqBP4Rw4yxxltyDUuF5MBclFzDTXO+ACchGQoeela4DSfzdQ==}
get-tsconfig@4.13.0:
resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==}
giget@2.0.0:
resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==}
hasBin: true
globrex@0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
grammex@3.1.12:
resolution: {integrity: sha512-6ufJOsSA7LcQehIJNCO7HIBykfM7DXQual0Ny780/DEcJIpBlHRvcqEBWGPYd7hrXL2GJ3oJI1MIhaXjWmLQOQ==}
hono@4.10.6:
resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==}
engines: {node: '>=16.9.0'}
hookable@6.0.1:
resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==}
http-status-codes@2.3.0:
resolution: {integrity: sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==}
iconv-lite@0.7.1:
resolution: {integrity: sha512-2Tth85cXwGFHfvRgZWszZSvdo+0Xsqmw8k8ZwxScfcBneNUraK+dxRxRm24nszx80Y0TVio8kKLt5sLE7ZCLlw==}
engines: {node: '>=0.10.0'}
import-without-cache@0.2.5:
resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==}
engines: {node: '>=20.19.0'}
is-property@1.0.2:
resolution: {integrity: sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==}
isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
jiti@2.6.1:
resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==}
hasBin: true
js-sha512@0.9.0:
resolution: {integrity: sha512-mirki9WS/SUahm+1TbAPkqvbCiCfOAAsyXeHxK1UkullnJVVqoJG2pL9ObvT05CN+tM7fxhfYm0NbXn+1hWoZg==}
@@ -709,23 +903,97 @@ packages:
engines: {node: '>=6'}
hasBin: true
lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
lodash@4.17.21:
resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==}
long@5.3.2:
resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==}
lru.min@1.1.3:
resolution: {integrity: sha512-Lkk/vx6ak3rYkRR0Nhu4lFUT2VDnQSxBe8Hbl7f36358p6ow8Bnvr8lrLt98H8J1aGxfhbX4Fs5tYg2+FTwr5Q==}
engines: {bun: '>=1.0.0', deno: '>=1.30.0', node: '>=8.0.0'}
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
ms@2.1.3:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
mysql2@3.15.3:
resolution: {integrity: sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==}
engines: {node: '>= 8.0'}
named-placeholders@1.1.6:
resolution: {integrity: sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==}
engines: {node: '>=8.0.0'}
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
node-fetch-native@1.6.7:
resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==}
nypm@0.6.2:
resolution: {integrity: sha512-7eM+hpOtrKrBDCh7Ypu2lJ9Z7PNZBdi/8AT3AX8xoCj43BBVHD0hPSTEvMtkMpfs8FCqBGhxB+uToIQimA111g==}
engines: {node: ^14.16.0 || >=16.10.0}
hasBin: true
obug@2.1.1:
resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==}
ohash@2.0.11:
resolution: {integrity: sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==}
path-key@3.1.1:
resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
engines: {node: '>=8'}
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
perfect-debounce@1.0.0:
resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
pg-cloudflare@1.2.7:
resolution: {integrity: sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg==}
pg-connection-string@2.9.1:
resolution: {integrity: sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w==}
pg-int8@1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
pg-pool@3.10.1:
resolution: {integrity: sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg==}
peerDependencies:
pg: '>=8.0'
pg-protocol@1.10.3:
resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==}
pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
pg@8.16.3:
resolution: {integrity: sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw==}
engines: {node: '>= 16.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
peerDependenciesMeta:
pg-native:
optional: true
pgpass@1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
picocolors@1.1.1:
resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==}
@@ -733,24 +1001,91 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
pkg-types@2.3.0:
resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==}
postcss@8.5.6:
resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==}
engines: {node: ^10 || ^12 || >=14}
prisma@5.22.0:
resolution: {integrity: sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==}
engines: {node: '>=16.13'}
postgres-array@2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
postgres-array@3.0.4:
resolution: {integrity: sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==}
engines: {node: '>=12'}
postgres-bytea@1.0.1:
resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==}
engines: {node: '>=0.10.0'}
postgres-date@1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
postgres-interval@1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
postgres@3.4.7:
resolution: {integrity: sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==}
engines: {node: '>=12'}
prisma@7.2.0:
resolution: {integrity: sha512-jSdHWgWOgFF24+nRyyNRVBIgGDQEsMEF8KPHvhBBg3jWyR9fUAK0Nq9ThUmiGlNgq2FA7vSk/ZoCvefod+a8qg==}
engines: {node: ^20.19 || ^22.12 || >=24.0}
hasBin: true
peerDependencies:
better-sqlite3: '>=9.0.0'
typescript: '>=5.4.0'
peerDependenciesMeta:
better-sqlite3:
optional: true
typescript:
optional: true
proper-lockfile@4.1.2:
resolution: {integrity: sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==}
pure-rand@6.1.0:
resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==}
quansync@1.0.0:
resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
rc9@2.1.2:
resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==}
react-dom@19.2.3:
resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==}
peerDependencies:
react: ^19.2.3
react@19.2.3:
resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==}
engines: {node: '>=0.10.0'}
readdirp@4.1.2:
resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==}
engines: {node: '>= 14.18.0'}
redis@4.7.1:
resolution: {integrity: sha512-S1bJDnqLftzHXHP8JsT5II/CtHWQrASX5K96REjWjlmWKrviSOLWmM7QnRLstAWsu1VBBV1ffV6DzCvxNP0UJQ==}
regexp-to-ast@0.5.0:
resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==}
remeda@2.21.3:
resolution: {integrity: sha512-XXrZdLA10oEOQhLLzEJEiFFSKi21REGAkHdImIb4rt/XXy8ORGXh5HCcpUOsElfPNDb+X6TA/+wkh+p2KffYmg==}
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
retry@0.12.0:
resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==}
engines: {node: '>= 4'}
rolldown-plugin-dts@0.20.0:
resolution: {integrity: sha512-cLAY1kN2ilTYMfZcFlGWbXnu6Nb+8uwUBsi+Mjbh4uIx7IN8uMOmJ7RxrrRgPsO4H7eSz3E+JwGoL1gyugiyUA==}
engines: {node: '>=20.19.0'}
@@ -780,24 +1115,59 @@ packages:
engines: {node: '>=18.0.0', npm: '>=8.0.0'}
hasBin: true
safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
scheduler@0.27.0:
resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
semver@7.7.3:
resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==}
engines: {node: '>=10'}
hasBin: true
seq-queue@0.0.5:
resolution: {integrity: sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==}
shebang-command@2.0.0:
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
engines: {node: '>=8'}
shebang-regex@3.0.0:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'}
siginfo@2.0.0:
resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
split2@4.2.0:
resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==}
engines: {node: '>= 10.x'}
sqlstring@2.3.3:
resolution: {integrity: sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==}
engines: {node: '>= 0.6'}
stackback@0.0.2:
resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
std-env@3.10.0:
resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
std-env@3.9.0:
resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==}
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -855,6 +1225,10 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
type-fest@4.41.0:
resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==}
engines: {node: '>=16'}
typescript@5.9.3:
resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==}
engines: {node: '>=14.17'}
@@ -876,6 +1250,14 @@ packages:
synckit:
optional: true
valibot@1.2.0:
resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==}
peerDependencies:
typescript: '>=5'
peerDependenciesMeta:
typescript:
optional: true
vite-tsconfig-paths@4.3.2:
resolution: {integrity: sha512-0Vd/a6po6Q+86rPlntHye7F31zA2URZMbH8M3saAZ/xR9QoGN/L21bxEGfXdWmFdNkqPpRdxFT7nmNe12e9/uA==}
peerDependencies:
@@ -958,14 +1340,26 @@ packages:
jsdom:
optional: true
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
hasBin: true
why-is-node-running@2.3.0:
resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
engines: {node: '>=8'}
hasBin: true
xtend@4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
yallist@4.0.0:
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
zeptomatch@2.0.2:
resolution: {integrity: sha512-H33jtSKf8Ijtb5BW6wua3G5DhnFjbFML36eFu+VdOoVY4HD9e7ggjqdM6639B+L87rjnR6Y+XeRzBXZdy52B/g==}
zod@4.2.1:
resolution: {integrity: sha512-0wZ1IRqGGhMP76gLqz8EyfBXKk0J2qo2+H3fi4mcUP/KtTocoX08nmIAHl1Z2kJIZbZee8KOpBCSNPRgauucjw==}
@@ -992,6 +1386,31 @@ snapshots:
'@babel/helper-string-parser': 7.27.1
'@babel/helper-validator-identifier': 7.28.5
'@chevrotain/cst-dts-gen@10.5.0':
dependencies:
'@chevrotain/gast': 10.5.0
'@chevrotain/types': 10.5.0
lodash: 4.17.21
'@chevrotain/gast@10.5.0':
dependencies:
'@chevrotain/types': 10.5.0
lodash: 4.17.21
'@chevrotain/types@10.5.0': {}
'@chevrotain/utils@10.5.0': {}
'@electric-sql/pglite-socket@0.0.6(@electric-sql/pglite@0.3.2)':
dependencies:
'@electric-sql/pglite': 0.3.2
'@electric-sql/pglite-tools@0.2.7(@electric-sql/pglite@0.3.2)':
dependencies:
'@electric-sql/pglite': 0.3.2
'@electric-sql/pglite@0.3.2': {}
'@emnapi/core@1.7.1':
dependencies:
'@emnapi/wasi-threads': 1.1.0
@@ -1086,6 +1505,10 @@ snapshots:
'@esbuild/win32-x64@0.27.2':
optional: true
'@hono/node-server@1.19.6(hono@4.10.6)':
dependencies:
hono: 4.10.6
'@jridgewell/gen-mapping@0.3.13':
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -1100,6 +1523,11 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5
'@mrleebo/prisma-ast@0.12.1':
dependencies:
chevrotain: 10.5.0
lilconfig: 2.1.0
'@napi-rs/wasm-runtime@1.1.0':
dependencies:
'@emnapi/core': 1.7.1
@@ -1109,30 +1537,92 @@ snapshots:
'@oxc-project/types@0.103.0': {}
'@prisma/client@5.22.0(prisma@5.22.0)':
'@prisma/adapter-pg@7.2.0':
dependencies:
'@prisma/driver-adapter-utils': 7.2.0
pg: 8.16.3
postgres-array: 3.0.4
transitivePeerDependencies:
- pg-native
'@prisma/client-runtime-utils@7.2.0': {}
'@prisma/client@7.2.0(prisma@7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3))(typescript@5.9.3)':
dependencies:
'@prisma/client-runtime-utils': 7.2.0
optionalDependencies:
prisma: 5.22.0
prisma: 7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)
typescript: 5.9.3
'@prisma/debug@5.22.0': {}
'@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2': {}
'@prisma/engines@5.22.0':
'@prisma/config@7.2.0':
dependencies:
'@prisma/debug': 5.22.0
'@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2
'@prisma/fetch-engine': 5.22.0
'@prisma/get-platform': 5.22.0
c12: 3.1.0
deepmerge-ts: 7.1.5
effect: 3.18.4
empathic: 2.0.0
transitivePeerDependencies:
- magicast
'@prisma/fetch-engine@5.22.0':
dependencies:
'@prisma/debug': 5.22.0
'@prisma/engines-version': 5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2
'@prisma/get-platform': 5.22.0
'@prisma/debug@6.8.2': {}
'@prisma/get-platform@5.22.0':
'@prisma/debug@7.2.0': {}
'@prisma/dev@0.17.0(typescript@5.9.3)':
dependencies:
'@prisma/debug': 5.22.0
'@electric-sql/pglite': 0.3.2
'@electric-sql/pglite-socket': 0.0.6(@electric-sql/pglite@0.3.2)
'@electric-sql/pglite-tools': 0.2.7(@electric-sql/pglite@0.3.2)
'@hono/node-server': 1.19.6(hono@4.10.6)
'@mrleebo/prisma-ast': 0.12.1
'@prisma/get-platform': 6.8.2
'@prisma/query-plan-executor': 6.18.0
foreground-child: 3.3.1
get-port-please: 3.1.2
hono: 4.10.6
http-status-codes: 2.3.0
pathe: 2.0.3
proper-lockfile: 4.1.2
remeda: 2.21.3
std-env: 3.9.0
valibot: 1.2.0(typescript@5.9.3)
zeptomatch: 2.0.2
transitivePeerDependencies:
- typescript
'@prisma/driver-adapter-utils@7.2.0':
dependencies:
'@prisma/debug': 7.2.0
'@prisma/engines-version@7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3': {}
'@prisma/engines@7.2.0':
dependencies:
'@prisma/debug': 7.2.0
'@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3
'@prisma/fetch-engine': 7.2.0
'@prisma/get-platform': 7.2.0
'@prisma/fetch-engine@7.2.0':
dependencies:
'@prisma/debug': 7.2.0
'@prisma/engines-version': 7.2.0-4.0c8ef2ce45c83248ab3df073180d5eda9e8be7a3
'@prisma/get-platform': 7.2.0
'@prisma/get-platform@6.8.2':
dependencies:
'@prisma/debug': 6.8.2
'@prisma/get-platform@7.2.0':
dependencies:
'@prisma/debug': 7.2.0
'@prisma/query-plan-executor@6.18.0': {}
'@prisma/studio-core@0.9.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)':
dependencies:
'@types/react': 19.2.7
react: 19.2.3
react-dom: 19.2.3(react@19.2.3)
'@quansync/fs@1.0.0':
dependencies:
@@ -1293,6 +1783,10 @@ snapshots:
dependencies:
undici-types: 6.21.0
'@types/react@19.2.7':
dependencies:
csstype: 3.2.3
'@vitest/expect@4.0.16':
dependencies:
'@standard-schema/spec': 1.1.0
@@ -1302,13 +1796,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
'@vitest/mocker@4.0.16(vite@7.3.0(@types/node@20.19.27))':
'@vitest/mocker@4.0.16(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1))':
dependencies:
'@vitest/spy': 4.0.16
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
vite: 7.3.0(@types/node@20.19.27)
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)
'@vitest/pretty-format@4.0.16':
dependencies:
@@ -1341,22 +1835,83 @@ snapshots:
'@babel/parser': 7.28.5
pathe: 2.0.3
aws-ssl-profiles@1.1.2: {}
birpc@4.0.0: {}
c12@3.1.0:
dependencies:
chokidar: 4.0.3
confbox: 0.2.2
defu: 6.1.4
dotenv: 16.6.1
exsolve: 1.0.8
giget: 2.0.0
jiti: 2.6.1
ohash: 2.0.11
pathe: 2.0.3
perfect-debounce: 1.0.0
pkg-types: 2.3.0
rc9: 2.1.2
cac@6.7.14: {}
chai@6.2.2: {}
chevrotain@10.5.0:
dependencies:
'@chevrotain/cst-dts-gen': 10.5.0
'@chevrotain/gast': 10.5.0
'@chevrotain/types': 10.5.0
'@chevrotain/utils': 10.5.0
lodash: 4.17.21
regexp-to-ast: 0.5.0
chokidar@4.0.3:
dependencies:
readdirp: 4.1.2
citty@0.1.6:
dependencies:
consola: 3.4.2
cluster-key-slot@1.1.2: {}
confbox@0.2.2: {}
consola@3.4.2: {}
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
csstype@3.2.3: {}
debug@4.4.3:
dependencies:
ms: 2.1.3
deepmerge-ts@7.1.5: {}
defu@6.1.4: {}
denque@2.1.0: {}
destr@2.0.5: {}
dotenv@16.6.1: {}
dotenv@17.2.3: {}
dts-resolver@2.1.3: {}
effect@3.18.4:
dependencies:
'@standard-schema/spec': 1.1.0
fast-check: 3.23.2
empathic@2.0.0: {}
es-module-lexer@1.7.0: {}
@@ -1396,59 +1951,230 @@ snapshots:
expect-type@1.3.0: {}
exsolve@1.0.8: {}
fast-check@3.23.2:
dependencies:
pure-rand: 6.1.0
fdir@6.5.0(picomatch@4.0.3):
optionalDependencies:
picomatch: 4.0.3
foreground-child@3.3.1:
dependencies:
cross-spawn: 7.0.6
signal-exit: 4.1.0
fsevents@2.3.3:
optional: true
generate-function@2.3.1:
dependencies:
is-property: 1.0.2
generic-pool@3.9.0: {}
get-port-please@3.1.2: {}
get-tsconfig@4.13.0:
dependencies:
resolve-pkg-maps: 1.0.0
giget@2.0.0:
dependencies:
citty: 0.1.6
consola: 3.4.2
defu: 6.1.4
node-fetch-native: 1.6.7
nypm: 0.6.2
pathe: 2.0.3
globrex@0.1.2: {}
graceful-fs@4.2.11: {}
grammex@3.1.12: {}
hono@4.10.6: {}
hookable@6.0.1: {}
http-status-codes@2.3.0: {}
iconv-lite@0.7.1:
dependencies:
safer-buffer: 2.1.2
import-without-cache@0.2.5: {}
is-property@1.0.2: {}
isexe@2.0.0: {}
jiti@2.6.1: {}
js-sha512@0.9.0: {}
jsesc@3.1.0: {}
lilconfig@2.1.0: {}
lodash@4.17.21: {}
long@5.3.2: {}
lru.min@1.1.3: {}
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
ms@2.1.3: {}
mysql2@3.15.3:
dependencies:
aws-ssl-profiles: 1.1.2
denque: 2.1.0
generate-function: 2.3.1
iconv-lite: 0.7.1
long: 5.3.2
lru.min: 1.1.3
named-placeholders: 1.1.6
seq-queue: 0.0.5
sqlstring: 2.3.3
named-placeholders@1.1.6:
dependencies:
lru.min: 1.1.3
nanoid@3.3.11: {}
node-fetch-native@1.6.7: {}
nypm@0.6.2:
dependencies:
citty: 0.1.6
consola: 3.4.2
pathe: 2.0.3
pkg-types: 2.3.0
tinyexec: 1.0.2
obug@2.1.1: {}
ohash@2.0.11: {}
path-key@3.1.1: {}
pathe@2.0.3: {}
perfect-debounce@1.0.0: {}
pg-cloudflare@1.2.7:
optional: true
pg-connection-string@2.9.1: {}
pg-int8@1.0.1: {}
pg-pool@3.10.1(pg@8.16.3):
dependencies:
pg: 8.16.3
pg-protocol@1.10.3: {}
pg-types@2.2.0:
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.1
postgres-date: 1.0.7
postgres-interval: 1.2.0
pg@8.16.3:
dependencies:
pg-connection-string: 2.9.1
pg-pool: 3.10.1(pg@8.16.3)
pg-protocol: 1.10.3
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
pg-cloudflare: 1.2.7
pgpass@1.0.5:
dependencies:
split2: 4.2.0
picocolors@1.1.1: {}
picomatch@4.0.3: {}
pkg-types@2.3.0:
dependencies:
confbox: 0.2.2
exsolve: 1.0.8
pathe: 2.0.3
postcss@8.5.6:
dependencies:
nanoid: 3.3.11
picocolors: 1.1.1
source-map-js: 1.2.1
prisma@5.22.0:
postgres-array@2.0.0: {}
postgres-array@3.0.4: {}
postgres-bytea@1.0.1: {}
postgres-date@1.0.7: {}
postgres-interval@1.2.0:
dependencies:
'@prisma/engines': 5.22.0
xtend: 4.0.2
postgres@3.4.7: {}
prisma@7.2.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3):
dependencies:
'@prisma/config': 7.2.0
'@prisma/dev': 0.17.0(typescript@5.9.3)
'@prisma/engines': 7.2.0
'@prisma/studio-core': 0.9.0(@types/react@19.2.7)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)
mysql2: 3.15.3
postgres: 3.4.7
optionalDependencies:
fsevents: 2.3.3
typescript: 5.9.3
transitivePeerDependencies:
- '@types/react'
- magicast
- react
- react-dom
proper-lockfile@4.1.2:
dependencies:
graceful-fs: 4.2.11
retry: 0.12.0
signal-exit: 3.0.7
pure-rand@6.1.0: {}
quansync@1.0.0: {}
rc9@2.1.2:
dependencies:
defu: 6.1.4
destr: 2.0.5
react-dom@19.2.3(react@19.2.3):
dependencies:
react: 19.2.3
scheduler: 0.27.0
react@19.2.3: {}
readdirp@4.1.2: {}
redis@4.7.1:
dependencies:
'@redis/bloom': 1.2.0(@redis/client@1.6.1)
@@ -1458,8 +2184,16 @@ snapshots:
'@redis/search': 1.2.0(@redis/client@1.6.1)
'@redis/time-series': 1.1.0(@redis/client@1.6.1)
regexp-to-ast@0.5.0: {}
remeda@2.21.3:
dependencies:
type-fest: 4.41.0
resolve-pkg-maps@1.0.0: {}
retry@0.12.0: {}
rolldown-plugin-dts@0.20.0(rolldown@1.0.0-beta.57)(typescript@5.9.3):
dependencies:
'@babel/generator': 7.28.5
@@ -1523,16 +2257,38 @@ snapshots:
'@rollup/rollup-win32-x64-msvc': 4.54.0
fsevents: 2.3.3
safer-buffer@2.1.2: {}
scheduler@0.27.0: {}
semver@7.7.3: {}
seq-queue@0.0.5: {}
shebang-command@2.0.0:
dependencies:
shebang-regex: 3.0.0
shebang-regex@3.0.0: {}
siginfo@2.0.0: {}
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
source-map-js@1.2.1: {}
split2@4.2.0: {}
sqlstring@2.3.3: {}
stackback@0.0.2: {}
std-env@3.10.0: {}
std-env@3.9.0: {}
tinybench@2.9.0: {}
tinyexec@1.0.2: {}
@@ -1580,6 +2336,8 @@ snapshots:
tslib@2.8.1:
optional: true
type-fest@4.41.0: {}
typescript@5.9.3: {}
unconfig-core@7.4.2:
@@ -1593,18 +2351,22 @@ snapshots:
dependencies:
rolldown: 1.0.0-beta.57
vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)):
valibot@1.2.0(typescript@5.9.3):
optionalDependencies:
typescript: 5.9.3
vite-tsconfig-paths@4.3.2(typescript@5.9.3)(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.3)
optionalDependencies:
vite: 7.3.0(@types/node@20.19.27)
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)
transitivePeerDependencies:
- supports-color
- typescript
vite@7.3.0(@types/node@20.19.27):
vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1):
dependencies:
esbuild: 0.27.2
fdir: 6.5.0(picomatch@4.0.3)
@@ -1615,11 +2377,12 @@ snapshots:
optionalDependencies:
'@types/node': 20.19.27
fsevents: 2.3.3
jiti: 2.6.1
vitest@4.0.16(@types/node@20.19.27):
vitest@4.0.16(@types/node@20.19.27)(jiti@2.6.1):
dependencies:
'@vitest/expect': 4.0.16
'@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@20.19.27))
'@vitest/mocker': 4.0.16(vite@7.3.0(@types/node@20.19.27)(jiti@2.6.1))
'@vitest/pretty-format': 4.0.16
'@vitest/runner': 4.0.16
'@vitest/snapshot': 4.0.16
@@ -1636,7 +2399,7 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
vite: 7.3.0(@types/node@20.19.27)
vite: 7.3.0(@types/node@20.19.27)(jiti@2.6.1)
why-is-node-running: 2.3.0
optionalDependencies:
'@types/node': 20.19.27
@@ -1653,11 +2416,21 @@ snapshots:
- tsx
- yaml
which@2.0.2:
dependencies:
isexe: 2.0.0
why-is-node-running@2.3.0:
dependencies:
siginfo: 2.0.0
stackback: 0.0.2
xtend@4.0.2: {}
yallist@4.0.0: {}
zeptomatch@2.0.2:
dependencies:
grammex: 3.1.12
zod@4.2.1: {}
+17 -15
View File
@@ -7,17 +7,19 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const DEFAULT_ENV_FILE = path.resolve(__dirname, '..', '..', '.env.ci');
const COMMON_PACKAGE_JSON = path.resolve(
const INFRA_PACKAGE_JSON = path.resolve(
__dirname,
'..',
'..',
'packages',
'common',
'infra',
'package.json'
);
const commonRequire = createRequire(COMMON_PACKAGE_JSON);
const { PrismaClient } = commonRequire('@prisma/client');
const { createClient } = commonRequire('redis');
const infraRequire = createRequire(INFRA_PACKAGE_JSON);
const { PrismaClient } = infraRequire('@prisma/client');
const { PrismaPg } = infraRequire('@prisma/adapter-pg');
const { Pool } = infraRequire('pg');
const { createClient } = infraRequire('redis');
type EnvMap = Record<string, string | undefined>;
@@ -84,17 +86,17 @@ const resolveRedisUrl = (env: EnvMap): string => {
};
const testPostgres = async (databaseUrl: string): Promise<void> => {
const prisma = new PrismaClient({
datasources: {
db: {
url: databaseUrl,
},
},
});
const pool = new Pool({ connectionString: databaseUrl });
const adapter = new PrismaPg(pool);
const prisma = new PrismaClient({ adapter });
await prisma.$connect();
await prisma.$queryRawUnsafe('SELECT 1');
await prisma.$disconnect();
try {
await prisma.$connect();
await prisma.$queryRawUnsafe('SELECT 1');
} finally {
await prisma.$disconnect();
await pool.end();
}
};
const testRedis = async (redisUrl: string): Promise<void> => {