Update DEFAULT_LOCAL_CONFIG, VALID_STORAGE_TYPES, and repo-root mosaic.config.json to use pglite instead of sqlite, completing the storage dialect migration started in the previous commit. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
141 lines
4.6 KiB
TypeScript
141 lines
4.6 KiB
TypeScript
import { readFileSync, existsSync } from 'node:fs';
|
|
import { resolve } from 'node:path';
|
|
import type { StorageConfig } from '@mosaic/storage';
|
|
import type { QueueAdapterConfig as QueueConfig } from '@mosaic/queue';
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Types */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
export type StorageTier = 'local' | 'team';
|
|
|
|
export interface MemoryConfigRef {
|
|
type: 'pgvector' | 'sqlite-vec' | 'keyword';
|
|
}
|
|
|
|
export interface MosaicConfig {
|
|
tier: StorageTier;
|
|
storage: StorageConfig;
|
|
queue: QueueConfig;
|
|
memory: MemoryConfigRef;
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Defaults */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
export const DEFAULT_LOCAL_CONFIG: MosaicConfig = {
|
|
tier: 'local',
|
|
storage: { type: 'pglite', dataDir: '.mosaic/storage-pglite' },
|
|
queue: { type: 'local', dataDir: '.mosaic/queue' },
|
|
memory: { type: 'keyword' },
|
|
};
|
|
|
|
export const DEFAULT_TEAM_CONFIG: MosaicConfig = {
|
|
tier: 'team',
|
|
storage: { type: 'postgres', url: 'postgresql://mosaic:mosaic@localhost:5432/mosaic' },
|
|
queue: { type: 'bullmq' },
|
|
memory: { type: 'pgvector' },
|
|
};
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Validation */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
const VALID_TIERS = new Set<string>(['local', 'team']);
|
|
const VALID_STORAGE_TYPES = new Set<string>(['postgres', 'pglite', 'files']);
|
|
const VALID_QUEUE_TYPES = new Set<string>(['bullmq', 'local']);
|
|
const VALID_MEMORY_TYPES = new Set<string>(['pgvector', 'sqlite-vec', 'keyword']);
|
|
|
|
export function validateConfig(raw: unknown): MosaicConfig {
|
|
if (typeof raw !== 'object' || raw === null) {
|
|
throw new Error('MosaicConfig must be a non-null object');
|
|
}
|
|
|
|
const obj = raw as Record<string, unknown>;
|
|
|
|
// tier
|
|
const tier = obj['tier'];
|
|
if (typeof tier !== 'string' || !VALID_TIERS.has(tier)) {
|
|
throw new Error(`Invalid tier "${String(tier)}" — expected "local" or "team"`);
|
|
}
|
|
|
|
// storage
|
|
const storage = obj['storage'];
|
|
if (typeof storage !== 'object' || storage === null) {
|
|
throw new Error('config.storage must be a non-null object');
|
|
}
|
|
const storageType = (storage as Record<string, unknown>)['type'];
|
|
if (typeof storageType !== 'string' || !VALID_STORAGE_TYPES.has(storageType)) {
|
|
throw new Error(`Invalid storage.type "${String(storageType)}"`);
|
|
}
|
|
|
|
// queue
|
|
const queue = obj['queue'];
|
|
if (typeof queue !== 'object' || queue === null) {
|
|
throw new Error('config.queue must be a non-null object');
|
|
}
|
|
const queueType = (queue as Record<string, unknown>)['type'];
|
|
if (typeof queueType !== 'string' || !VALID_QUEUE_TYPES.has(queueType)) {
|
|
throw new Error(`Invalid queue.type "${String(queueType)}"`);
|
|
}
|
|
|
|
// memory
|
|
const memory = obj['memory'];
|
|
if (typeof memory !== 'object' || memory === null) {
|
|
throw new Error('config.memory must be a non-null object');
|
|
}
|
|
const memoryType = (memory as Record<string, unknown>)['type'];
|
|
if (typeof memoryType !== 'string' || !VALID_MEMORY_TYPES.has(memoryType)) {
|
|
throw new Error(`Invalid memory.type "${String(memoryType)}"`);
|
|
}
|
|
|
|
return {
|
|
tier: tier as StorageTier,
|
|
storage: storage as StorageConfig,
|
|
queue: queue as QueueConfig,
|
|
memory: memory as MemoryConfigRef,
|
|
};
|
|
}
|
|
|
|
/* ------------------------------------------------------------------ */
|
|
/* Loader */
|
|
/* ------------------------------------------------------------------ */
|
|
|
|
function detectFromEnv(): MosaicConfig {
|
|
if (process.env['DATABASE_URL']) {
|
|
return {
|
|
...DEFAULT_TEAM_CONFIG,
|
|
storage: {
|
|
type: 'postgres',
|
|
url: process.env['DATABASE_URL'],
|
|
},
|
|
queue: {
|
|
type: 'bullmq',
|
|
url: process.env['VALKEY_URL'],
|
|
},
|
|
};
|
|
}
|
|
return DEFAULT_LOCAL_CONFIG;
|
|
}
|
|
|
|
export function loadConfig(configPath?: string): MosaicConfig {
|
|
// 1. Explicit path or default location
|
|
const paths = configPath
|
|
? [resolve(configPath)]
|
|
: [
|
|
resolve(process.cwd(), 'mosaic.config.json'),
|
|
resolve(process.cwd(), '../../mosaic.config.json'), // monorepo root when cwd is apps/gateway
|
|
];
|
|
|
|
for (const p of paths) {
|
|
if (existsSync(p)) {
|
|
const raw: unknown = JSON.parse(readFileSync(p, 'utf-8'));
|
|
return validateConfig(raw);
|
|
}
|
|
}
|
|
|
|
// 2. Fall back to env-var detection
|
|
return detectFromEnv();
|
|
}
|