import { Controller, Get, Param, Req, Res } from '@nestjs/common'; import { ShareService } from './share.service'; import { FastifyReply, FastifyRequest } from 'fastify'; import { join } from 'path'; import * as fs from 'node:fs'; import { validate as isValidUUID } from 'uuid'; import { WorkspaceRepo } from '@docmost/db/repos/workspace/workspace.repo'; import { EnvironmentService } from '../../integrations/environment/environment.service'; import { Workspace } from '@docmost/db/types/entity.types'; @Controller('share') export class ShareSeoController { constructor( private readonly shareService: ShareService, private workspaceRepo: WorkspaceRepo, private environmentService: EnvironmentService, ) {} /* * add meta tags to publicly shared pages */ @Get([':shareId/:pageSlug', 'p/:pageSlug']) async getShare( @Res({ passthrough: false }) res: FastifyReply, @Req() req: FastifyRequest, @Param('shareId') shareId: string, @Param('pageSlug') pageSlug: string, ) { // Nestjs does not to apply middlewares to paths excluded from the global /api prefix // https://github.com/nestjs/nest/issues/9124 // https://github.com/nestjs/nest/issues/11572 // https://github.com/nestjs/nest/issues/13401 // we have to duplicate the DomainMiddleware code here as a workaround let workspace: Workspace = null; if (this.environmentService.isSelfHosted()) { workspace = await this.workspaceRepo.findFirst(); } else { const header = req.raw.headers.host; const subdomain = header.split('.')[0]; workspace = await this.workspaceRepo.findByHostname(subdomain); } const clientDistPath = join( __dirname, '..', '..', '..', '..', 'client/dist', ); if (fs.existsSync(clientDistPath)) { const indexFilePath = join(clientDistPath, 'index.html'); if (!workspace) { return this.sendIndex(indexFilePath, res); } const pageId = this.extractPageSlugId(pageSlug); const share = await this.shareService.getShareForPage( pageId, workspace.id, ); if (!share) { return this.sendIndex(indexFilePath, res); } const rawTitle = share.sharedPage.title ?? 'untitled'; const metaTitle = rawTitle.length > 80 ? `${rawTitle.slice(0, 77)}…` : rawTitle; const metaTagVar = ''; const metaTags = [ ``, ``, !share.searchIndexing ? `` : '', ] .filter(Boolean) .join('\n '); const html = fs.readFileSync(indexFilePath, 'utf8'); const transformedHtml = html .replace(/