Files
DarkSky 027d163921 fix(server): add embedding table repair (#14895)
fix #14894


#### PR Dependency Tree


* **PR #14895** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Improved database initialization for self-hosted deployments with
automatic creation and repair of embedding tables and indexes, applied
only when related base tables and extensions are present.
* Updated pre-deploy process to run Prisma migrations, perform
embedding-table maintenance, and execute additional data migrations as
part of setup.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
2026-05-04 03:45:37 +08:00

114 lines
2.9 KiB
JavaScript

import { execSync } from 'node:child_process';
import { generateKeyPairSync } from 'node:crypto';
import fs from 'node:fs';
import { homedir } from 'node:os';
import path from 'node:path';
const SELF_HOST_CONFIG_DIR = `${homedir()}/.affine/config`;
function generatePrivateKey() {
const key = generateKeyPairSync('ec', {
namedCurve: 'prime256v1',
}).privateKey.export({
type: 'sec1',
format: 'pem',
});
if (key instanceof Buffer) {
return key.toString('utf-8');
}
return key;
}
/**
* @type {Array<{ to: string; generator: () => string }>}
*/
const files = [{ to: 'private.key', generator: generatePrivateKey }];
function prepare() {
fs.mkdirSync(SELF_HOST_CONFIG_DIR, { recursive: true });
for (const { to, generator } of files) {
const targetFilePath = path.join(SELF_HOST_CONFIG_DIR, to);
if (!fs.existsSync(targetFilePath)) {
console.log(`creating config file [${targetFilePath}].`);
fs.writeFileSync(targetFilePath, generator(), 'utf-8');
}
}
}
function runPrismaMigrations() {
console.log('running prisma migrations.');
execSync('yarn prisma migrate deploy', {
encoding: 'utf-8',
env: process.env,
stdio: 'inherit',
});
}
function repairPgvectorEmbeddingTables() {
console.log('repairing copilot pgvector embedding tables.');
const sql = fs.readFileSync(
path.join(import.meta.dirname, 'repair-pgvector-embedding-tables.sql'),
'utf-8'
);
execSync('yarn prisma db execute --stdin --schema schema.prisma', {
encoding: 'utf-8',
env: process.env,
input: sql,
stdio: ['pipe', 'inherit', 'inherit'],
});
}
function runDataMigrations() {
console.log('running data migrations.');
execSync('yarn cli run', {
encoding: 'utf-8',
env: process.env,
stdio: 'inherit',
});
}
function fixFailedMigrations() {
console.log('fixing failed migrations.');
const maybeFailedMigrations = [
'20250521083048_fix_workspace_embedding_chunk_primary_key',
];
for (const migration of maybeFailedMigrations) {
try {
execSync(`yarn prisma migrate resolve --rolled-back ${migration}`, {
encoding: 'utf-8',
env: process.env,
stdio: 'pipe',
});
console.log(`migration [${migration}] has been rolled back.`);
} catch (err) {
if (
err.message.includes(
'cannot be rolled back because it is not in a failed state'
) ||
err.message.includes(
'cannot be rolled back because it was never applied'
) ||
err.message.includes(
'called markMigrationRolledBack on a database without migrations table'
)
) {
// migration has been rolled back, skip it
continue;
}
// ignore other errors
console.log(
`migration [${migration}] rolled back failed. ${err.message}`
);
}
}
}
prepare();
fixFailedMigrations();
runPrismaMigrations();
repairPgvectorEmbeddingTables();
runDataMigrations();