mirror of
https://github.com/docmost/docmost.git
synced 2026-08-27 08:47:06 +08:00
* feat(ai): add AI_VECTOR_DRIVER and turbopuffer configuration * feat(ai): carry workspace and target space ids on vector lifecycle events * feat(ai): add vector driver interface and turbopuffer request helpers * feat(ai): add pgvector driver behind the vector driver interface * refactor(ai): route vector reads and writes through the vector driver * feat(ai): add turbopuffer vector driver * feat(ai): rebuild turbopuffer namespaces when the embedding model changes * feat(ai): warm the vector namespace cache on session start * fix(ai): harden turbopuffer misconfiguration and reset failure paths * fix(ai): collapse blank-line runs in extracted page text * fix(ai): skip full re-embed when ai search is re-enabled within the delete grace window * sync * fix(ai): store real embedding dimensions instead of serialized vector length * fix(ai): filter search hits by the page's current space at query time * fix(ai): retry the page moved-to-space vector patch job * sync * feat(ai): pre-warm the vector namespace * fix(ai): pass AI_VECTOR_DRIVER through the client build config
86 lines
2.8 KiB
TypeScript
86 lines
2.8 KiB
TypeScript
import { Module, OnModuleInit } from '@nestjs/common';
|
|
import { HttpAdapterHost } from '@nestjs/core';
|
|
import { join } from 'path';
|
|
import * as fs from 'node:fs';
|
|
import fastifyStatic from '@fastify/static';
|
|
import { EnvironmentService } from '../environment/environment.service';
|
|
|
|
@Module({})
|
|
export class StaticModule implements OnModuleInit {
|
|
constructor(
|
|
private readonly httpAdapterHost: HttpAdapterHost,
|
|
private readonly environmentService: EnvironmentService,
|
|
) {}
|
|
|
|
public async onModuleInit() {
|
|
const httpAdapter = this.httpAdapterHost.httpAdapter;
|
|
const app = httpAdapter.getInstance();
|
|
|
|
const clientDistPath = join(
|
|
__dirname,
|
|
'..',
|
|
'..',
|
|
'..',
|
|
'..',
|
|
'client/dist',
|
|
);
|
|
|
|
const indexFilePath = join(clientDistPath, 'index.html');
|
|
|
|
if (fs.existsSync(clientDistPath) && fs.existsSync(indexFilePath)) {
|
|
const indexTemplateFilePath = join(clientDistPath, 'index-template.html');
|
|
const windowVar = '<!--window-config-->';
|
|
|
|
const configString = {
|
|
ENV: this.environmentService.getNodeEnv(),
|
|
APP_URL: this.environmentService.getAppUrl(),
|
|
CLOUD: this.environmentService.isCloud(),
|
|
FILE_UPLOAD_SIZE_LIMIT:
|
|
this.environmentService.getFileUploadSizeLimit(),
|
|
FILE_IMPORT_SIZE_LIMIT:
|
|
this.environmentService.getFileImportSizeLimit(),
|
|
DRAWIO_URL: this.environmentService.getDrawioUrl(),
|
|
SUBDOMAIN_HOST: this.environmentService.isCloud()
|
|
? this.environmentService.getSubdomainHost()
|
|
: undefined,
|
|
COLLAB_URL: this.environmentService.getCollabUrl(),
|
|
BILLING_TRIAL_DAYS: this.environmentService.isCloud()
|
|
? this.environmentService.getBillingTrialDays()
|
|
: undefined,
|
|
POSTHOG_HOST: this.environmentService.getPostHogHost(),
|
|
POSTHOG_KEY: this.environmentService.getPostHogKey(),
|
|
AI_VECTOR_DRIVER:
|
|
this.environmentService.getAiVectorDriver() === 'turbopuffer'
|
|
? 'turbopuffer'
|
|
: undefined,
|
|
};
|
|
|
|
const windowScriptContent = `<script>window.CONFIG=${JSON.stringify(configString)};</script>`;
|
|
|
|
if (!fs.existsSync(indexTemplateFilePath)) {
|
|
fs.copyFileSync(indexFilePath, indexTemplateFilePath);
|
|
}
|
|
|
|
const html = fs.readFileSync(indexTemplateFilePath, 'utf8');
|
|
const transformedHtml = html.replace(windowVar, windowScriptContent);
|
|
|
|
fs.writeFileSync(indexFilePath, transformedHtml);
|
|
|
|
const RENDER_PATH = '*';
|
|
|
|
await app.register(fastifyStatic, {
|
|
root: clientDistPath,
|
|
wildcard: false,
|
|
});
|
|
|
|
app.get(RENDER_PATH, (req: any, res: any) => {
|
|
const stream = fs.createReadStream(indexFilePath);
|
|
res
|
|
.header('Cache-Control', 'no-cache, no-store, must-revalidate')
|
|
.type('text/html')
|
|
.send(stream);
|
|
});
|
|
}
|
|
}
|
|
}
|