fix(storage): unify workspace root resolution for docstore and migrations
Adopt a consistent findWorkspaceRoot helper across bootstrap, storage, and database modules to reliably locate the monorepo root. Update environment file loading and docstore path construction to use the workspace root, ensuring correct file resolution in multi-package setups. This addresses issues with relative paths and improves compatibility in monorepo and containerized environments.
This commit is contained in:
parent
74a96c0d15
commit
ee979205b3
4 changed files with 85 additions and 15 deletions
|
|
@ -21,10 +21,26 @@ import {
|
|||
} from './embedded-seaweedfs.mjs';
|
||||
import { resolveEmbeddedWorkerLaunch } from './embedded-worker.mjs';
|
||||
|
||||
function findWorkspaceRoot(startDir = process.cwd()) {
|
||||
let dir = startDir;
|
||||
while (true) {
|
||||
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
||||
return dir;
|
||||
}
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) {
|
||||
break;
|
||||
}
|
||||
dir = parent;
|
||||
}
|
||||
return startDir;
|
||||
}
|
||||
|
||||
const workspaceRoot = findWorkspaceRoot(process.cwd());
|
||||
|
||||
function loadEnvFiles() {
|
||||
const cwd = process.cwd();
|
||||
const envPath = path.join(cwd, '.env');
|
||||
const envLocalPath = path.join(cwd, '.env.local');
|
||||
const envPath = path.join(workspaceRoot, '.env');
|
||||
const envLocalPath = path.join(workspaceRoot, '.env.local');
|
||||
|
||||
if (fs.existsSync(envPath)) {
|
||||
dotenv.config({ path: envPath });
|
||||
|
|
@ -111,7 +127,7 @@ function spawnMainCommand(command, env) {
|
|||
|
||||
async function runDbMigrations(env) {
|
||||
console.log('Running database migrations...');
|
||||
await runMigrations({ cwd: process.cwd(), env });
|
||||
await runMigrations({ cwd: workspaceRoot, env });
|
||||
}
|
||||
|
||||
function runStorageMigrations(env) {
|
||||
|
|
@ -278,7 +294,7 @@ async function main() {
|
|||
}
|
||||
|
||||
if (useEmbeddedWeed) {
|
||||
runtimeEnv.WEED_MINI_DIR = withDefault(runtimeEnv.WEED_MINI_DIR, 'docstore/seaweedfs');
|
||||
runtimeEnv.WEED_MINI_DIR = withDefault(runtimeEnv.WEED_MINI_DIR, path.join(workspaceRoot, 'docstore/seaweedfs'));
|
||||
runtimeEnv.WEED_MINI_WAIT_SEC = withDefault(runtimeEnv.WEED_MINI_WAIT_SEC, '20');
|
||||
runtimeEnv.S3_BUCKET = withDefault(runtimeEnv.S3_BUCKET, 'openreader-documents');
|
||||
runtimeEnv.S3_REGION = withDefault(runtimeEnv.S3_REGION, 'us-east-1');
|
||||
|
|
@ -371,7 +387,7 @@ async function main() {
|
|||
runtimeEnv.COMPUTE_WORKER_HOST = withDefault(runtimeEnv.COMPUTE_WORKER_HOST, '127.0.0.1');
|
||||
runtimeEnv.COMPUTE_NATS_REPLICAS = withDefault(runtimeEnv.COMPUTE_NATS_REPLICAS, '1');
|
||||
|
||||
const natsStoreDir = withDefault(runtimeEnv.EMBEDDED_NATS_STORE_DIR, 'docstore/nats/jetstream');
|
||||
const natsStoreDir = withDefault(runtimeEnv.EMBEDDED_NATS_STORE_DIR, path.join(workspaceRoot, 'docstore/nats/jetstream'));
|
||||
fs.mkdirSync(natsStoreDir, { recursive: true });
|
||||
|
||||
console.log(`Starting embedded nats-server on 127.0.0.1:${embeddedNatsPort}...`);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,23 @@ const { Pool } = require('pg');
|
|||
const BetterSqlite3 = require('better-sqlite3');
|
||||
const ffmpegStatic = require('ffmpeg-static');
|
||||
|
||||
const DOCSTORE_DIR = path.join(process.cwd(), 'docstore');
|
||||
function findWorkspaceRoot(startDir = process.cwd()) {
|
||||
let dir = startDir;
|
||||
while (true) {
|
||||
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
||||
return dir;
|
||||
}
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) {
|
||||
break;
|
||||
}
|
||||
dir = parent;
|
||||
}
|
||||
return startDir;
|
||||
}
|
||||
|
||||
const workspaceRoot = findWorkspaceRoot(process.cwd());
|
||||
const DOCSTORE_DIR = path.join(workspaceRoot, 'docstore');
|
||||
const DOCUMENTS_V1_DIR = path.join(DOCSTORE_DIR, 'documents_v1');
|
||||
const AUDIOBOOKS_V1_DIR = path.join(DOCSTORE_DIR, 'audiobooks_v1');
|
||||
const UNCLAIMED_USER_ID = 'unclaimed';
|
||||
|
|
@ -27,10 +43,15 @@ const SAFE_AUDIOBOOK_ID_REGEX = /^[a-zA-Z0-9._-]{1,128}$/;
|
|||
const DOCUMENT_ID_REGEX = /^[a-f0-9]{64}$/i;
|
||||
|
||||
function loadEnvFiles() {
|
||||
const envPath = path.join(process.cwd(), '.env');
|
||||
const envLocalPath = path.join(process.cwd(), '.env.local');
|
||||
if (fs.existsSync(envPath)) dotenv.config({ path: envPath });
|
||||
if (fs.existsSync(envLocalPath)) dotenv.config({ path: envLocalPath, override: true });
|
||||
const envPath = path.join(workspaceRoot, '.env');
|
||||
const envLocalPath = path.join(workspaceRoot, '.env.local');
|
||||
|
||||
if (fs.existsSync(envPath)) {
|
||||
dotenv.config({ path: envPath });
|
||||
}
|
||||
if (fs.existsSync(envLocalPath)) {
|
||||
dotenv.config({ path: envLocalPath, override: true });
|
||||
}
|
||||
}
|
||||
|
||||
function parseBool(value, fallback = false) {
|
||||
|
|
@ -688,7 +709,7 @@ function openDatabase() {
|
|||
};
|
||||
}
|
||||
|
||||
const dbPath = path.join(process.cwd(), 'docstore', 'sqlite3.db');
|
||||
const dbPath = path.join(DOCSTORE_DIR, 'sqlite3.db');
|
||||
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
||||
const sqlite = new BetterSqlite3(dbPath);
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -59,6 +59,21 @@ export function ensureSystemUserExists(userId: string) {
|
|||
}
|
||||
}
|
||||
|
||||
function findWorkspaceRoot(startDir: string = process.cwd()): string {
|
||||
let dir = startDir;
|
||||
while (true) {
|
||||
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
||||
return dir;
|
||||
}
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) {
|
||||
break;
|
||||
}
|
||||
dir = parent;
|
||||
}
|
||||
return startDir;
|
||||
}
|
||||
|
||||
function getDrizzleDB() {
|
||||
if (dbInstance) return dbInstance;
|
||||
|
||||
|
|
@ -79,7 +94,8 @@ function getDrizzleDB() {
|
|||
const { drizzle: drizzleSqlite } = require('drizzle-orm/better-sqlite3');
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const Database = require('better-sqlite3');
|
||||
const dbPath = path.join(process.cwd(), 'docstore', 'sqlite3.db');
|
||||
const workspaceRoot = findWorkspaceRoot(process.cwd());
|
||||
const dbPath = path.join(workspaceRoot, 'docstore', 'sqlite3.db');
|
||||
const dir = path.dirname(dbPath);
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
|
|
|
|||
|
|
@ -13,8 +13,24 @@ function loadEnvFiles(cwd) {
|
|||
if (fs.existsSync(envLocalPath)) dotenv.config({ path: envLocalPath, override: true });
|
||||
}
|
||||
|
||||
function findWorkspaceRoot(startDir = process.cwd()) {
|
||||
let dir = startDir;
|
||||
while (true) {
|
||||
if (fs.existsSync(path.join(dir, 'pnpm-workspace.yaml'))) {
|
||||
return dir;
|
||||
}
|
||||
const parent = path.dirname(dir);
|
||||
if (parent === dir) {
|
||||
break;
|
||||
}
|
||||
dir = parent;
|
||||
}
|
||||
return startDir;
|
||||
}
|
||||
|
||||
export async function runMigrations({ cwd = process.cwd(), env = process.env } = {}) {
|
||||
loadEnvFiles(cwd);
|
||||
const workspaceRoot = findWorkspaceRoot(cwd);
|
||||
loadEnvFiles(workspaceRoot);
|
||||
|
||||
if (env.POSTGRES_URL?.trim()) {
|
||||
const [{ drizzle }, { migrate }, { Pool }] = await Promise.all([
|
||||
|
|
@ -33,7 +49,7 @@ export async function runMigrations({ cwd = process.cwd(), env = process.env } =
|
|||
return;
|
||||
}
|
||||
|
||||
const dbPath = path.join(cwd, 'docstore', 'sqlite3.db');
|
||||
const dbPath = path.join(workspaceRoot, 'docstore', 'sqlite3.db');
|
||||
fs.mkdirSync(path.dirname(dbPath), { recursive: true });
|
||||
const [{ drizzle }, { migrate }, { default: BetterSqlite3 }] = await Promise.all([
|
||||
import('drizzle-orm/better-sqlite3'),
|
||||
|
|
@ -49,3 +65,4 @@ export async function runMigrations({ cwd = process.cwd(), env = process.env } =
|
|||
sqlite.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue