Compare commits

..

6 Commits

Author SHA1 Message Date
Philip Okugbe bfa002898f Cleanup
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-11 19:12:36 +00:00
Philipinho 7ec650138c fix: add new indexes for better performance 2026-01-11 18:08:34 +00:00
Philipinho 732951a322 v0.24.1 2025-12-14 13:24:09 +00:00
Philipinho 2544775266 fix: switch to node slim image 2025-12-14 13:16:40 +00:00
Philipinho d59539f197 fix ai streaming 2025-12-13 14:15:41 +00:00
Philipinho b061df7f7d Use new fastify router options 2025-12-13 14:15:06 +00:00
10 changed files with 217 additions and 14 deletions
+4 -2
View File
@@ -1,4 +1,4 @@
FROM node:22-alpine AS base
FROM node:22-slim AS base
LABEL org.opencontainers.image.source="https://github.com/docmost/docmost"
FROM base AS builder
@@ -13,7 +13,9 @@ RUN pnpm build
FROM base AS installer
RUN apk add --no-cache curl bash
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl bash \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "client",
"private": true,
"version": "0.24.0",
"version": "0.24.1",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
@@ -37,14 +37,18 @@ export async function askAi(
let answer = "";
let sources: any[] = [];
let buffer = "";
if (reader) {
while (true) {
const { done, value } = await reader.read();
if (done) break;
const chunk = decoder.decode(value);
const lines = chunk.split("\n");
buffer += decoder.decode(value, { stream: true });
const lines = buffer.split("\n");
// Keep the last incomplete line in the buffer
buffer = lines.pop() || "";
for (const line of lines) {
if (line.startsWith("data: ")) {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "server",
"version": "0.24.0",
"version": "0.24.1",
"description": "",
"author": "",
"private": true,
@@ -0,0 +1,196 @@
import { type Kysely, sql } from 'kysely';
export async function up(db: Kysely<any>): Promise<void> {
await db.schema
.createIndex('idx_group_users_user_id')
.ifNotExists()
.on('group_users')
.column('user_id')
.execute();
await db.schema
.createIndex('idx_space_members_user_id')
.ifNotExists()
.on('space_members')
.column('user_id')
.execute();
await db.schema
.createIndex('idx_space_members_group_id')
.ifNotExists()
.on('space_members')
.column('group_id')
.execute();
// Page tree
await sql`
CREATE INDEX IF NOT EXISTS idx_pages_space_parent_position
ON pages (space_id, parent_page_id, position COLLATE "C")
WHERE deleted_at IS NULL
`.execute(db);
await sql`
CREATE INDEX IF NOT EXISTS idx_pages_parent_page_id
ON pages (parent_page_id)
WHERE deleted_at IS NULL
`.execute(db);
// Recent pages query
await sql`
CREATE INDEX IF NOT EXISTS idx_pages_space_updated
ON pages (space_id, updated_at DESC)
WHERE deleted_at IS NULL
`.execute(db);
// Trash view
await sql`
CREATE INDEX IF NOT EXISTS idx_pages_space_deleted
ON pages (space_id, deleted_at DESC)
WHERE deleted_at IS NOT NULL
`.execute(db);
await sql`
CREATE UNIQUE INDEX IF NOT EXISTS idx_workspaces_hostname_lower
ON workspaces (LOWER(hostname))
`.execute(db);
await db.schema
.createIndex('idx_workspaces_created_at')
.ifNotExists()
.on('workspaces')
.column('created_at')
.execute();
await db.schema
.createIndex('idx_users_workspace_deleted_created')
.ifNotExists()
.on('users')
.columns(['workspace_id', 'deleted_at', 'created_at'])
.execute();
await sql`
CREATE INDEX IF NOT EXISTS idx_users_workspace_email_lower
ON users (workspace_id, LOWER(email))
`.execute(db);
await sql`
CREATE UNIQUE INDEX IF NOT EXISTS idx_spaces_workspace_slug_lower
ON spaces (workspace_id, LOWER(slug))
`.execute(db);
await db.schema
.createIndex('idx_spaces_workspace_created')
.ifNotExists()
.on('spaces')
.columns(['workspace_id', 'created_at'])
.execute();
await sql`
CREATE UNIQUE INDEX IF NOT EXISTS idx_groups_workspace_name_lower
ON groups (workspace_id, LOWER(name))
`.execute(db);
await db.schema
.createIndex('idx_groups_workspace_id')
.ifNotExists()
.on('groups')
.column('workspace_id')
.execute();
await db.schema
.createIndex('idx_shares_page_id')
.ifNotExists()
.on('shares')
.column('page_id')
.execute();
await sql`
CREATE UNIQUE INDEX IF NOT EXISTS idx_shares_key_lower
ON shares (LOWER(key))
`.execute(db);
await db.schema
.createIndex('idx_attachments_page_id')
.ifNotExists()
.on('attachments')
.column('page_id')
.execute();
await db.schema
.createIndex('idx_attachments_space_id')
.ifNotExists()
.on('attachments')
.column('space_id')
.execute();
await db.schema
.createIndex('idx_comments_page_id')
.ifNotExists()
.on('comments')
.columns(['page_id', 'created_at'])
.execute();
await db.schema
.createIndex('idx_comments_parent_comment_id')
.ifNotExists()
.on('comments')
.column('parent_comment_id')
.execute();
await sql`
CREATE INDEX IF NOT EXISTS idx_page_history_page_created
ON page_history (page_id, created_at DESC)
`.execute(db);
}
export async function down(db: Kysely<any>): Promise<void> {
await db.schema.dropIndex('idx_group_users_user_id').ifExists().execute();
await db.schema.dropIndex('idx_space_members_user_id').ifExists().execute();
await db.schema.dropIndex('idx_space_members_group_id').ifExists().execute();
await db.schema
.dropIndex('idx_pages_space_parent_position')
.ifExists()
.execute();
await db.schema.dropIndex('idx_pages_parent_page_id').ifExists().execute();
await db.schema.dropIndex('idx_pages_space_updated').ifExists().execute();
await db.schema.dropIndex('idx_pages_space_deleted').ifExists().execute();
await db.schema
.dropIndex('idx_workspaces_hostname_lower')
.ifExists()
.execute();
await db.schema.dropIndex('idx_workspaces_created_at').ifExists().execute();
await db.schema
.dropIndex('idx_users_workspace_deleted_created')
.ifExists()
.execute();
await db.schema
.dropIndex('idx_users_workspace_email_lower')
.ifExists()
.execute();
await db.schema
.dropIndex('idx_spaces_workspace_slug_lower')
.ifExists()
.execute();
await db.schema
.dropIndex('idx_spaces_workspace_created')
.ifExists()
.execute();
await db.schema
.dropIndex('idx_groups_workspace_name_lower')
.ifExists()
.execute();
await db.schema.dropIndex('idx_groups_workspace_id').ifExists().execute();
await db.schema.dropIndex('idx_shares_page_id').ifExists().execute();
await db.schema.dropIndex('idx_shares_key_lower').ifExists().execute();
await db.schema.dropIndex('idx_attachments_page_id').ifExists().execute();
await db.schema.dropIndex('idx_attachments_space_id').ifExists().execute();
await db.schema.dropIndex('idx_comments_page_id').ifExists().execute();
await db.schema
.dropIndex('idx_comments_parent_comment_id')
.ifExists()
.execute();
await db.schema
.dropIndex('idx_page_history_page_created')
.ifExists()
.execute();
}
@@ -117,7 +117,7 @@ export class EnvironmentVariables {
@IsOptional()
@ValidateIf((obj) => obj.AI_EMBEDDING_DIMENSION)
@IsIn(['768', '1024', '1536'])
@IsIn(['768', '1024', '1536', '2000'])
@IsString()
AI_EMBEDDING_DIMENSION: string;
+5 -3
View File
@@ -15,10 +15,12 @@ async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({
ignoreTrailingSlash: true,
ignoreDuplicateSlashes: true,
maxParamLength: 1000,
trustProxy: true,
routerOptions: {
maxParamLength: 1000,
ignoreTrailingSlash: true,
ignoreDuplicateSlashes: true,
},
}),
{
rawBody: true,
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "docmost",
"homepage": "https://docmost.com",
"version": "0.24.0",
"version": "0.24.1",
"private": true,
"scripts": {
"build": "nx run-many -t build",
+1 -2
View File
@@ -3,7 +3,6 @@ import { Editor, findParentNode, isTextSelection } from "@tiptap/core";
import { Selection, Transaction } from "@tiptap/pm/state";
import { CellSelection, TableMap } from "@tiptap/pm/tables";
import { Node, ResolvedPos } from "@tiptap/pm/model";
import Table from "@tiptap/extension-table";
import { sanitizeUrl as braintreeSanitizeUrl } from "@braintree/sanitize-url";
import { customAlphabet } from "nanoid";
@@ -289,7 +288,7 @@ export const isColumnGripSelected = ({
const node = nodeDOM || domAtPos;
if (
!editor.isActive(Table.name) ||
!editor.isActive("table") ||
!node ||
isTableSelected(state.selection)
) {